MON Price: $0.018956 (+3.48%)

Contract

0x32faD39e79FAc67f80d1C86CbD1598043e52CDb6

Overview

MON Balance

Monad Chain LogoMonad Chain LogoMonad Chain Logo0 MON

MON Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Add C Token Supp...485771052026-01-14 3:47:0710 days ago1768362427IN
0x32faD39e...43e52CDb6
0 MON0.01082077102
Add C Token Supp...485770812026-01-14 3:46:5710 days ago1768362417IN
0x32faD39e...43e52CDb6
0 MON0.01082077102
Add Asset Pricin...485770052026-01-14 3:46:2710 days ago1768362387IN
0x32faD39e...43e52CDb6
0 MON0.04838461102
Add Asset Pricin...408500252025-12-09 6:12:5246 days ago1765260772IN
0x32faD39e...43e52CDb6
0 MON0.04539989102
Add C Token Supp...386963392025-11-29 5:11:0756 days ago1764393067IN
0x32faD39e...43e52CDb6
0 MON0.0108475102.2519562
Add C Token Supp...386963122025-11-29 5:10:5756 days ago1764393057IN
0x32faD39e...43e52CDb6
0 MON0.0108475102.2519562
Add Asset Pricin...379369982025-11-25 16:29:2560 days ago1764088165IN
0x32faD39e...43e52CDb6
0 MON0.06095496121
Remove Asset Pri...379369692025-11-25 16:29:1460 days ago1764088154IN
0x32faD39e...43e52CDb6
0 MON0.0089674104.035
Add Asset Pricin...379361982025-11-25 16:24:0560 days ago1764087845IN
0x32faD39e...43e52CDb6
0 MON0.05425969107.79394438
Remove Asset Pri...379361672025-11-25 16:23:5260 days ago1764087832IN
0x32faD39e...43e52CDb6
0 MON0.01098795127.5
Remove Asset Pri...379361622025-11-25 16:23:5060 days ago1764087830IN
0x32faD39e...43e52CDb6
0 MON0.01243023127.5
Add C Token Supp...378341232025-11-25 4:58:5560 days ago1764046735IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378340992025-11-25 4:58:4660 days ago1764046726IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378340222025-11-25 4:58:1560 days ago1764046695IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378339932025-11-25 4:58:0360 days ago1764046683IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378339032025-11-25 4:57:2760 days ago1764046647IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378338732025-11-25 4:57:1560 days ago1764046635IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378337872025-11-25 4:56:4160 days ago1764046601IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378337602025-11-25 4:56:3060 days ago1764046590IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378336782025-11-25 4:55:5760 days ago1764046557IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378336542025-11-25 4:55:4860 days ago1764046548IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378335822025-11-25 4:55:1960 days ago1764046519IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378335592025-11-25 4:55:1060 days ago1764046510IN
0x32faD39e...43e52CDb6
0 MON0.01379118130
Add C Token Supp...378333982025-11-25 4:54:0560 days ago1764046445IN
0x32faD39e...43e52CDb6
0 MON0.01100536103.74
Add C Token Supp...378333732025-11-25 4:53:5560 days ago1764046435IN
0x32faD39e...43e52CDb6
0 MON0.01100536103.74
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
508962192026-01-24 22:39:254 mins ago1769294365
0x32faD39e...43e52CDb6
0 MON
508962192026-01-24 22:39:254 mins ago1769294365
0x32faD39e...43e52CDb6
0 MON
508962192026-01-24 22:39:254 mins ago1769294365
0x32faD39e...43e52CDb6
0 MON
508962192026-01-24 22:39:254 mins ago1769294365
0x32faD39e...43e52CDb6
0 MON
508962192026-01-24 22:39:254 mins ago1769294365
0x32faD39e...43e52CDb6
0 MON
508962192026-01-24 22:39:254 mins ago1769294365
0x32faD39e...43e52CDb6
0 MON
508893762026-01-24 21:53:4949 mins ago1769291629
0x32faD39e...43e52CDb6
0 MON
508893762026-01-24 21:53:4949 mins ago1769291629
0x32faD39e...43e52CDb6
0 MON
508893762026-01-24 21:53:4949 mins ago1769291629
0x32faD39e...43e52CDb6
0 MON
508893762026-01-24 21:53:4949 mins ago1769291629
0x32faD39e...43e52CDb6
0 MON
508893762026-01-24 21:53:4949 mins ago1769291629
0x32faD39e...43e52CDb6
0 MON
508880622026-01-24 21:45:0458 mins ago1769291104
0x32faD39e...43e52CDb6
0 MON
508880622026-01-24 21:45:0458 mins ago1769291104
0x32faD39e...43e52CDb6
0 MON
508880622026-01-24 21:45:0458 mins ago1769291104
0x32faD39e...43e52CDb6
0 MON
508878292026-01-24 21:43:311 hr ago1769291011
0x32faD39e...43e52CDb6
0 MON
508878292026-01-24 21:43:311 hr ago1769291011
0x32faD39e...43e52CDb6
0 MON
508878292026-01-24 21:43:311 hr ago1769291011
0x32faD39e...43e52CDb6
0 MON
508878292026-01-24 21:43:311 hr ago1769291011
0x32faD39e...43e52CDb6
0 MON
508878292026-01-24 21:43:311 hr ago1769291011
0x32faD39e...43e52CDb6
0 MON
508860582026-01-24 21:31:411 hr ago1769290301
0x32faD39e...43e52CDb6
0 MON
508860582026-01-24 21:31:411 hr ago1769290301
0x32faD39e...43e52CDb6
0 MON
508860582026-01-24 21:31:411 hr ago1769290301
0x32faD39e...43e52CDb6
0 MON
508860582026-01-24 21:31:411 hr ago1769290301
0x32faD39e...43e52CDb6
0 MON
508860582026-01-24 21:31:411 hr ago1769290301
0x32faD39e...43e52CDb6
0 MON
508860582026-01-24 21:31:411 hr ago1769290301
0x32faD39e...43e52CDb6
0 MON
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
OracleManager

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, BSL 1.1 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at monadscan.com on 2025-11-25
*/

// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.28;

// contracts/libraries/ConstantsLib.sol

/// @dev Scalar for math. `WAD` * `WAD`.
uint256 constant WAD_SQUARED = 1e36;

/// @dev Scalar for math. `WAD` * `WAD` / `BPS`.
///      1e18 * 1e18 / 1e4
uint256 constant WAD_SQUARED_BPS_OFFSET = 1e32;

/// @dev Scalar for math. Increased precision when WAD is insufficient
///      but WAD_SQUARED runs the risk of overflow.
uint256 constant RAY = 1e27;

/// @dev Scalar for math. `WAD` * `BPS`.
uint256 constant WAD_BPS = 1e22;

/// @dev Scalar for math. Base precision matching ether.
uint256 constant WAD = 1e18;

/// @dev Scalar for math. Represents basis points typically used in TradFi.
uint256 constant BPS = 1e4;

/// @dev Return value indicating no price returned at all.
uint256 constant BAD_SOURCE = 2;

/// @dev Return value indicating price divergence or a missing price feed.
uint256 constant CAUTION = 1;

/// @dev Return value indicating no price error.
uint256 constant NO_ERROR = 0;

/// @dev Extra time added to top end Oracle feed heartbeat incase of
///      transaction congestion delaying an update.
uint256 constant HEARTBEAT_GRACE_PERIOD = 120;

/// @dev Unix time has 31,536,000 seconds per year.
///      All my homies hate leap seconds and leap years.
uint256 constant SECONDS_PER_YEAR = 31_536_000;

// contracts/libraries/external/FixedPointMathLib.sol

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @dev Reduced function scope from full FixedPointMathLib library to only what is needed for Curvance.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
    error MulDivFailed();

    /// @dev The full precision multiply-divide operation failed, either due
    /// to the result being larger than 256 bits, or a division by a zero.
    error FullMulDivFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  GENERAL NUMBER UTILITIES                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Calculates `floor(x * y / d)` with full precision.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
    function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                // 512-bit multiply `[p1 p0] = x * y`.
                // Compute the product mod `2**256` and mod `2**256 - 1`
                // then use the Chinese Remainder Theorem to reconstruct
                // the 512 bit result. The result is stored in two 256
                // variables such that `product = p1 * 2**256 + p0`.

                // Least significant 256 bits of the product.
                result := mul(x, y) // Temporarily use `result` as `p0` to save gas.
                let mm := mulmod(x, y, not(0))
                // Most significant 256 bits of the product.
                let p1 := sub(mm, add(result, lt(mm, result)))

                // Handle non-overflow cases, 256 by 256 division.
                if iszero(p1) {
                    if iszero(d) {
                        mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                        revert(0x1c, 0x04)
                    }
                    result := div(result, d)
                    break
                }

                // Make sure the result is less than `2**256`. Also prevents `d == 0`.
                if iszero(gt(d, p1)) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }

                /*------------------- 512 by 256 division --------------------*/

                // Make division exact by subtracting the remainder from `[p1 p0]`.
                // Compute remainder using mulmod.
                let r := mulmod(x, y, d)
                // `t` is the least significant bit of `d`.
                // Always greater or equal to 1.
                let t := and(d, sub(0, d))
                // Divide `d` by `t`, which is a power of two.
                d := div(d, t)
                // Invert `d mod 2**256`
                // Now that `d` is an odd number, it has an inverse
                // modulo `2**256` such that `d * inv = 1 mod 2**256`.
                // Compute the inverse by starting with a seed that is correct
                // correct for four bits. That is, `d * inv = 1 mod 2**4`.
                let inv := xor(2, mul(3, d))
                // Now use Newton-Raphson iteration to improve the precision.
                // Thanks to Hensel's lifting lemma, this also works in modular
                // arithmetic, doubling the correct bits in each step.
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
                inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
                result :=
                    mul(
                        // Divide [p1 p0] by the factors of two.
                        // Shift in bits from `p1` into `p0`. For this we need
                        // to flip `t` such that it is `2**256 / t`.
                        or(
                            mul(sub(p1, gt(r, result)), add(div(sub(0, t), t), 1)),
                            div(sub(result, r), t)
                        ),
                        // inverse mod 2**256
                        mul(inv, sub(2, mul(d, inv)))
                    )
                break
            }
        }
    }

    /// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
    /// Throws if result overflows a uint256 or when `d` is zero.
    /// Credit to Uniswap-v3-core under MIT license:
    /// https://github.com/Uniswap/v3-core/blob/contracts/libraries/FullMath.sol
    function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 result) {
        result = fullMulDiv(x, y, d);
        /// @solidity memory-safe-assembly
        assembly {
            if mulmod(x, y, d) {
                result := add(result, 1)
                if iszero(result) {
                    mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Returns `floor(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := div(mul(x, y), d)
        }
    }

    /// @dev Returns `ceil(x * y / d)`.
    /// Reverts if `x * y` overflows, or `d` is zero.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(d != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(d, iszero(mul(y, gt(x, div(not(0), y)))))) {
                mstore(0x00, 0xad251c27) // `MulDivFailed()`.
                revert(0x1c, 0x04)
            }
            z := add(iszero(iszero(mod(mul(x, y), d))), div(mul(x, y), d))
        }
    }

    /// @dev Returns the square root of `x`.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
            // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            z := sub(z, lt(div(x, z), z))
        }
    }
}

// contracts/interfaces/ICentralRegistry.sol

/// TYPES ///

/// @notice Configuration data for a separately supported blockchain.
/// @param isSupported Whether the chain is supported or not.
/// @param messagingChainId Messaging Chain ID where this address authorized.
/// @param domain Domain for the chain.
/// @param messagingHub Messaging Hub address on the chain.
/// @param votingHub Voting Hub address on the chain.
/// @param cveAddress CVE address on the chain.
/// @param feeTokenAddress Fee token address on the chain.
/// @param crosschainRelayer Crosschain relayer address on the chain.
struct ChainConfig {
    bool isSupported;
    uint16 messagingChainId;
    uint32 domain;
    address messagingHub;
    address votingHub;
    address cveAddress;
    address feeTokenAddress;
    address crosschainRelayer;
}

interface ICentralRegistry {
    /// @notice The length of one protocol epoch, in seconds.
    function EPOCH_DURATION() external view returns (uint256);

    /// @notice Sequencer uptime oracle on this chain (for L2s).
    function SEQUENCER_ORACLE() external view returns (address);

    /// @notice Returns Genesis Epoch Timestamp of Curvance.
    function genesisEpoch() external view returns (uint256);

    /// @notice Returns Protocol DAO address.
    function daoAddress() external view returns (address);

    /// @notice Returns Protocol Emergency Council address.
    function emergencyCouncil() external view returns (address);

    /// @notice Indicates if address has DAO permissions or not.
    function hasDaoPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has elevated DAO permissions or not.
    function hasElevatedPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has lock creation permissions or not.
    function hasLockingPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has auction permissions or not.
    function hasAuctionPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has market permissions or not.
    function hasMarketPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Indicates if address has harvest permissions or not.
    function hasHarvestPermissions(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Returns Reward Manager address.
    function rewardManager() external view returns (address);

    /// @notice Returns Gauge Manager address.
    function gaugeManager() external view returns (address);

    /// @notice Returns CVE address.
    function cve() external view returns (address);

    /// @notice Returns veCVE address.
    function veCVE() external view returns (address);

    /// @notice Returns Voting Hub address.
    function votingHub() external view returns (address);

    /// @notice Returns Messaging Hub address.
    function messagingHub() external view returns (address);

    /// @notice Returns Oracle Manager address.
    function oracleManager() external view returns (address);

    /// @notice Returns Fee Manager address.
    function feeManager() external view returns (address);

    /// @notice Returns Fee Token address.
    function feeToken() external view returns (address);

    /// @notice Returns Crosschain Core contract address.
    function crosschainCore() external view returns (address);

    /// @notice Returns Crosschain Relayer contract address.
    function crosschainRelayer() external view returns (address);

    /// @notice Returns Token Messenger contract address.
    function tokenMessager() external view returns (address);

    /// @notice Returns Messenger Transmitter contract address.
    function messageTransmitter() external view returns (address);

    /// @notice Returns domain value.
    function domain() external view returns (uint32);

    /// @notice Returns protocol gas fee on harvest, in `BPS`.
    function protocolCompoundFee() external view returns (uint256);

    /// @notice Returns protocol yield fee on strategy harvest, in `BPS`.
    function protocolYieldFee() external view returns (uint256);

    /// @notice Returns protocol yield + gas fee on strategy harvest,
    ///         in `BPS`.
    function protocolHarvestFee() external view returns (uint256);

    /// @notice Returns protocol fee on leverage actions, in `BPS`.
    function protocolLeverageFee() external view returns (uint256);

    /// @notice Returns default fee on interest generated from active loans,
    ///         in `BPS`.
    function defaultProtocolInterestFee() external view returns (uint256);

    /// @notice Returns earlyUnlockPenaltyMultiplier value, in `BPS`.
    function earlyUnlockPenaltyMultiplier() external view returns (uint256);

    /// @notice Returns voteBoostMultiplier value, in `BPS`.
    function voteBoostMultiplier() external view returns (uint256);

    /// @notice Returns lockBoostMultiplier value, in `BPS`.
    function lockBoostMultiplier() external view returns (uint256);

    /// @notice Returns swap slippage limit, in `BPS`.
    function slippageLimit() external view returns (uint256);

    /// @notice Returns an array of Chain IDs recorded in the Crosschain
    ///         Protocol's Chain ID format.
    function foreignChainIds() external view returns (uint256[] memory);

    /// @notice Returns an array of Curvance markets on this chain.
    function marketManagers() external view returns (address[] memory);

    /// @notice Increments a caller's approval index.
    /// @dev By incrementing their approval index, a user's delegates will all
    ///      have their delegation authority revoked across all Curvance
    ///      contracts.
    ///      Emits an {ApprovalIndexIncremented} event.
    function incrementApprovalIndex() external;

    /// @notice Returns `user`'s approval index.
    /// @param user The user to check approval index for.
    function userApprovalIndex(address user) external view returns (uint256);

    /// @notice Returns whether a user has delegation disabled.
    /// @param user The user to check delegation status for.
    function checkNewDelegationDisabled(
        address user
    ) external view returns (bool);

    /// @notice Returns whether a particular GETH chainId is supported.
    /// ChainId => messagingHub address, 2 = supported; 1 = unsupported.
    function chainConfig(
        uint256 chainId
    ) external view returns (ChainConfig memory);

    /// @notice Returns the GETH chainId corresponding chainId corresponding
    ///         to Crosschain Messaging Protocol's `chainId`.
    /// @param chainId The Crosschain Messaging Protocol's chainId.
    /// @return The GETH chainId corresponding chainId corresponding to
    ///         Crosschain Messaging Protocol's `chainId`.
    function messagingToGETHChainId(
        uint16 chainId
    ) external view returns (uint256);

    /// @notice Returns the Crosschain Messaging Protocol's ChainId
    ///         corresponding to the GETH `chainId`.
    /// @param chainId The GETH chainId.
    /// @return The Crosschain Messaging Protocol's ChainId
    ///         corresponding to the GETH `chainId`.
    function GETHToMessagingChainId(
        uint256 chainId
    ) external view returns (uint256);

    /// @notice Indicates if an address is a market manager or not.
    function isMarketManager(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Maps an intent target address to the contract that will
    ///         inspect provided external calldata.
    function externalCalldataChecker(
        address addressToCheck
    ) external view returns (address);

    /// @notice Maps a Multicall target address to the contract that will
    ///         inspect provided multicall calldata.
    function multicallChecker(
        address addressToCheck
    ) external view returns (address);

    /// @notice Indicates the amount of token rewards allocated on this chain,
    ///         for an epoch.
    function emissionsAllocatedByEpoch(
        uint256 epoch
    ) external view returns (uint256);

    /// @notice Indicates the amount of token rewards allocated across all
    ///         chains, for an era. An era is a particular period in time in
    ///         which rewards are constant, before a halvening event moves the
    ///         protocol to a new era.
    function targetEmissionAllocationByEra(
        uint256 era
    ) external view returns (uint256);

    /// @notice Unlocks a market to process auction-based liquidations.
    /// @param marketToUnlock The address of the market manager to unlock
    ///                       auction-based liquidations with a specific
    ///                       liquidation bonus.
    function unlockAuctionForMarket(address marketToUnlock) external;

    /// @notice Checks if a market is unlocked for auction operations.
    /// @return Whether the caller is an unlocked market, approved for
    ///         auction-based liquidations.
    function isMarketUnlocked() external view returns (bool);

    /// @notice Sets the amount of token rewards allocated on this chain,
    ///         for an epoch.
    /// @dev Only callable by the Voting Hub.
    /// @param epoch The epoch having its token emission values set.
    /// @param emissionsAllocated The amount of token rewards allocated on
    ///                           this chain, for an epoch.
    function setEmissionsAllocatedByEpoch(
        uint256 epoch,
        uint256 emissionsAllocated
    ) external;

    /// @notice Checks whether `user` has transferability enabled or disabled
    ///         for their tokens.
    /// @dev This is inherited from ActionRegistry portion of centralRegistry.
    /// @param user The address to check whether transferability is enabled or
    ///             disabled for.
    /// @return result Indicates whether `user` has transferability disabled
    ///                or not, true = disabled, false = not disabled.
    function checkTransfersDisabled(
        address user
    ) external view returns (bool result);
}

// contracts/interfaces/external/chainlink/IChainlink.sol

interface IChainlink {
    /// @notice Returns the number of decimals the aggregator responds with.
    function decimals() external view returns (uint8);

    /// @notice Returns the latest oracle data from the aggregator.
    /// @return roundId The round ID from the aggregator for which the data
    ///                 was retrieved.
    ///         answer The price returned by the aggregator.
    ///         startedAt The timestamp the current round was started.
    ///         updatedAt The timestamp the current round last was updated.
    ///         answeredInRound The round ID of the round in which `answer`
    ///                         was computed.
    function latestRoundData() external view returns (
        uint80 roundId,
        int256 answer,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    );
    
    /// @notice Returns the latest roundID the aggregator responds with.
    function latestRound() external view returns (uint256);

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

// contracts/interfaces/IDynamicIRM.sol

interface IDynamicIRM {
    /// @notice Returns the interval at which interest rates are adjusted.
    /// @notice The interval at which interest rates are adjusted,
    ///         in seconds.
    function ADJUSTMENT_RATE() external view returns (uint256);

    /// @notice The borrowable token linked to this interest rate model
    ///         contract.
    function linkedToken() external view returns (address);

    /// @notice Calculates the current borrow rate, per second.
    /// @dev This function's intention is for frontend data querying and
    ///     should not be used for onchain execution.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @return result The borrow interest rate percentage, per second,
    ///                in `WAD`.
    function borrowRate(
        uint256 assetsHeld,
        uint256 debt
    ) external view returns (uint256 result);

    /// @notice Calculates the current borrow rate per second,
    ///         with updated vertex multiplier applied.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @return result The borrow rate percentage per second, in `WAD`.
    function predictedBorrowRate(
        uint256 assetsHeld,
        uint256 debt
    ) external view returns (uint256 result);

    /// @notice Calculates the current supply rate, per second.
    /// @dev This function's intention is for frontend data querying and
    ///     should not be used for onchain execution.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @param interestFee The current interest rate protocol fee
    ///                    for the market token.
    /// @return result The supply interest rate percentage, per second,
    ///                in `WAD`.
    function supplyRate(
        uint256 assetsHeld,
        uint256 debt,
        uint256 interestFee
    ) external view returns (uint256 result);

    /// @notice Calculates the interest rate paid per second by borrowers,
    ///         in percentage paid, per second, in `WAD`, and updates
    ///         `vertexMultiplier` if necessary.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param debt The amount of outstanding debt in the pool.
    /// @return ratePerSecond The interest rate paid per second by borrowers,
    ///                       in percentage paid, per second, in `WAD`.
    /// @return adjustmentRate The period of time at which interest rates are
    ///                        adjusted, in seconds.
    function adjustedBorrowRate(
        uint256 assetsHeld,
        uint256 debt
    ) external returns (uint256 ratePerSecond, uint256 adjustmentRate);

    /// @notice Calculates the borrow utilization rate of the market.
    /// @param assetsHeld The amount of underlying assets held in the pool.
    /// @param outstandingDebt The amount of outstanding debt in the pool.
    /// @return The utilization rate between [0, WAD].
    function utilizationRate(
        uint256 assetsHeld,
        uint256 outstandingDebt
    ) external view returns (uint256);
}

// contracts/interfaces/IERC165.sol

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

// contracts/interfaces/IERC20.sol

// @dev Interface of the ERC20 standard
interface IERC20 {
    // @dev Returns the name of the token.
    function name() external view returns (string memory);

    // @dev Returns the symbol of the token.
    function symbol() external view returns (string memory);

    // @dev Returns the decimals of the token.
    function decimals() external view returns (uint8);

    // @dev Emitted when `value` tokens are moved from one account (`from`) to
    //      another (`to`).
    // Note that `value` may be zero.
    event Transfer(address indexed from, address indexed to, uint256 value);

    // @dev Emitted when the allowance of a `spender` for an `owner` is set by
    //      a call to {approve}. `value` is the new allowance.
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    // @dev Returns the amount of tokens in existence.
    function totalSupply() external view returns (uint256);

    // @dev Returns the amount of tokens owned by `account`.
    function balanceOf(address account) external view returns (uint256);

    // @dev Moves `amount` tokens from the caller's account to `to`.
    // Returns a boolean value indicating whether the operation succeeded.
    // Emits a {Transfer} event.
    function transfer(address to, uint256 amount) external returns (bool);

    // @dev Moves `amount` tokens from `from` to `to` using the
    //      allowance mechanism. `amount` is then deducted from the caller's
    //      allowance.
    // Returns a boolean value indicating whether the operation succeeded.
    // Emits a {Transfer} event.
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    // @dev Returns the remaining number of tokens that `spender` will be
    //      allowed to spend on behalf of `owner` through {transferFrom}. This
    //      is zero by default.
    function allowance(
        address owner,
        address spender
    ) external view returns (uint256);

    //  @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    //       Returns a boolean value indicating whether the operation succeeded.
    //       IMPORTANT: Beware that changing an allowance with this method brings the risk
    //       that someone may use both the old and the new allowance by unfortunate
    //       transaction ordering. One possible solution to mitigate this race
    //       condition is to first reduce the spender's allowance to 0 and set the
    //       desired value afterwards:
    //       https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
    // Emits an {Approval} event.
    function approve(address spender, uint256 amount) external returns (bool);
}

// contracts/interfaces/IMarketManager.sol

interface IMarketManager {
    /// TYPES ///

    /// @notice Data structure passed communicating the intended liquidation
    ///         scenario to review based on current liquidity levels.
    /// @param collateralToken The token which was used as collateral
    ///                        by `account` and may be seized.
    /// @param debtToken The token to potentially repay which has
    ///                  outstanding debt by `account`.
    /// @param numAccounts The number of accounts to be, potentially,
    ///                    liquidated.
    /// @param liquidateExact Whether the liquidator desires a specific
    ///                       liquidation amount.
    /// @param liquidatedShares Empty variable slot to store how much
    ///                         `collateralToken` will be seized as
    ///                         part of a particular liquidation.
    /// @param debtRepaid Empty variable slot to store how much
    ///                   `debtToken` will be repaid as part of a
    ///                   particular liquidation.
    /// @param badDebt Empty variable slot to store how much bad debt will
    ///                be realized by lenders as part of a particular
    ///                liquidation.
    struct LiqAction {
        address collateralToken;
        address debtToken;
        uint256 numAccounts;
        bool liquidateExact;
        uint256 liquidatedShares;
        uint256 debtRepaid;
        uint256 badDebt;
    }

    /// @notice Data structure returned communicating outcome of a liquidity
    ///         scenario review based on current liquidity levels.
    /// @param liquidatedShares An array containing the collateral amounts to
    ///                         liquidate from accounts, in shares.
    /// @param debtRepaid The total amount of debt to repay from accounts,
    ///                   in assets.
    /// @param badDebtRealized The total amount of debt to realize as losses
    ///                        for lenders, in assets.
    struct LiqResult {
        uint256[] liquidatedShares;
        uint256 debtRepaid;
        uint256 badDebtRealized;
    }

    /// @notice Returns whether minting, collateralization, borrowing of
    ///         `cToken` is paused.
    /// @param cToken The address of the Curvance token to return
    ///               action statuses of.
    /// @return bool Whether minting `cToken` is paused or not.
    /// @return bool Whether collateralization `cToken` is paused or not.
    /// @return bool Whether borrowing `cToken` is paused or not.
    function actionsPaused(
        address cToken
    ) external view returns (bool, bool, bool);

    /// @notice Returns the current collateralization configuration
    ///         of `cToken`.
    /// @param cToken The address of the Curvance token to return
    ///               collateralization configuration of.
    /// @return The ratio at which this token can be borrowed against
    ///         when collateralized.
    /// @return The collateral requirement where dipping below this
    ///         will cause a soft liquidation.
    /// @return The collateral requirement where dipping below
    ///         this will cause a hard liquidation.
    function collConfig(address cToken) external view returns (
         uint256, uint256, uint256
    );

    /// @notice Returns the current liquidation configuration
    ///         of `cToken`.
    /// @param cToken The address of the Curvance token to return
    ///               liquidation configuration of.
    /// @return The base ratio at which this token will be
    ///         compensated on soft liquidation.
    /// @return The liquidation incentive curve length between soft
    ///         liquidation to hard liquidation, in `WAD`. e.g. 5% base
    ///         incentive with 8% curve length results in 13% liquidation
    ///         incentive on hard liquidation.
    /// @return The minimum possible liquidation incentive for during an
    ///         auction, in `WAD`.
    /// @return The maximum possible liquidation incentive for during an
    ///         auction, in `WAD`.
    /// @return Maximum % that a liquidator can repay when soft
    ///         liquidating an account, in `WAD`.
    /// @return Curve length between soft liquidation and hard liquidation,
    ///         should be equal to 100% - `closeFactorBase`, in `WAD`.
    /// @return The minimum possible close factor for during an auction,
    ///         in `WAD`.
    /// @return The maximum possible close factor for during an auction,
    ///         in `WAD`.
    function liquidationConfig(address cToken) external view returns (
        uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
    );

    /// @notice Enables an auction-based liquidation, potentially with a dynamic
    ///         close factor and liquidation penalty values in transient storage.
    /// @dev Transient storage enforces any liquidator outside auction-based
    ///      liquidations uses the default risk parameters.
    /// @param cToken The Curvance token to configure liquidations for during
    ///               an auction-based liquidation.
    /// @param incentive The auction liquidation incentive value, in `BPS`.
    /// @param closeFactor The auction close factor value, in `BPS`.
    function setTransientLiquidationConfig(
        address cToken,
        uint256 incentive,
        uint256 closeFactor
    ) external;

    /// @notice Called from the AuctionManager as a post hook after liquidations
    ///         are tried to enable all collateral to be liquidated outside
    ///         an Auction tx.
    /// @notice Resets the liquidation risk parameters in transient storage to
    ///         zero.
    /// @dev This is redundant since the transient values will be reset after
    ///      the liquidation transaction, but can be useful during meta calls
    ///      with multiple liquidations during a single transaction. 
    function resetTransientLiquidationConfig() external;

    /// @notice Checks if the account should be allowed to mint tokens
    ///         in the given market.
    /// @param cToken The token to verify mints against.
    function canMint(address cToken) external;

    /// @notice Checks if the account should be allowed to collateralize
    ///         their shares of the given market.
    ///         Prunes unused positions in `account` data.
    /// @dev May emit a {PositionUpdated} event.
    /// @param cToken The token to verify collateralization of.
    /// @param account The account which would collateralize the asset.
    /// @param newNetCollateral The amount of shares that would be
    ///                         collateralized in total if allowed.
    function canCollateralize(
        address cToken,
        address account,
        uint256 newNetCollateral
    ) external;

    /// @notice Checks if the account should be allowed to redeem tokens
    ///         in the given market, and then redeems.
    /// @dev This can only be called by the cToken itself.
    /// @param cToken The token to verify the redemption against.
    /// @param shares The number of cToken shares to redeem for the
    ///               underlying asset in the market.
    /// @param account The account which would redeem `shares`.
    /// @param balanceOf The current cToken share balance of `account`.
    /// @param collateralPosted The current cToken shares posted as
    ///                         collateral by `account`.
    /// @param forceRedeemCollateral Whether the collateral should be always
    ///                              reduced.
    function canRedeemWithCollateralRemoval(
        address cToken,
        uint256 shares,
        address account,
        uint256 balanceOf,
        uint256 collateralPosted,
        bool forceRedeemCollateral
    ) external returns (uint256);

    /// @notice Checks if the account should be allowed to borrow
    ///         the underlying asset of the given market.
    ///         Prunes unused positions in `account` data.
    /// @dev May emit a {PositionUpdated} event.
    /// @param cToken The token to verify borrowability of.
    /// @param assets The amount of underlying assets `account` would borrow.
    /// @param account The account which would borrow the asset.
    /// @param newNetDebt The amount of assets that would be
    ///                   outstanding debt in total if allowed.
    function canBorrow(
        address cToken,
        uint256 assets,
        address account,
        uint256 newNetDebt
    ) external;

    /// @notice Checks if the account should be allowed to borrow
    ///         the underlying asset of the given market,
    ///         and notifies the market of the borrow.
    /// @dev This can only be called by the market itself.
    /// @param cToken The market to verify the borrow against.
    /// @param assets The amount of underlying assets `account` would borrow.
    /// @param account The account which would borrow the asset.
    /// @param newNetDebt The amount of assets that would be
    ///                   outstanding debt in total if allowed.
    function canBorrowWithNotify(
        address cToken,
        uint256 assets,
        address account,
        uint256 newNetDebt
    ) external;

    /// @notice Checks if the account should be allowed to repay a borrow
    ///         in the given market, may clean up positions.
    /// @param cToken The Curvance token to verify the repayment of.
    /// @param newNetDebt The new debt amount owed by `account` after
    ///                   repayment.
    /// @param debtAsset The debt asset being repaid to `cToken`.
    /// @param decimals The decimals that `debtToken` is measured in.
    /// @param account The account who will have their loan repaid.
    function canRepayWithReview(
        address cToken,
        uint256 newNetDebt,
        address debtAsset,
        uint256 decimals,
        address account
    ) external;

    /// @notice Checks if the liquidation should be allowed to occur,
    ///         and returns how many collateralized shares should be seized
    ///         on liquidation.
    /// @param debtAmounts The amounts of outstanding debt the liquidator
    ///                    wishes to repay, in underlying assets, empty if
    ///                    intention is to liquidate maximum amount possible
    ///                    for each account.
    /// @param liquidator The address of the account trying to liquidate
    ///                   `accounts`.
    /// @param accounts The addresses of the accounts to be liquidated.
    /// @param action A LiqAction struct containing:
    ///               collateralToken The token which is used as collateral
    ///                               by `account` and may be seized.
    ///               debtToken The token to potentially repay which has
    ///                         outstanding debt by `account`.
    ///               numAccounts The number of accounts to be, potentially,
    ///                           liquidated.
    ///               liquidateExact Whether the liquidator desires a
    ///                              specific liquidation amount.
    ///               collateralLiquidated Empty variable slot to store how
    ///                                    much `collateralToken` will be
    ///                                    seized as part of a particular
    ///                                    liquidation.
    ///               debtRepaid Empty variable slot to store how much
    ///                          `debtToken` will be repaid as part of a
    ///                          particular liquidation.
    ///               badDebt Empty variable slot to store how much bad debt
    ///                       will be realized as part of a particular
    ///                       liquidation.
    /// @return result A LiqResult struct containing:
    ///                liquidatedShares An array containing the collateral
    ///                                 amounts to liquidate from
    ///                                 `accounts`.
    ///                debtRepaid The total amount of debt to repay from
    ///                           `accounts`.
    ///                badDebtRealized The total amount of debt to realize as
    ///                                losses for lenders inside this market.
    /// @return An array containing the debt amounts to repay from
    ///        `accounts`, in assets.
    function canLiquidate(
        uint256[] memory debtAmounts,
        address liquidator,
        address[] calldata accounts,
        IMarketManager.LiqAction memory action
    ) external returns (LiqResult memory, uint256[] memory);

    /// @notice Checks if the seizing of `collateralToken` by repayment of
    ///         `debtToken` should be allowed.
    /// @param collateralToken The Curvance token which was used as collateral
    ///                        and will be seized.
    /// @param debtToken The Curvance token which has outstanding debt to and
    ///                  would be repaid during `collateralToken` seizure.
    function canSeize(address collateralToken, address debtToken) external;

    /// @notice Checks if the account should be allowed to transfer collateral
    ///         tokens in the given market.
    /// @param cToken The Curvance token to verify the transfer of.
    /// @param shares The amount of `cToken` to transfer.
    /// @param account The account which will transfer `shares`.
    /// @param balanceOf The current balance that `account` has of `cToken`
    ///                  shares.
    /// @param collateralPosted The amount of `cToken` shares posted as
    ///                         collateral by `account`.
    /// @param isCollateral Boolean indicating whether the token is currently
    ///                     being used as collateral.
    function canTransfer(
        address cToken,
        uint256 shares,
        address account,
        uint256 balanceOf,
        uint256 collateralPosted,
        bool isCollateral
    ) external returns (uint256);

    /// @notice Updates `account` cooldownTimestamp to the current block
    ///         timestamp.
    /// @dev The caller must be a listed cToken in the `markets` mapping.
    /// @param cToken The address of the token that the account is borrowing.
    /// @param account The address of the account that has just borrowed.
    function notifyBorrow(address cToken, address account) external;

    /// @notice A list of all tokens inside this market for
    ///         offchain querying.
    function queryTokensListed() external view returns (address[] memory);

    /// @notice Returns whether `cToken` is listed in the lending market.
    /// @param cToken market token address.
    function isListed(address cToken) external view returns (bool);

    /// @notice The total amount of `cToken` that can be posted as collateral,
    ///         in shares.
    function collateralCaps(address cToken) external view returns (uint256);

    /// @notice The total amount of `cToken` underlying that can be borrowed,
    ///         in assets.
    function debtCaps(address cToken) external view returns (uint256);

    /// @notice Returns whether `addressToCheck` is an approved position
    ///         manager or not.
    /// @param addressToCheck Address to check for position management
    ///                       authority.
    function isPositionManager(
        address addressToCheck
    ) external view returns (bool);

    /// @notice Returns the assets an account has entered.
    /// @param account The address of the account to pull assets for.
    /// @return A dynamic list with the assets `account` has entered.
    function assetsOf(
        address account
    ) external view returns (address[] memory);

    /// @notice Determine `account`'s current status between collateral,
    ///         debt, and additional liquidity.
    /// @param account The account to determine liquidity for.
    /// @return The current total collateral amount of `account`.
    /// @return The maximum debt amount of `account` can take out with
    ///         their current collateral.
    /// @return The current total borrow amount of `account`.
    function statusOf(
        address account
    ) external returns (uint256, uint256, uint256);
}

// contracts/interfaces/IMulticallChecker.sol

interface IMulticallChecker {
    function checkCalldata(
        address caller,
        address target,
        bytes memory data
    ) external;
}

// contracts/interfaces/IOracleAdaptor.sol

interface IOracleAdaptor {
    /// TYPES ///

    /// @notice Return data from pricing an asset.
    /// @param price The price of the asset.
    /// @param inUsd Boolean indicating whether `price` is denominated
    ///              in USD (true) or native token (false).
    /// @param hadError Boolean indicating whether the asset was priced
    ///                 without running into any issues or not.
    struct PricingResult {
        uint256 price;
        bool inUSD;
        bool hadError;
    }

    /// @notice Guard logic when pricing `asset` configured to prevent oracle
    ///         mispricing either by mistake or malicious PriceGuard when
    ///         pricing `asset` denominated either USD or native tokens.
    /// @param timestampStart When `increasePerYear` should start increasing
    ///                       `basePrice` raising the maximum price returned
    ///                       when pricing `asset`.
    /// @param ips The magnitude that `basePrice` should increase overtime
    ///            from `timestampStart`, in `WAD`, per second.
    /// @param basePrice The base price that should be the maximum price
    ///                  returned when pricing `asset`.
    /// @param minPrice The minimum price that should be allowed to be
    ///                 returned when pricing `asset`.
    struct PriceGuard {
        uint40 timestampStart;
        uint40 ips;
        uint88 basePrice;
        uint88 minPrice;
    }

    /// @notice Called by OracleManager to price an asset.
    /// @param asset The address of the asset for which the price is needed.
    /// @param inUSD A boolean to determine if the price should be returned in
    ///              USD or not.
    /// @param getLower A boolean to determine if lower of two oracle prices
    ///                 should be retrieved.
    /// @return result Return data for a priced asset containing:
    ///                price The price of the asset.
    ///                inUSD Boolean indicating whether `price` is denominated
    ///                      in USD (true) or native token (false).
    ///                hadError Boolean indicating whether the asset was priced
    ///                         without running into any issues or not.
    function getPrice(
        address asset,
        bool inUSD,
        bool getLower
    ) external view returns (PricingResult memory);

    /// @notice Whether an asset is supported by the Oracle Adaptor or not.
    /// @dev Asset => Supported by adaptor.
    function isSupportedAsset(address asset) external view returns (bool);

    /// @notice Token price guard configuration for pricing an asset.
    /// @dev Token address => inUSD => Price Guard configuration.
    function getPriceGuard(
        address asset,
        bool inUSD
    ) external view returns (PriceGuard memory);

    /// @notice Returns the adaptor's type.
    /// @dev Used by frontends to determine how to properly interact
    ///      with a supported asset.
    function adaptorType() external view returns (uint256);
}

// contracts/libraries/LowLevelCallsHelper.sol

library LowLevelCallsHelper {
    /// ERRORS ///

    error LowLevelCallsHelper__InsufficientBalance();
    error LowLevelCallsHelper__CallFailed();

    /// INTERNAL FUNCTIONS ///

    /// @notice Executes a low level .call() and validates that execution
    ///         was safely performed.
    /// @dev Bubbles up errors and reverts if anything along the execution
    ///      path failed or was a red flag.
    /// @param target The target contract address to execute .call() at.
    /// @param data The bytecode data to attach to the .call() execution
    ///             including the function signature hash and function call
    ///             parameters.
    function _call(
        address target,
        bytes memory data
    ) internal returns (bytes memory) {
        (bool success, bytes memory returnData) = target.call{value: 0}(data);
        
        return _verifyResult(target, success, returnData);
    }

    /// @notice Executes a low level .call(), with attached native token
    ///         and validates that execution was safely performed.
    /// @dev Bubbles up errors and reverts if anything along the execution
    ///      path failed or was a red flag.
    /// @param target The target contract address to execute .call() at.
    /// @param data The bytecode data to attach to the .call() execution
    ///             including the function signature hash and function call
    ///             parameters.
    /// @param value The amount of native token to attach to the low level
    ///              call.
    function _callWithNative(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert LowLevelCallsHelper__InsufficientBalance();
        }

        (bool success, bytes memory returnData) = target.call{
            value: value
        }(data);

        return _verifyResult(target, success, returnData);
    }

    /// @notice Executes a low level .delegatecall() and validates that
    ///         execution was safely performed.
    /// @dev Bubbles up errors and reverts if anything along the execution
    ///      path failed or was a red flag.
    /// @param target The target contract address to execute .delegatecall()
    ///               at.
    /// @param data The bytecode data to attach to the .call() execution
    ///             including the function signature hash and function call
    ///             parameters.
    function _delegateCall(
        address target,
        bytes memory data
    ) internal returns (bytes memory) {
        (bool success, bytes memory returnData) = target.delegatecall(data);

        return _verifyResult(target, success, returnData);
    }

    /// @dev Validates whether the low level call or delegate call was
    ///      successful and reverts in cases of bubbled up revert messages
    ///      or if `target` was not actually a contract.
    function _verifyResult(
        address target,
        bool success,
        bytes memory returnData
    ) internal view returns (bytes memory) {
        _propagateError(success, returnData);

        // If the call was successful but there was no return data we need
        // to make sure a contract was actually called as expected.
        if (returnData.length == 0 && target.code.length == 0) {
            revert LowLevelCallsHelper__CallFailed();
        }

        return returnData;
    }

    /// @dev Propagates an error message, if necessary.
    /// @param success If transaction was successful.
    /// @param resultData The transaction result data.
    function _propagateError(
        bool success,
        bytes memory resultData
    ) internal pure {
        if (!success) {
            if (resultData.length == 0) {
                revert LowLevelCallsHelper__CallFailed();
            }

            // Bubble up error if there was one given.
            assembly {
                revert(add(32, resultData), mload(resultData))
            }
        }
    }
}

// contracts/libraries/external/SafeTransferLib.sol

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

// contracts/libraries/external/ERC165Checker.sol

// @author Modified from OpenZeppelin Contracts (utils/introspection/ERC165Checker.sol)

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface.
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            supportsERC165InterfaceUnchecked(
                account,
                type(IERC165).interfaceId
            ) &&
            !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(
        address account,
        bytes4 interfaceId
    ) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return
            supportsERC165(account) &&
            supportsERC165InterfaceUnchecked(account, interfaceId);
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     *
     * Some precompiled contracts will falsely indicate support for a given interface, so caution
     * should be exercised when using this function.
     *
     * Interface identification is specified in ERC-165.
     */
    function supportsERC165InterfaceUnchecked(
        address account,
        bytes4 interfaceId
    ) internal view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeCall(
            IERC165.supportsInterface,
            (interfaceId)
        );

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(
                30000,
                account,
                add(encodedParams, 0x20),
                mload(encodedParams),
                0x00,
                0x20
            )
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}

// contracts/libraries/CentralRegistryLib.sol

/// @title Curvance Central Registry Validation Library
/// @notice For validating that Central Registry is configured properly
///         on launch.
library CentralRegistryLib {
    /// ERRORS ///

    error CentralRegistryLib__InvalidCentralRegistry();

    /// INTERNAL FUNCTIONS ///

    /// @notice Validates that `cr` is the Protocol Central Registry.
    /// @param cr The proposed Protocol Central Registry.
    function _isCentralRegistry(ICentralRegistry cr) internal view {
        if (
            !ERC165Checker.supportsInterface(
                address(cr),
                type(ICentralRegistry).interfaceId
            )
        ) {
            revert CentralRegistryLib__InvalidCentralRegistry();
        }
    }
}

// contracts/libraries/Multicall.sol

/// @title Curvance Multicall helper.
/// @notice Multicall implementation to support pull based oracles and
///         other chained actions within Curvance.
abstract contract Multicall {
    /// TYPES ///

    /// @notice Struct containing information on the desired
    ///         multicall action to execute. 
    /// @param target The address of the target contract to execute the call at.
    /// @param isPriceUpdate Boolean indicating if the call is a price update.
    /// @param data The data to attach to the call.
    struct MulticallAction {
        address target;
        bool isPriceUpdate;
        bytes data;
    }

    /// ERRORS ///

    error Multicall__InvalidTarget();
    error Multicall__UnknownCalldata();

    /// EXTERNAL FUNCTIONS ///

    /// @notice Executes multiple calls in a single transaction.
    ///         This can be used to update oracle prices before
    ///         a liquidity dependent action.
    function multicall(
        MulticallAction[] calldata calls
    ) external returns (bytes[] memory results) {
        ICentralRegistry cr = _getCentralRegistry();
        uint256 numCalls = calls.length;
        results = new bytes[](numCalls);
        MulticallAction memory cachedCall;

        for (uint256 i; i < numCalls; ++i) {
            cachedCall = calls[i];
            
            if (cachedCall.isPriceUpdate) {
                // CASE: We need to update a pull based price oracle and we
                //       need a direct call to the target address.
                address checker = cr.multicallChecker(cachedCall.target);

                // Validate we know how to verify this calldata.
                if (checker == address(0)) {
                    revert Multicall__UnknownCalldata();
                }

                IMulticallChecker(checker).checkCalldata(
                    msg.sender,
                    cachedCall.target,
                    cachedCall.data
                );

                results[i] = LowLevelCallsHelper.
                    _call(cachedCall.target, cachedCall.data);
                
                continue;
            }

            // CASE: Not a price update and we need delegate the call to the
            //       current address.

            if (address(this) != cachedCall.target) {
                revert Multicall__InvalidTarget();
            }

            results[i] = LowLevelCallsHelper.
                _delegateCall(address(this), cachedCall.data);
        }
    }

    /// @notice Returns the Protocol Central Registry contract in interface
    ///         form.
    /// @dev MUST be overridden in every multicallable contract's
    ///      implementation.
    function _getCentralRegistry()
        internal
        view
        virtual
        returns (ICentralRegistry);
}

// contracts/libraries/CommonLib.sol

/// @title Curvance Common Library
/// @notice A utility library for common functions used throughout the
///        Curvance Protocol.
library CommonLib {

    /// @notice Returns whether `tokenA` matches `tokenB` or not.
    /// @param tokenA The first token address to compare.
    /// @param tokenB The second token address to compare.
    /// @return Whether `tokenA` matches `tokenB` or not.
    function _isMatchingToken(
        address tokenA,
        address tokenB
    ) internal pure returns (bool) {
        if (tokenA == tokenB) {
            return true;
        }

        if (_isNative(tokenA) && _isNative(tokenB)) {
            return true;
        }

        return false;
    }

    /// @notice Returns whether `token` is referring to network gas token
    ///         or not.
    /// @param token The address to review.
    /// @return result Whether `token` is referring to network gas token or
    ///                not.
    function _isNative(address token) internal pure returns (bool result) {
        result = token == address(0) ||
            token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    }

    /// @notice Returns balance of `token` for this contract.
    /// @param token The token address to query balance of.
    /// @return b The balance of `token` inside address(this).
    function _balanceOf(address token) internal view returns (uint256 b) {
        b = _isNative(token) ? address(this).balance :
            IERC20(token).balanceOf(address(this));
    }

    /// @notice Returns the Oracle Manager in interface form from `cr`.
    /// @param cr The address of the Protocol Central Registry.
    /// @return oracleManager The Oracle Manager in interface form.
    function _oracleManager(
        ICentralRegistry cr
    ) internal view returns (IOracleManager oracleManager) {
        oracleManager = IOracleManager(cr.oracleManager());
    }
}

// contracts/interfaces/IBorrowableCToken.sol

interface IBorrowableCToken {
    /// ICToken GENERIC FUNCTIONS ///

    /// @notice Starts a cToken market, executed via marketManager.
    /// @dev This initial mint is a failsafe against rounding exploits,
    ///      although, we protect against them in many ways,
    ///      better safe than sorry.
    /// @param by The account initializing deposits.
    function initializeDeposits(address by) external returns (bool);

    /// @notice Returns the decimals of the cToken.
    /// @dev We pull directly from underlying incase its a proxy contract,
    ///      and changes decimals on us.
    /// @return The number of decimals for this cToken,
    ///         matching the underlying token.
    function decimals() external view returns (uint8);

    /// @notice Returns whether the underlying token can be borrowed.
    /// @dev true = Borrowable; false = Not Borrowable.
    /// @return Whether this token is borrowable or not.
    function isBorrowable() external view returns (bool);

    /// @notice The token balance of an account.
    /// @dev Account address => account token balance.
    /// @param account The address of the account to query token balance for.
    function balanceOf(address account) external view returns (uint256);

    /// @notice Returns the address of the underlying asset.
    /// @return The address of the underlying asset.
    function asset() external view returns (address);

    /// @notice Returns the current vesting yield information.
    /// @return vestingRate % per second in `asset()`.
    /// @return vestingEnd When the current vesting period ends and interest
    ///                    rates paid will update.
    /// @return lastVestingClaim Last time pending vested yield was claimed.
    /// @return debtIndex The current market debt index.
    function getYieldInformation() external view returns (
        uint256 vestingRate,
        uint256 vestingEnd,
        uint256 lastVestingClaim,
        uint256 debtIndex
    );

    /// @notice Get a snapshot of `account` data in this Curvance token.
    /// @dev Used by marketManager to more efficiently perform
    ///      liquidity checks.
    ///      NOTE: Does not accrue pending interest as part of the call.
    /// @param account The address of the account to snapshot.
    /// @return The account snapshot of `account`.
    function getSnapshot(
        address account
    ) external view returns (AccountSnapshot memory);

    /// @notice Total number of cTokens in circulation.
    function totalSupply() external view returns (uint256);

    /// @notice Returns the total amount of assets held by the market.
    /// @return The total amount of assets held by the market.
    function totalAssets() external view returns (uint256);

    /// @notice Address of the Market Manager linked to this contract.
    function marketManager() external view returns (IMarketManager);

    /// @notice Returns the amount of assets that would be exchanged
    ///         by the vault for `shares` provided.
    /// @param shares The number of shares to theoretically use
    ///               for conversion to assets.
    /// @return The number of assets a user would receive for converting
    ///         `shares`.
    function convertToAssets(uint256 shares) external view returns (uint256);

    /// @notice Returns share -> asset exchange rate, in `WAD`.
    /// @dev Oracle Manager calculates cToken value from this exchange rate.
    function exchangeRate() external view returns (uint256);

    /// @notice Executes multiple calls in a single transaction.
    ///         This can be used to update oracle prices before
    ///         a liquidity dependent action.
    function multicall(
        Multicall.MulticallAction[] memory calls
    ) external returns (bytes[] memory results);

    /// @notice Caller deposits `assets` into the market and `receiver`
    ///         receives shares.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function deposit(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev The caller must be depositing for themselves, or be managing
    ///      their position through a Position Manager contract.
    ///      If the caller is not approved to collateralize the function will
    ///      simply deposit assets on behalf of `receiver`.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateral(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev Requires that `receiver` approves the caller prior to
    ///      collateralize on their behalf.
    ///      NOTE: Be careful who you approve here!
    ///      They can delay redemption of assets through repeated
    ///      collateralization preventing withdrawal.
    ///      If the caller is not approved to collateralize the function will
    ///      simply deposit assets on behalf of `receiver`.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateralFor(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to be redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner`.
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares, sending assets to `receiver`.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Caller withdraws assets from the market and burns their
    ///         shares, on behalf of `owner`.
    /// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemCollateralFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Used by a Position Manager contract to redeem assets from
    ///         collateralized shares by `account` to perform a complex
    ///         action.
    /// @param assets The amount of the underlying assets to redeem.
    /// @param owner The owner address of assets to redeem.
    /// @param action Instructions for a deleverage action containing:
    ///               cToken Address of the cToken that will be redeemed from
    ///                      and assets swapped into `borrowableCToken` asset.
    ///               collateralAssets The amount of `cToken` that will be
    ///                                deleveraged, in assets.
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will have its debt paid.
    ///               repayAssets The amount of `borrowableCToken` asset that
    ///                           will be repaid to lenders.
    ///               swapActions Swap actions instructions converting
    ///                           collateral asset into debt asset to
    ///                           facilitate deleveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       deleverage action.
    function withdrawByPositionManager(
        uint256 assets,
        address owner,
        IPositionManager.DeleverageAction memory action
    ) external;

    /// @notice Amount of tokens that has been posted as collateral,
    ///         in shares.
    function marketCollateralPosted() external view returns (uint256);

    /// @notice Shares of this token that an account has posted as collateral.
    /// @param account The address of the account to check collateral posted
    ///                of.
    function collateralPosted(address account) external view returns (uint256);

    /// @notice Transfers tokens from `account` to `liquidator`.
    /// @dev Will fail unless called by a cToken during the process
    ///      of liquidation.
    /// @param shares An array containing the number of cToken shares
    ///               to seize.
    /// @param liquidator The account receiving seized cTokens.
    /// @param accounts An array containing the accounts having
    ///                 collateral seized.
    function seize(
        uint256[] calldata shares,
        address liquidator,
        address[] calldata accounts
    ) external;

    /// @notice Allows users to simulate the effects of their deposit at
    ///         the current block.
    /// @param assets The number of assets to preview a deposit call.
    /// @return The shares received for depositing `assets`.
    function previewDeposit(uint256 assets) external view returns (uint256);

    /// IBorrowableCToken SPECIFIC FUNCTIONS ///

    /// @notice Address of the current Dynamic IRM.
    function IRM() external view returns (IDynamicIRM);

    /// @notice Fee that goes to protocol for interested generated for
    ///         lenders, in `WAD`.
    function interestFee() external view returns (uint256);

    /// @notice Can accrue interest yield, configure next interest accrual
    ///         period, and updates vesting data, if needed.
    /// @dev May emit a {RatesAdjusted} event.
    function accrueIfNeeded() external;

    /// @notice The amount of tokens that has been borrowed as debt,
    ///         in assets.
    function marketOutstandingDebt() external view returns (uint256);

    /// @notice Returns the current debt balance for `account`.
    /// @dev Note: Pending interest is not applied in this calculation.
    /// @param account The address whose debt balance should be calculated.
    /// @return result The current outstanding debt balance of `account`.
    function debtBalance(
        address account
    ) external view returns (uint256 result);

    /// @notice Updates pending interest and returns the current outstanding
    ///         debt owed by `account`.
    /// @param account The address whose debt balance should be calculated.
    /// @return result The current outstanding debt of `account`, with pending
    ///                interest applied.
    function debtBalanceUpdated(
        address account
    ) external returns (uint256 result);

    /// @notice Updates pending interest and returns the up-to-date exchange
    ///         rate from the underlying to the BorrowableCToken.
    /// @return result The share -> asset exchange rate, in `WAD`.
    function exchangeRateUpdated() external returns (uint256);

    /// @notice Used by a delegated user to borrow underlying tokens
    ///         from lenders, based on collateral posted inside this market
    ///         by `account`.
    /// @dev Updates pending interest before executing the borrow.
    ///      NOTE: Be careful who you approve here!
    ///      Not only can they take borrowed funds, but, they can delay
    ///      repayment through repeated borrows preventing withdrawal.
    /// @param assets The amount of the underlying asset to borrow.
    /// @param receiver The account who will receive the borrowed assets.
    /// @param owner The account who will have their assets borrowed
    ///              against.
    function borrowFor(
        uint256 assets,
        address receiver,
        address owner
    ) external;

    /// @notice Used by a Position Manager contract to borrow assets from
    ///         lenders, based on collateralized shares by `account` to
    ///         perform a complex action.
    /// @param assets The amount of the underlying assets to borrow.
    /// @param owner The account address to borrow on behalf of.
    /// @param action Instructions for a leverage action containing:
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will be borrowed from and assets
    ///                                swapped into `cToken` asset.
    ///               borrowAssets The amount borrowed from
    ///                            `borrowableCToken`, in assets.
    ///               cToken Curvance token assets that borrowed funds will be
    ///                      swapped into.
    ///               swapAction Swap action instructions converting debt
    ///                          asset into collateral asset to facilitate
    ///                          leveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       leverage action.
    function borrowForPositionManager(
        uint256 assets,
        address owner,
        IPositionManager.LeverageAction memory action
    ) external;

    /// @notice Repays underlying tokens to lenders, on behalf of `account`,
    ///         freeing up their collateral posted inside this market.
    /// @dev Updates pending interest before executing the repay.
    /// @param assets The amount to repay, or 0 for the full outstanding
    ///               amount.
    /// @param owner The account address to repay on behalf of.
    function repayFor(uint256 assets, address owner) external;

    /// @notice Gets balance of this contract, in terms of the underlying.
    /// @dev This excludes changes in underlying token balance by the
    ///      current transaction, if any.
    /// @return The quantity of underlying tokens held by the market.
    function assetsHeld() external view returns (uint256);
}

// contracts/interfaces/ICToken.sol

struct AccountSnapshot {
    address asset;
    address underlying;
    uint8 decimals;
    bool isCollateral;
    uint256 collateralPosted;
    uint256 debtBalance;
}

interface ICToken {
    /// @notice Starts a cToken market, executed via marketManager.
    /// @dev This initial mint is a failsafe against rounding exploits,
    ///      although, we protect against them in many ways,
    ///      better safe than sorry.
    /// @param by The account initializing deposits.
    function initializeDeposits(address by) external returns (bool);

    /// @notice Returns the decimals of the cToken.
    /// @dev We pull directly from underlying incase its a proxy contract,
    ///      and changes decimals on us.
    /// @return The number of decimals for this cToken,
    ///         matching the underlying token.
    function decimals() external view returns (uint8);

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

    /// @notice Returns whether the underlying token can be borrowed.
    /// @dev true = Borrowable; false = Not Borrowable.
    /// @return Whether this token is borrowable or not.
    function isBorrowable() external view returns (bool);

    /// @notice The token balance of an account.
    /// @dev Account address => account token balance.
    /// @param account The address of the account to query token balance for.
    function balanceOf(address account) external view returns (uint256);

    /// @notice Returns the address of the underlying asset.
    /// @return The address of the underlying asset.
    function asset() external view returns (address);

    /// @notice Updates pending assets and returns a snapshot of the cToken
    ///         and `account` data.
    /// @dev Used by marketManager to more efficiently perform
    ///      liquidity checks.
    /// @return result The snapshot of the cToken and `account` data.
    function getSnapshotUpdated(
        address account
    ) external returns (AccountSnapshot memory result);

    /// @notice Get a snapshot of `account` data in this Curvance token.
    /// @dev NOTE: Does not accrue pending assets as part of the call.
    /// @param account The address of the account to snapshot.
    /// @return The account snapshot of `account`.
    function getSnapshot(
        address account
    ) external view returns (AccountSnapshot memory);

    /// @notice Total number of cTokens in circulation.
    function totalSupply() external view returns (uint256);

    /// @notice Returns the total amount of assets held by the market.
    /// @return The total amount of assets held by the market.
    function totalAssets() external view returns (uint256);

    /// @notice Address of the Market Manager linked to this contract.
    function marketManager() external view returns (IMarketManager);

    /// @notice Returns the amount of assets that would be exchanged
    ///         by the vault for `shares` provided.
    /// @param shares The number of shares to theoretically use
    ///               for conversion to assets.
    /// @return The number of assets a user would receive for converting
    ///         `shares`.
    function convertToAssets(uint256 shares) external view returns (uint256);

    /// @notice Updates pending assets and returns the up-to-date exchange
    ///         rate from the underlying to the BorrowableCToken.
    /// @dev Oracle Manager calculates cToken value from this exchange rate.
    /// @return The share -> asset exchange rate, in `WAD`.
    function exchangeRateUpdated() external returns (uint256) ;

    /// @notice Returns the up-to-date exchange rate from the underlying to
    ///         the BorrowableCToken.
    /// @dev Oracle Manager calculates cToken value from this exchange rate.
    /// @return The share -> asset exchange rate, in `WAD`.
    function exchangeRate() external view returns (uint256);

    /// @notice Executes multiple calls in a single transaction.
    ///         This can be used to update oracle prices before
    ///         a liquidity dependent action.
    function multicall(
        Multicall.MulticallAction[] memory calls
    ) external returns (bytes[] memory results);

    /// @notice Caller deposits `assets` into the market and `receiver`
    ///         receives shares.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function deposit(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev The caller must be depositing for themselves, or be managing
    ///      their position through a Position Manager contract.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateral(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Caller deposits `assets` into the market, `receiver` receives
    ///         shares, and collateralization of `assets` is enabled.
    /// @dev Requires that `receiver` approves the caller prior to
    ///      collateralize on their behalf.
    ///      NOTE: Be careful who you approve here!
    ///      They can delay redemption of assets through repeated
    ///      collateralization preventing withdrawal.
    /// @param assets The amount of the underlying assets to deposit.
    /// @param receiver The account that should receive the shares.
    /// @return shares The amount of shares received by `receiver`.
    function depositAsCollateralFor(
        uint256 assets,
        address receiver
    ) external returns (uint256 shares);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to be redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner`.
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Withdraws assets, quoted in `shares` from the market,
    ///         and burns `owner` shares, sending assets to `receiver`.
    /// @dev Does not force collateral to be withdrawn.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Caller withdraws assets from the market and burns their
    ///         shares, on behalf of `owner`.
    /// @dev Forces collateral to be withdrawn from `owner` collateralPosted.
    /// @param shares The amount of shares to redeemed.
    /// @param receiver The account that should receive the assets.
    /// @param owner The account that will burn their shares to withdraw
    ///              assets.
    /// @return assets The amount of assets redeemed by `owner` and sent to
    ///                `receiver`.
    function redeemCollateralFor(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /// @notice Used by a Position Manager contract to redeem assets from
    ///         collateralized shares by `account` to perform a complex
    ///         action.
    /// @param assets The amount of the underlying assets to redeem.
    /// @param owner The owner address of assets to redeem.
    /// @param action Instructions for a deleverage action containing:
    ///               cToken Address of the cToken that will be redeemed from
    ///                      and assets swapped into `borrowableCToken` asset.
    ///               collateralAssets The amount of `cToken` that will be
    ///                                deleveraged, in assets.
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will have its debt paid.
    ///               repayAssets The amount of `borrowableCToken` asset that
    ///                           will be repaid to lenders.
    ///               swapActions Swap actions instructions converting
    ///                           collateral asset into debt asset to
    ///                           facilitate deleveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       deleverage action.
    function withdrawByPositionManager(
        uint256 assets,
        address owner,
        IPositionManager.DeleverageAction memory action
    ) external;

    /// @notice Amount of tokens that has been posted as collateral,
    ///         in shares.
    function marketCollateralPosted() external view returns (uint256);

    /// @notice Shares of this token that an account has posted as collateral.
    /// @param account The address of the account to check collateral posted
    ///                of.
    function collateralPosted(address account) external view returns (uint256);

    /// @notice Transfers tokens from `account` to `liquidator`.
    /// @dev Will fail unless called by a cToken during the process
    ///      of liquidation.
    /// @param shares An array containing the number of cToken shares
    ///               to seize.
    /// @param liquidator The account receiving seized cTokens.
    /// @param accounts An array containing the accounts having
    ///                 collateral seized.
    function seize(
        uint256[] calldata shares,
        address liquidator,
        address[] calldata accounts
    ) external;

    /// @notice Allows users to simulate the effects of their deposit at
    ///         the current block.
    /// @param assets The number of assets to preview a deposit call.
    /// @return The shares received for depositing `assets`.
    function previewDeposit(uint256 assets) external view returns (uint256);
}

// contracts/interfaces/IExternalCalldataChecker.sol

interface IExternalCalldataChecker {
    /// @notice Inspects calldata for compliance with other swap instruction
    ///         parameters.
    /// @dev Used on swap to inspect and validate calldata safety.
    /// @param swapAction Swap action instructions including both direct
    ///                   parameters and decodeable calldata.
    /// @param expectedRecipient Address who will receive proceeds of
    ///                          `swapAction`.
    function checkCalldata(
        SwapperLib.Swap memory swapAction,
        address expectedRecipient
    ) external;
}

// contracts/interfaces/IOracleManager.sol

interface IOracleManager {
    /// @notice Retrieves the price of a specified asset from either single
    ///         or dual oracles.
    /// @dev If the asset has one oracle, it fetches the price from a single feed.
    ///      If it has two or more oracles, it fetches the price from both feeds.
    /// @param asset The address of the asset to retrieve the price for.
    /// @param inUSD Whether the price should be returned in USD or ETH.
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if two feeds are available.
    /// @return price The current price of `asset`.
    /// @return errorCode An error code related to fetching the price:
    ///                   '0' indicates no error fetching price.
    ///                   '1' indicates that price should be taken with
    ///                   caution.
    ///                   '2' indicates a complete failure in receiving
    ///                   a price.
    function getPrice(
        address asset,
        bool inUSD,
        bool getLower
    ) external view returns (uint256 price, uint256 errorCode);

    /// @notice Retrieves the prices of a collateral token and debt token
    ///         underlyings.
    /// @param collateralToken The cToken currently collateralized to price.
    /// @param debtToken The cToken borrowed from to price.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return collateralUnderlyingPrice The current price of
    ///                                   `collateralToken` underlying.
    /// @return debtUnderlyingPrice The current price of `debtToken`
    ///                             underlying.
    function getPriceIsolatedPair(
        address collateralToken,
        address debtToken,
        uint256 errorCodeBreakpoint
    ) external returns (uint256, uint256);

    /// @notice Retrieves the prices and account data of multiple assets
    ///         inside a Curvance Market.
    /// @param account The account to retrieve data for.
    /// @param assets An array of asset addresses to retrieve the prices for.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return AccountSnapshot[] Contains `assets` data for `account`
    /// @return uint256[] Contains prices for `assets`.
    /// @return uint256 The number of assets `account` is in.
    function getPricesForMarket(
        address account,
        address[] calldata assets,
        uint256 errorCodeBreakpoint
    )
        external
        returns (AccountSnapshot[] memory, uint256[] memory, uint256);

    /// @notice Potentially removes the dependency on pricing from `adaptor`
    ///         for `asset`, triggered by an adaptor's notification of a price
    ///         feed's removal.
    /// @notice Removes a pricing adaptor for `asset` triggered by an
    ///         adaptor's notification of a price feed's removal.
    /// @dev Requires that the adaptor is currently being used for pricing
    ///      for `asset`.
    ///      NOTE: This intentionally does not modify asset deviation values
    ///            because they simply wont be used if there are less than two
    ///            pricing adaptors in use, so no reason to delete data as
    ///            when a second pricing adaptor is configured the deviation
    ///            has the opportunity be to reconfigured anyway.
    /// @param asset The address of the asset to potentially remove the
    ///              pricing adaptor dependency from depending on current
    ///              `asset` configuration.
    function notifyFeedRemoval(address asset) external;

    /// @notice Returns the adaptors used for pricing `asset`.
    /// @param asset The address of the asset to get pricing adaptors for.
    /// @return The current adaptor(s) used for pricing `asset`.
    function getPricingAdaptors(
        address asset
    ) external view returns(address[] memory);

    /// @notice Address => Adaptor approval status.
    /// @param adaptor The address of the adaptor to check.
    /// @return True if the adaptor is supported, false otherwise.
    function isApprovedAdaptor(address adaptor) external view returns (bool);

    /// @notice Whether a token is recognized as a Curvance token or not,
    ///         if it is, will return its underlying asset address instead
    ///         of address (0).
    /// @return The cToken's underlying asset, or address(0) if not a cToken.
    function cTokens(address cToken) external view returns (address);

    /// @notice Checks if a given asset is supported by the Oracle Manager.
    /// @dev An asset is considered supported if it has one
    ///      or more associated price feeds.
    /// @param asset The address of the asset to check.
    /// @return True if the asset is supported, false otherwise.
    function isSupportedAsset(address asset) external view returns (bool);

    /// @notice Check whether L2 sequencer is valid or down.
    /// @return True if sequencer is valid.
    function isSequencerValid() external view returns (bool);
}

// contracts/interfaces/IPositionManager.sol

interface IPositionManager {
    /// TYPES ///

    /// @notice Instructions for a leverage action.
    /// @param borrowableCToken Address of the borrowableCToken that will be
    ///                         borrowed from and assets swapped into `cToken`
    ///                         asset.
    /// @param borrowAssets The amount borrowed from `borrowableCToken`,
    ///                     in assets.
    /// @param cToken Curvance token assets that borrowed funds will be
    ///               swapped into.
    /// @param expectedShares The expected shares received from depositing
    ///                       into `cToken` with swapped `borrowAssets`.
    /// @param swapAction Swap action instructions converting debt asset into
    ///                   collateral asset to facilitate leveraging.
    /// @param auxData Optional auxiliary data for execution of a leverage
    ///                action.
    struct LeverageAction {
        IBorrowableCToken borrowableCToken;
        uint256 borrowAssets;
        ICToken cToken;
        uint256 expectedShares;
        SwapperLib.Swap swapAction;
        bytes auxData;
    }

    /// @notice Instructions for a deleverage action.
    /// @param cToken Address of the cToken that will be redeemed from and
    ///               assets swapped into `borrowableCToken` asset.
    /// @param collateralAssets The amount of `cToken` that will be
    ///                         deleveraged, in assets.
    /// @param borrowableCToken Address of the borrowableCToken that will
    ///                         have its debt paid.
    /// @param repayAssets The amount of `borrowableCToken` asset that will
    ///                    be repaid to lenders.
    /// @param swapActions Swap actions instructions converting collateral
    ///                    asset into debt asset to facilitate deleveraging.
    /// @param auxData Optional auxiliary data for execution of a deleverage
    ///                action.
    struct DeleverageAction {
        ICToken cToken;
        uint256 collateralAssets;
        IBorrowableCToken borrowableCToken;
        uint256 repayAssets;
        SwapperLib.Swap[] swapActions;
        bytes auxData;
    }

    /// @notice Callback function to execute post borrow of
    ///         `borrowableCToken`'s asset and swap it to deposit
    ///         new collateralized shares for `owner`.
    /// @dev Measures slippage after this callback validating that `owner`
    ///      is still within acceptable liquidity requirements.
    /// @param borrowableCToken The borrowableCToken borrowed from.
    /// @param borrowAssets The amount of `borrowableCToken`'s asset borrowed.
    /// @param owner The account borrowing that will be swapped into
    ///              collateral assets deposited into Curvance.
    /// @param action Instructions for a leverage action containing:
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will be borrowed from and assets
    ///                                swapped into `cToken` asset.
    ///               borrowAssets The amount borrowed from
    ///                            `borrowableCToken`, in assets.
    ///               cToken Curvance token assets that borrowed funds will be
    ///                      swapped into.
    ///               swapAction Swap action instructions converting debt
    ///                          asset into collateral asset to facilitate
    ///                          leveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       leverage action.
    function onBorrow(
        address borrowableCToken,
        uint256 borrowAssets,
        address owner,
        LeverageAction memory action
    ) external;

    /// @notice Callback function to execute post redemption of `cToken`'s
    ///         asset and swap it to repay outstanding debt for `owner`.
    /// @dev Measures slippage after this callback validating that `owner`
    ///      is still within acceptable liquidity requirements.
    /// @param cToken The Curvance token redeemed for its underlying.
    /// @param collateralAssets The amount of `cToken` underlying redeemed.
    /// @param owner The account redeeming collateral that will be used to
    ///              repay their active debt.
    /// @param action Instructions for a deleverage action containing:
    ///               cToken Address of the cToken that will be redeemed from
    ///                      and assets swapped into `borrowableCToken` asset.
    ///               collateralAssets The amount of `cToken` that will be
    ///                                deleveraged, in assets.
    ///               borrowableCToken Address of the borrowableCToken that
    ///                                will have its debt paid.
    ///               repayAssets The amount of `borrowableCToken` asset that
    ///                           will be repaid to lenders.
    ///               swapAction Swap actions instructions converting
    ///                          collateral asset into debt asset to
    ///                          facilitate deleveraging.
    ///               auxData Optional auxiliary data for execution of a
    ///                       deleverage action.
    function onRedeem(
        address cToken,
        uint256 collateralAssets,
        address owner,
        DeleverageAction memory action
    ) external;
}

// contracts/libraries/SwapperLib.sol

/// @title Curvance Swapper Library.
/// @notice Helper Library for performing composable swaps with varying
///         degrees of slippage tolerance. "Unsafe" swaps perform a standard
///         slippage check whereas "safe" swaps not only check for standard
///         slippage but also check against the Oracle Manager's prices as
///         well.
///         NOTE: This library does not intend to provide support for fee on
///               transfer tokens though support may be built in the future.
library SwapperLib {
    /// TYPES ///

    /// @notice Instructions to execute a swap, selling `inputToken` for
    ///         `outputToken`.
    /// @param inputToken Address of input token to swap from.
    /// @param inputAmount The amount of `inputToken` to swap.
    /// @param outputToken Address of token to swap into.
    /// @param target Address of the swapper, usually an aggregator.
    /// @param slippage The amount of value-loss acceptable from swapping
    ///                 between tokens.
    /// @param call Swap instruction calldata.
    struct Swap {
        address inputToken;
        uint256 inputAmount;
        address outputToken;
        address target;
        uint256 slippage;
        bytes call;
    }

    /// @notice Address identifying a chain's native token.
    address public constant native =
        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// ERRORS ///

    error SwapperLib__UnknownCalldata();
    error SwapperLib__TokenPrice(address inputToken);
    error SwapperLib__Slippage(uint256 slippage);
    error SwapperLib__SameTokens();

    /// INTERNAL FUNCTIONS ///

    /// @notice Swaps `action.inputToken` into a `action.outputToken`
    ///         without an extra slippage check.
    /// @param cr The address of the Protocol Central Registry to pull
    ///           addresses from.
    /// @param action Instructions for a swap action containing:
    ///               inputToken Address of input token to swap from.
    ///               inputAmount The amount of `inputToken` to swap.
    ///               outputToken Address of token to swap into.
    ///               target Address of the swapper, usually an aggregator.
    ///               slippage The amount of value-loss acceptable from
    ///                        swapping between tokens.
    ///               call Swap instruction calldata.
    /// @return outAmount The output amount received from swapping.
    function _swapUnsafe(
        ICentralRegistry cr,
        Swap memory action
    ) internal returns (uint256 outAmount) {
        address outputToken = action.outputToken;
        address inputToken = action.inputToken;

        // Do not use this library if the tokens are the same.
        if (CommonLib._isMatchingToken(inputToken, outputToken)) {
            revert SwapperLib__SameTokens();
        }

        address callDataChecker = cr.externalCalldataChecker(action.target);

        // Validate we know how to verify this calldata.
        if (callDataChecker == address(0)) {
            revert SwapperLib__UnknownCalldata();
        }

        // Verify calldata integrity.
        IExternalCalldataChecker(callDataChecker)
            .checkCalldata(action, address(this));

        // Approve `action.inputToken` to target contract, if necessary.
        _approveIfNeeded(inputToken, action.target, action.inputAmount);

        // Cache output token from struct for easier querying.
        
        uint256 balanceBefore = CommonLib._balanceOf(outputToken);

        uint256 callValue = CommonLib._isNative(inputToken) ?
            action.inputAmount : 0;

        // Execute the swap.
        LowLevelCallsHelper._callWithNative(
            action.target,
            action.call,
            callValue
        );

        // Remove any excess approval.
        _removeApprovalIfNeeded(inputToken, action.target);

        outAmount = CommonLib._balanceOf(outputToken) - balanceBefore;
    }

    /// @notice Swaps `action.inputToken` into a `action.outputToken`
    ///         with an extra slippage check.
    /// @param cr The address of the Protocol Central Registry to pull
    ///           addresses from.
    /// @param action Instructions for a swap action containing:
    ///                   inputToken Address of input token to swap from.
    ///                   inputAmount The amount of `inputToken` to swap.
    ///                   outputToken Address of token to swap into.
    ///                   target Address of the swapper, usually an
    ///                          aggregator.
    ///                   slippage The amount of value-loss acceptable from
    ///                            swapping between tokens.
    ///                   call Swap instruction calldata.
    /// @return outAmount The output amount received from swapping.
    function _swapSafe(
        ICentralRegistry cr,
        Swap memory action
    ) internal returns (uint256 outAmount) {
        if (action.slippage >= WAD) {
            revert SwapperLib__Slippage(action.slippage);
        }

        outAmount = _swapUnsafe(cr, action);

        IOracleManager om = CommonLib._oracleManager(cr);
        uint256 valueIn = _getValue(om, action.inputToken, action.inputAmount);
        uint256 valueOut = _getValue(om, action.outputToken, outAmount);

        // Check if swap received positive slippage.
        if (valueOut > valueIn) {
            return outAmount;
        }

        // Calculate % slippage from executed swap.
        uint256 slippage = FixedPointMathLib.mulDivUp(
            valueIn - valueOut,
            WAD,
            valueIn
        );

        if (slippage > action.slippage) {
            revert SwapperLib__Slippage(slippage);
        }
    }

    /// @notice Get the value of a token amount.
    /// @notice Approves `token` spending allowance, if needed.
    /// @param om The Oracle Manager address to call for pricing `token`.
    /// @param token The token address to get the value of.
    /// @param amount The amount of `token` to get the value of.
    function _getValue(
        IOracleManager om,
        address token,
        uint256 amount
    ) internal view returns (uint256 result) {
        // If token is native, normalize to address(0) so it is compatible 
        // with the Oracle Manager.
        if (token == address(0)) {
            token = native;
        }
        
        (uint256 price, uint256 errorCode) = om.getPrice(token, true, true);
        if (errorCode != NO_ERROR) {
            revert SwapperLib__TokenPrice(token);
        }

        // Return price in WAD form.
        result = FixedPointMathLib.mulDiv(
            price,
            amount,
            10 ** (CommonLib._isNative(token) ? 18 : IERC20(token).decimals())
        );
    }

    /// @notice Approves `token` spending allowance, if needed.
    /// @param token The token address to approve.
    /// @param spender The spender address.
    /// @param amount The approval amount.
    function _approveIfNeeded(
        address token,
        address spender,
        uint256 amount
    ) internal {
        if (!CommonLib._isNative(token)) {
            SafeTransferLib.safeApprove(token, spender, amount);
        }
    }

    /// @notice Removes `token` spending allowance, if needed.
    /// @param token The token address to remove approval.
    /// @param spender The spender address.
    function _removeApprovalIfNeeded(address token, address spender) internal {
        if (!CommonLib._isNative(token)) {
            if (IERC20(token).allowance(address(this), spender) > 0) {
                SafeTransferLib.safeApprove(token, spender, 0);
            }
        }
    }
}

// contracts/oracles/OracleManager.sol

/// @title Curvance Dynamic Pessimistic Dual Oracle Manager.
/// @notice Provides a universal interface allowing contracts
///         to retrieve secure pricing data based on various price feeds.
/// @dev The Curvance Oracle Manager acts as a unified hub for pricing anything.
///      The Oracle Manager can support up to two oracle adaptors, returning
///      a maximum of two prices for any asset.
///
///      Prices can be returned in USD or a chain's native gas token.
///      Either the higher or lower of the two prices can returned, based on
///      what is desired. For Curvance protocol, the more advantageous of both
///      prices is used. For user collateralized assets, the lower of the two
///      prices is used. For user debt positions, the higher of the two prices
///      is used.
///
///      Curvance specific voucher tokens can also be priced by the Oracle
///      Router, based on the exchange rate between the voucher token, and
///      its underlying token.
///
///      The Oracle Manager also relays feedback based on any issues that
///      occurred during pricing an asset. This takes the form of three error
///      codes that are returned on querying a price or prices:
///      - An error code of 0 (NO_ERROR) corresponds to no error occurred
///        during pricing.
///      - An error code of 1 (CAUTION) corresponds to moderate issues
///        occurring during pricing, inside Curvance this results in new
///        borrowing, repayment, and redemption actions being blocked.
///      - An error code of 2 (BAD_SOURCE) corresponds to large issues
///        occurring during pricing, inside Curvance this results in new
///        borrowing, repayment, redemptions, and liquidation actions being
///        blocked.
///
///      "Circuit Breakers" have been introduced, that can be triggered based
///      on the prices returned to the Oracle Manager by adaptors. If prices
///      deviate heavily, error codes can be returned.
///      - An error code of 1 will be triggered by a deviation between pricing
///        adaptors of >= `cautionBound` for the corresponding asset.
///      - An error code of 2 will be triggered by a deviation between pricing
///        adaptors of >= `badSourceBound` for the corresponding asset.
///
///      Oracle Adaptors can be added or removed by the DAO which can change
///      how an asset is priced. This allows for continually improving the
///      data quality returned within the system. Oracle Adaptors handle
///      checks such as price staleness, decimal offsetting, and ecosystem
///      specific logic. All this is abstracted away from the Oracle Manager,
///      all data is returned in a standardized format of 18 decimals. Prices
///      must be positive (> 0). When PriceGuards are configured on an adaptor,
///      minimum and maximum prices are enforced via the guard's `minPrice`
///      (uint88) and `basePrice` (uint88) parameters respectively. When no
///      PriceGuard is configured, prices can range up to uint256.max with no
///      upper constraint beyond what the underlying oracle feed supports.
///      When using the Oracle Manager, verify what PriceGuard configurations
///      are active for the oracle adaptors to understand the effective
///      minimum/maximum price constraints.
///
///      Oracle Adaptors also can be used to introduce realtime information
///      based on offchain logic such as dynamic liquidation penalties.
///
///      The Oracle Manager was built to minimize Oracle trust by introducing
///      a decentralized model, many oracle providers all verified against
///      each other. "Don't trust, verify."
///
contract OracleManager is IOracleManager {
    /// TYPES ///

    /// @notice Storage structure for asset pricing configuration from various
    ///         oracle pricing adaptors.
    /// @param badSourceBoundUSD The bound value allowed between adaptor
    ///                          prices before `BAD_SOURCE` error code is
    ///                          returned, in `BPS`. An additional `BPS` is
    ///                          added to the value to save runtime gas costs
    ///                          during `_checkBounds` call. Used when pricing
    ///                          in USD denomination.
    /// @param cautionBoundUSD The bound value allowed between adaptor prices
    ///                        before `CAUTION` error code is returned, in
    ///                        `BPS`. An additional `BPS` is added to the
    ///                        value to save runtime gas costs during
    ///                        `_checkBounds` call. Used when pricing in USD
    ///                        denomination.
    /// @param badSourceBoundNative The bound value allowed between adaptor
    ///                             prices before `BAD_SOURCE` error code is
    ///                             returned, in `BPS`. An additional `BPS` is
    ///                             added to the value to save runtime gas
    ///                             costs during `_checkBounds` call. Used
    ///                             when pricing in native chain token
    ///                             denomination.
    /// @param cautionBoundNative The bound value allowed between adaptor
    ///                           prices before `CAUTION` error code is
    ///                           returned, in `BPS`. An additional `BPS`
    ///                           is added to the value to save runtime gas
    ///                           costs during `_checkBounds` call. Used when
    ///                           pricing in native chain token denomination.
    /// @dev 10050 = 0.5% = 50 basis point price feed deviation allowed.
    /// @param adaptors Array containing all pricing adaptors an asset is
    ///                 dependent on, maximum 2, 0 dependencies means the
    ///                 asset is not.
    struct PricingConfig {
        uint16 badSourceBoundUSD;
        uint16 cautionBoundUSD;
        uint16 badSourceBoundNative;
        uint16 cautionBoundNative;
        address[] adaptors;
    }

    /// CONSTANTS ///

    /// @notice Address identifying a chain's native token.
    address public constant native =
        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    /// @notice Time to pass before accepting answers when sequencer
    ///         comes back up, in seconds.
    uint256 public constant GRACE_PERIOD_TIME = 300;
    /// @notice Maximum value that a price deviation bound can be set as
    ///         inside the protocol, in `BPS`.
    /// @dev 300 = 3.0%, in `BPS`.
    uint256 public constant MAX_DEVIATION_BOUND = 350;
    /// @notice Minimum value that a price deviation bound can be set as
    ///         inside the protocol.
    /// @dev 20 = 0.2%.
    uint256 public constant MIN_DEVIATION_BOUND = 20;
    /// @notice The minimum buffer between `CAUTION` bound and `BAD_SOURCE`
    ///         bound when configuring bound values, in `BPS`.
    /// @dev 20 = 0.2% minimum buffer before `BAD_SOURCE` value can
    ///      be triggered.
    uint256 public constant MIN_CAUTION_TO_BAD_SOURCE_DELTA = 20;

    /// @notice Curvance DAO hub.
    ICentralRegistry public immutable centralRegistry;

    /// STORAGE ///

    /// @notice Whether an address is an approved Curvance price feed adaptor.
    /// @dev Adaptor address => Approved for usage.
    // Address => Adaptor approval status.
    mapping(address => bool) public isApprovedAdaptor;
    /// @notice Pricing configuration data for an asset.
    /// @dev Token address => Pricing configuration for `asset`.
    mapping(address => PricingConfig) public assetPricingConfig;
    // Address => Curvance token underlying asset address.
    mapping(address => address) public cTokens;

    /// EVENTS ///

    event AdaptorDependencyAdded(address asset, address adaptor);
    event AdaptorDependencyRemoved(address asset, address adaptor);
    event AssetDeviationBoundsSet(
        address asset,
        uint256 badSourceBoundUSD,
        uint256 cautionBoundUSD,
        uint256 badSourceBoundNative,
        uint256 cautionBoundNative
    );

    /// ERRORS ///

    error OracleManager__Unauthorized();
    error OracleManager__NotSupported();
    error OracleManager__InvalidParameter();
    error OracleManager__ErrorCodeFlagged();
    error OracleManager__AdaptorIsNotApproved();

    /// CONSTRUCTOR ///

    /// @param cr The address of the Protocol Central Registry.
    constructor(ICentralRegistry cr) {
        CentralRegistryLib._isCentralRegistry(cr);
        centralRegistry = cr;
    }

    /// EXTERNAL FUNCTIONS ///

    /// @notice Adds a new dependency for pricing `asset` on `adaptor`. If
    ///         this is the second adaptor dependency, set deviation values
    ///         too, validating they are safe based on price feed deviation.
    /// @dev Requires that `adaptor` is an approved adaptor, and that `asset`
    ///      does not already have two adaptor dependencies.
    ///      May emit an {AssetDeviationBoundsSet} event.
    /// @param asset The address of the asset to add a new pricing adaptor
    ///              dependency for.
    /// @param adaptor The address of the new adaptor to add dependency to.
    /// @param badSourceBoundUSD The new maximum price deviation before a
    ///                          `BAD_SOURCE` error code is returned for USD
    ///                          pricing, only used when adding a second
    ///                          adaptor dependency.
    /// @param cautionBoundUSD The new maximum price deviation before a
    ///                        `CAUTION` error code is returned for USD
    ///                        pricing, only used when adding a second
    ///                        adaptor dependency.
    /// @param badSourceBoundNative The new maximum price deviation before a
    ///                             `BAD_SOURCE` error code is returned for
    ///                             native pricing, only used when adding a
    ///                             second adaptor dependency.
    /// @param cautionBoundNative The new maximum price deviation before a
    ///                           `CAUTION` error code is returned for native
    ///                           pricing, only used when adding a second
    ///                           adaptor dependency.
    function addAssetPricingAdaptor(
        address asset,
        address adaptor,
        uint256 badSourceBoundUSD,
        uint256 cautionBoundUSD,
        uint256 badSourceBoundNative,
        uint256 cautionBoundNative
    ) external {
        _checkElevatedPermissions();
        _addAssetPricingAdaptor(asset, adaptor);

        // Pull `asset` pricing config data after the new adaptor has been
        // added.
        PricingConfig storage config = assetPricingConfig[asset];

        // If there are not two adaptor dependencies we can skip this logic.
        if (config.adaptors.length > 1) {
            _setDeviationBounds(
                asset,
                config,
                badSourceBoundUSD,
                cautionBoundUSD,
                badSourceBoundNative,
                cautionBoundNative
            );
        }
    }

    /// @notice Replaces the dependency on pricing from `adaptorToRemove` for
    ///         `asset` in favor of adding dependency on pricing to
    ///         `adaptorToAdd`.
    /// @dev Requires that `adaptorToAdd` is an approved adaptor, and that
    ///      `asset` currently has at least one adaptor configured. Which
    ///      should include `adaptorToRemove`.
    ///      May emit an {AssetDeviationBoundsSet} event.
    /// @param asset The address of the asset to adjust pricing adaptors for.
    /// @param adaptorToRemove The address of the adaptor to remove dependency
    ///                        from.
    /// @param adaptorToAdd The address of the new adaptor to add dependency
    ///                     to.
    /// @param badSourceBoundUSD The new maximum price deviation before a
    ///                          `BAD_SOURCE` error code is returned for USD
    ///                          pricing, only used when replacing a second
    ///                          adaptor dependency.
    /// @param cautionBoundUSD The new maximum price deviation before a
    ///                        `CAUTION` error code is returned for USD
    ///                        pricing, only used when replacing a second
    ///                        adaptor dependency.
    /// @param badSourceBoundNative The new maximum price deviation before a
    ///                             `BAD_SOURCE` error code is returned for
    ///                             native pricing, only used when replacing a
    ///                             second adaptor dependency.
    /// @param cautionBoundNative The new maximum price deviation before a
    ///                           `CAUTION` error code is returned for native
    ///                           pricing, only used when replacing a second
    ///                           adaptor dependency.
    function replaceAssetPricingAdaptor(
        address asset,
        address adaptorToRemove,
        address adaptorToAdd,
        uint256 badSourceBoundUSD,
        uint256 cautionBoundUSD,
        uint256 badSourceBoundNative,
        uint256 cautionBoundNative
    ) external {
        _checkElevatedPermissions();

        // Validate that the feeds are not identical as there would be no
        // point to replace a feed with itself.
        if (adaptorToRemove == adaptorToAdd) {
            revert OracleManager__InvalidParameter();
        }

        _removeAssetPricingAdaptor(asset, adaptorToRemove);
        _addAssetPricingAdaptor(asset, adaptorToAdd);

        // Pull `asset` pricing config data after the new adaptor has been
        // added.
        PricingConfig storage config = assetPricingConfig[asset];

        // If there are not two adaptor dependencies we can skip this logic.
        if (config.adaptors.length > 1) {
            _setDeviationBounds(
                asset,
                config,
                badSourceBoundUSD,
                cautionBoundUSD,
                badSourceBoundNative,
                cautionBoundNative
            );
        }
    }

    /// @notice Removes the dependency on pricing from `adaptor` for `asset`.
    /// @dev Requires that `adaptor` is currently being used for pricing
    ///      `asset`.
    ///      NOTE: This intentionally does not modify asset deviation values
    ///            because they simply wont be used if there are less than two
    ///            pricing adaptors in use, so no reason to delete data as
    ///            when a second pricing adaptor is configured the deviation
    ///            has the opportunity be to reconfigured anyway.
    /// @param asset The address of the asset to remove pricing adaptor
    ///              dependency from.
    /// @param adaptor The address of the adaptor to remove dependency from.
    function removeAssetPricingAdaptor(address asset, address adaptor) external {
        _checkElevatedPermissions();
        _removeAssetPricingAdaptor(asset, adaptor);
    }

    /// @notice Potentially removes the dependency on pricing from `adaptor`
    ///         for `asset`, triggered by an adaptor's notification of a price
    ///         feed's removal.
    /// @notice Removes a pricing adaptor for `asset` triggered by an
    ///         adaptor's notification of a price feed's removal.
    /// @dev Requires that the adaptor is currently being used for pricing
    ///      for `asset`.
    ///      NOTE: This intentionally does not modify deviation bound values
    ///            because they simply wont be used if there are less than two
    ///            pricing adaptors in use, so no reason to delete data as
    ///            when a second pricing adaptor is configured the deviation
    ///            has the opportunity be to reconfigured anyway.
    /// @param asset The address of the asset to potentially remove the
    ///              pricing adaptor dependency from depending on current
    ///              `asset` configuration.
    function notifyFeedRemoval(address asset) external {
        if (!isApprovedAdaptor[msg.sender]) {
            return;
        }

        address[] memory adaptors = assetPricingConfig[asset].adaptors;
        uint256 numAdaptors = adaptors.length;

        // Validate calling adaptor is a currently supported used for `asset`.
        // If unused can return immediately.
        if (numAdaptors > 1) {
            if (adaptors[0] != msg.sender && adaptors[1] != msg.sender) {
                return;
            }
        } else {
            if (numAdaptors == 0) {
                return;
            }

            if (adaptors[0] != msg.sender) {
                return;
            }
        }
        _removeAssetPricingAdaptor(asset, msg.sender);
    }

    /// @notice Returns the adaptors used for pricing `asset`.
    /// @param asset The address of the asset to get pricing adaptors for.
    /// @return result The current adaptor(s) used for pricing `asset`.
    function getPricingAdaptors(
        address asset
    ) external view returns(address[] memory result) {
        result = assetPricingConfig[asset].adaptors;
    }

    /// @notice Adds a new Curvance token to the Oracle Manager.
    /// @dev Requires that `newCToken` is not already supported.
    ///      The cToken's underlying CANNOT be equal to address(0).
    /// @param newCToken The address of the Curvance token to support.
    function addCTokenSupport(address newCToken) external {
        _checkElevatedPermissions();

        // We call a Curvance-specific token function as a sanity check.
        ICToken(newCToken).isBorrowable();

        // Validate `newCToken` has not already been registered as a cToken,
        // and that `newUnderlying` is not address(0) as that is how we check
        // whether a token is a cToken or not.
        address newUnderlying = ICToken(newCToken).asset();
        if (cTokens[newCToken] != address(0) || newUnderlying == address(0)) {
            revert OracleManager__InvalidParameter();
        }

        cTokens[newCToken]= newUnderlying;
    }

    /// @notice Removes a Curvance token's support in the Oracle Manager.
    /// @dev Requires that the Curvance token is supported.
    /// @param cTokenToRemove The address of the Curvance token to remove
    ///                       support for.
    function removeCTokenSupport(address cTokenToRemove) external {
        _checkElevatedPermissions();

        // Validate `newCToken` has already been registered as a cToken.
        if (cTokens[cTokenToRemove] == address(0)) {
            revert OracleManager__InvalidParameter();
        }

        delete cTokens[cTokenToRemove];
    }

    /// @notice Removes adaptor approval for `adaptorToRemove`, then,
    ///         adds adaptor approval for `adaptorToAdd`.
    /// @dev Requires that the adaptor isn't already approved.
    /// @param adaptorToRemove The address of the adaptor to remove approval.
    /// @param adaptorToAdd The address of the adaptor to approve.
    function replaceApprovedAdaptor(
        address adaptorToRemove,
        address adaptorToAdd
    ) external {
        _checkElevatedPermissions();

        // Validate `adaptorToAdd` is not already supported.
        if (isApprovedAdaptor[adaptorToAdd]) {
            revert OracleManager__InvalidParameter();
        }

        // Validate `adaptorToRemove` is currently supported.
        _checkIsApprovedAdaptor(adaptorToRemove);

        delete isApprovedAdaptor[adaptorToRemove];
        isApprovedAdaptor[adaptorToAdd] = true;
    }

    /// @notice Adds `newAdaptor` as an approved adaptor.
    /// @dev Requires that the adaptor isn't already approved.
    /// @param adaptorToAdd The address of the adaptor to approve.
    function addApprovedAdaptor(address adaptorToAdd) external {
        _checkElevatedPermissions();

        // Validate `adaptorToAdd` is not already supported.
        if (isApprovedAdaptor[adaptorToAdd]) {
            revert OracleManager__InvalidParameter();
        }

        isApprovedAdaptor[adaptorToAdd] = true;
    }

    /// @notice Removes `adaptorToRemove` as an approved adaptor.
    /// @dev Requires that the adaptor is currently approved.
    /// @param adaptorToRemove The address of the adaptor to remove.
    function removeApprovedAdaptor(address adaptorToRemove) external {
        _checkElevatedPermissions();
        // Validate `adaptorToRemove` is currently supported.
        _checkIsApprovedAdaptor(adaptorToRemove);

        delete isApprovedAdaptor[adaptorToRemove];
    }

    /// @notice Sets new maximum deviation bound values for pricing adaptors
    ///         before `CAUTION` or `BAD_SOURCE` error codes are activated
    ///         for `asset`.
    /// @dev Only allowed if there are two adaptor dependencies configured
    ///      already. Emits an {AssetDeviationBoundsSet} event.
    /// @param asset The address of the asset to set pricing deviation bound
    ///              values for.
    /// @param badSourceBoundUSD The new maximum price deviation before a
    ///                          `BAD_SOURCE` error code is returned for USD
    ///                          pricing.
    /// @param cautionBoundUSD The new maximum price deviation before a
    ///                        `CAUTION` error code is returned for USD
    ///                        pricing.
    /// @param badSourceBoundNative The new maximum price deviation before a
    ///                             `BAD_SOURCE` error code is returned for
    ///                             native pricing.
    /// @param cautionBoundNative The new maximum price deviation before a
    ///                           `CAUTION` error code is returned for native
    ///                           pricing.
    function setDeviationBounds(
        address asset,
        uint256 badSourceBoundUSD,
        uint256 cautionBoundUSD,
        uint256 badSourceBoundNative,
        uint256 cautionBoundNative
    ) external {
        _checkElevatedPermissions();
        PricingConfig storage config = assetPricingConfig[asset];

        // If there are not two adaptor dependencies we can skip this logic.
        if (config.adaptors.length < 2) {
            revert OracleManager__InvalidParameter();
        }

        _setDeviationBounds(
            asset,
            config,
            badSourceBoundUSD,
            cautionBoundUSD,
            badSourceBoundNative,
            cautionBoundNative
        );
    }

    /// @notice Checks if a given asset is supported by the Oracle Manager.
    /// @dev An asset is considered supported if it has one
    ///      or more associated price feeds.
    /// @param asset The address of the asset to check.
    /// @return True if the asset is supported, false otherwise.
    function isSupportedAsset(address asset) external view returns (bool) {
        address cTokenUnderlying = cTokens[asset];
        if (cTokenUnderlying != address(0)) {
            return assetPricingConfig[cTokenUnderlying].adaptors.length > 0;
        }

        return assetPricingConfig[asset].adaptors.length > 0;
    }

    /// @notice Check whether L2 sequencer is valid or down.
    /// @dev Uses Chainlink sequencer check if available, regardless of
    ///      linked oracle adaptor.
    /// @return True if sequencer is valid.
    function isSequencerValid() external view returns (bool) {
        return _isSequencerValid();
    }

    /// PUBLIC FUNCTIONS ///

    /// @notice Retrieves the price of a specified asset from either single
    ///         or dual oracles.
    /// @dev If the asset has one oracle, it fetches the price from a single
    ///      feed. If it has two or more oracles, it fetches the price from both
    ///      feeds. Additionally, also checks Chainlink L2 sequencer via
    ///      `_isSequencerValid()`
    ///      and returns `(0, BAD_SOURCE)` if down, even for non-Chainlink
    ///      adaptors. This is by design.
    /// @param asset The address of the asset to retrieve the price for.
    /// @param inUSD Specifies whether the price format should be in
    ///              USD (true) or a chain's native token (false).
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if two feeds are available.
    /// @return price The current price of `asset`.
    /// @return errorCode An error code related to fetching the price:
    ///                   '0' indicates no error fetching price.
    ///                   '1' indicates that price should be taken with
    ///                   caution.
    ///                   '2' indicates a complete failure in receiving
    ///                   a price.
    function getPrice(
        address asset,
        bool inUSD,
        bool getLower
    ) public view returns (uint256 price, uint256 errorCode) {
        if (!_isSequencerValid()) {
            return (0, BAD_SOURCE);
        }

        address cToken;
        address cTokenUnderlying = cTokens[asset];
        // Check whether `asset` is Curvance token.
        if (cTokenUnderlying != address(0)) {
            cToken = asset;
            asset = cTokenUnderlying;
        }

        (price, errorCode) = _getPrice(asset, inUSD, getLower);

        // Query the exchange rate between a Curvance token and its underlying
        // token and convert the price into WAD form.
        if (cToken != address(0)) {
            if (getLower) {
                price = FixedPointMathLib.mulDiv(
                    price,
                    ICToken(cToken).exchangeRate(),
                    WAD
                );
            } else {
                price = FixedPointMathLib.mulDivUp(
                    price,
                    ICToken(cToken).exchangeRate(),
                    WAD
                );
            }
        }

        // If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
        // flag is bubbled up.
        if (price == 0 && errorCode < BAD_SOURCE) {
            errorCode = BAD_SOURCE;
        }
    }

    /// @notice Retrieves the prices of a collateral token, and debt token
    ///         underlying.
    /// @param collateralToken The cToken currently collateralized to price.
    /// @param debtToken The borrowableCToken borrowed from to price
    ///                  underlying of.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return collateralSharesPrice The current price of `collateralToken`.
    /// @return debtUnderlyingPrice The current price of `debtToken`
    ///                             underlying.
    function getPriceIsolatedPair(
        address collateralToken,
        address debtToken,
        uint256 errorCodeBreakpoint
    ) external returns (
        uint256 collateralSharesPrice,
        uint256 debtUnderlyingPrice
    ) {
        if (!_isSequencerValid()) {
            revert OracleManager__ErrorCodeFlagged();
        }

        uint256 errorCode;
        address underlying = cTokens[collateralToken];
        if (underlying == address(0)) {
            revert OracleManager__NotSupported();
        }

        (collateralSharesPrice, errorCode) = _getPrice(
            underlying,
            true,
            true
        );

        collateralSharesPrice = FixedPointMathLib.mulDiv(
            collateralSharesPrice,
            ICToken(collateralToken).exchangeRateUpdated(),
            WAD
        );

        // If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
        // flag is bubbled up.
        if (collateralSharesPrice == 0 && errorCode < BAD_SOURCE) {
            errorCode = BAD_SOURCE;
        }

        if (errorCode >= errorCodeBreakpoint) {
            revert OracleManager__ErrorCodeFlagged();
        }

        underlying = cTokens[debtToken];
        if (underlying == address(0)) {
            revert OracleManager__NotSupported();
        }

        (debtUnderlyingPrice, errorCode) = _getPrice(
            underlying,
            true,
            false
        );

        // If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
        // flag is bubbled up.
        if (debtUnderlyingPrice == 0 && errorCode < BAD_SOURCE) {
            errorCode = BAD_SOURCE;
        }

        if (errorCode >= errorCodeBreakpoint) {
            revert OracleManager__ErrorCodeFlagged();
        }
    }

    /// @notice Retrieves the prices and account data of multiple assets
    ///         inside a Curvance Market.
    /// @dev If the asset is being used as collateral the users liquidity is
    ///      priced in shares, if theyre borrowing the outstanding debt is
    ///      measured in assets (underlying).
    /// @param account The account to retrieve data for.
    /// @param assets An array of asset addresses to retrieve the prices for.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return AccountSnapshot[] Contains `assets` data for `account`
    /// @return uint256[] Contains prices for `assets`.
    /// @return uint256 The number of assets `account` is in.
    function getPricesForMarket(
        address account,
        address[] calldata assets,
        uint256 errorCodeBreakpoint
    ) external returns (
        AccountSnapshot[] memory,
        uint256[] memory,
        uint256
    ) {
        if (!_isSequencerValid()) {
            revert OracleManager__ErrorCodeFlagged();
        }

        uint256 numAssets = assets.length;
        AccountSnapshot[] memory snapshots = new AccountSnapshot[](numAssets);
        uint256[] memory prices = new uint256[](numAssets);
        uint256 errorCode;

        address asset;
        for (uint256 i; i < numAssets; ++i) {
            asset = assets[i];
            snapshots[i] = ICToken(asset).getSnapshotUpdated(account);

            if (snapshots[i].isCollateral) {
                // If the asset is being used as collateral the users liquidity is
                // priced in shares using _getPrice multiplied by exchange rate.
                (prices[i], errorCode) = _getPrice(
                    snapshots[i].underlying,
                    true,
                    true
                );
                // `getSnapshotUpdated` already accrues any pending assets so
                // we can call `exchangeRate` directly.
                prices[i] = FixedPointMathLib.mulDiv(
                    prices[i],
                    ICToken(asset).exchangeRate(),
                    WAD
                );
            } else {
                // If the asset is being borrowed the outstanding debt is
                // measured in assets (underlying) using _getPrice.
                (prices[i], errorCode) = _getPrice(
                    snapshots[i].underlying,
                    true,
                    false
                );
            }

            // If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
            // flag is bubbled up.
            if (prices[i] == 0 && errorCode < BAD_SOURCE) {
                errorCode = BAD_SOURCE;
            }

            if (errorCode >= errorCodeBreakpoint) {
                revert OracleManager__ErrorCodeFlagged();
            }
        }

        return (snapshots, prices, numAssets);
    }

    /// INTERNAL FUNCTIONS ///

    /// @notice Retrieves the price of a specified asset from either single
    ///         or dual oracles.
    /// @dev If the asset has one oracle, it fetches the price from a single
    ///      feed.
    ///      If it has two or more oracles, it fetches the price from both
    ///      feeds.
    /// @param asset The address of the asset to retrieve the price for.
    /// @param inUSD Specifies whether the price format should be in
    ///              USD (true) or a chain's native token (false).
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if two feeds are available.
    /// @return price The current price of `asset`.
    /// @return errorCode An error code related to fetching the price:
    ///                   '0' indicates no error fetching price.
    ///                   '1' indicates that price should be taken with
    ///                   caution.
    ///                   '2' indicates a complete failure in receiving
    ///                   a price.
    function _getPrice(
        address asset,
        bool inUSD,
        bool getLower
    ) internal view returns (uint256 price, uint256 errorCode) {
        if (asset == address(0)) {
            revert OracleManager__NotSupported();
        }

        PricingConfig memory config = assetPricingConfig[asset];
        uint256 numAdaptors = config.adaptors.length;
        if (numAdaptors == 0) {
            revert OracleManager__NotSupported();
        }

        // Get price from a single adaptor source or dual adaptor source.
        if (numAdaptors > 1) {
            (price, errorCode) =
                _getPriceDualAdaptor(asset, config, inUSD, getLower);
        } else {
            bool hadError;
            (price, hadError) =
                _getPriceFromAdaptor(asset, config.adaptors[0], inUSD, getLower);
            if (hadError) {
                errorCode = BAD_SOURCE;
            }
        }
    }

    /// @notice Adds a new dependency for pricing `asset` on `adaptor`. If
    ///         this is the second adaptor dependency, set deviation values
    ///         too, validating they are safe based on adaptor's price feed
    ///         deviation threshold.
    /// @dev Requires that `adaptor` is an approved adaptor, and that `asset`
    ///      does not already have two adaptor dependencies.
    /// @param asset The address of the asset to add a new pricing adaptor
    ///              dependency for.
    /// @param adaptor The address of the new adaptor to add dependency to.
    function _addAssetPricingAdaptor(address asset, address adaptor) internal {
        // Validate that `adaptor` is approved for pricing usage.
        _checkIsApprovedAdaptor(adaptor);

        // Validate that the adaptor supports pricing `asset`.
        if (!IOracleAdaptor(adaptor).isSupportedAsset(asset)) {
            revert OracleManager__InvalidParameter();
        }

        address[] storage adaptors = assetPricingConfig[asset].adaptors;
        uint256 numAdaptors = adaptors.length;

        // Validate that we do not already have 2 pricing adaptors configured
        // for `asset`.
        if (numAdaptors > 1) {
            revert OracleManager__InvalidParameter();
        }

        // If there is already an adaptor dependency for `asset` make sure
        // that it is not `adaptor`, which would duplicate the dependency.
        // Validate that the adaptor proposed is not a duplicate of the
        // current adaptor of a supported feed for `asset`.
        if (numAdaptors != 0 && adaptors[0] == adaptor) {
            revert OracleManager__InvalidParameter();
        }

        // Validate that the adaptor returns an acceptable price for `asset`
        // by sampling a price call with `getLower` = true.
        IOracleAdaptor.PricingResult memory result = IOracleAdaptor(adaptor)
            .getPrice(asset, true, true);

        if (result.price == 0 || result.hadError) {
            revert OracleManager__InvalidParameter();
        }

        // Validate that the adaptor returns an acceptable price for `asset`
        // by sampling a price call with `getLower` = false.
        result = IOracleAdaptor(adaptor).getPrice(asset, true, false);

        if (result.price == 0 || result.hadError) {
            revert OracleManager__InvalidParameter();
        }

        adaptors.push(adaptor);
        emit AdaptorDependencyAdded(asset, adaptor);
    }

    /// @notice Removes the dependency on pricing from `adaptor` for `asset`.
    /// @dev Requires that `adaptor` is currently being used for pricing
    ///      `asset`.
    ///      NOTE: This intentionally does not modify asset deviation values
    ///            because they simply wont be used if there are less than two
    ///            pricing adaptors in use, so no reason to delete data as
    ///            when a second pricing adaptor is configured the deviation
    ///            has the opportunity be to reconfigured anyway.
    /// @param asset The address of the asset to remove pricing adaptor
    ///              dependency from.
    /// @param adaptor The address of the adaptor to remove dependency from.
    function _removeAssetPricingAdaptor(
        address asset,
        address adaptor
    ) internal {
        // If theres two adaptor dependencies, figure out which to remove,
        // otherwise we know the adaptor to remove is the first entry.
        address[] storage adaptors = assetPricingConfig[asset].adaptors;
        uint256 numAdaptors = adaptors.length;
        if (numAdaptors == 0) {
            revert OracleManager__NotSupported();
        }

        if (numAdaptors > 1) {
            // Check whether `adaptor` is a currently dependency for pricing
            // `asset`.
            if (adaptors[0] != adaptor && adaptors[1] != adaptor) {
                revert OracleManager__NotSupported();
            }

            // We want to remove the first adaptor dependency of the two,
            // so move the second adaptor dependency to slot one.
            if (adaptors[0] == adaptor) {
                adaptors[0] = adaptors[1];
            }
        } else {
            if (adaptors[0] != adaptor) {
                revert OracleManager__NotSupported();
            }
        }
        // We know the adaptor exists, but we cannot use `isApprovedAdaptor`
        // as we could have removed it as an approved adaptor prior to this
        // function call.
        adaptors.pop();
        emit AdaptorDependencyRemoved(asset, adaptor);
    }

    /// @notice Retrieves the price of a specified asset from two specific
    ///         price feeds.
    /// @dev If both price feeds return an error, it returns (0, BAD_SOURCE).
    ///      If one of the price feeds return an error, it returns the
    ///      price from the working feed along with a CAUTION flag.
    ///      Otherwise, it returns (price, NO_ERROR).
    /// @param asset The address of the asset to retrieve the price for.
    /// @param config The current pricing configuration of `asset`.
    /// @param inUSD Specifies whether the price format should be in
    ///              USD (true) or a chain's native token (false).
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if two feeds are available.
    /// @return uint256 The current price of `asset`.
    /// @return bool An error flag (if any).
    function _getPriceDualAdaptor(
        address asset,
        PricingConfig memory config,
        bool inUSD,
        bool getLower
    ) internal view returns (uint256, uint256) {
        (uint256 price0, bool error0) = _getPriceFromAdaptor(
            asset, config.adaptors[0], inUSD, getLower
        );
        (uint256 price1, bool error1)= _getPriceFromAdaptor(
            asset, config.adaptors[1], inUSD, getLower
        );

        // Check if we had any working price feeds,
        // if not we need to block any market operations.
        if (error0 && error1){
            return (0, BAD_SOURCE);
        }
        // Check if we had an error in either price that should block
        // borrowing/redemption.
        if (error0 || error1) {
            // We know based on context of when this if statement block is
            // called that one but not both adaptors have an error. So, if
            // adaptor0 had the error, adaptor1 is usable, and vice versa.
            if (error0) {
                return (price1, CAUTION);
            }

            return (price0, CAUTION);
        }

        uint256 badSourceBound = inUSD ?
            config.badSourceBoundUSD : config.badSourceBoundNative;
        uint256 cautionBound = inUSD ?
            config.cautionBoundUSD : config.cautionBoundNative;

        uint256 errorCode =
            _checkBounds(price0, price1, badSourceBound, cautionBound);
        if (getLower) {
            return (price1 < price0 ? price1 : price0, errorCode);
        }

        return (price1 > price0 ? price1 : price0, errorCode);
    }

    /// @notice Retrieves the price of `asset` from `adaptor`.
    /// @dev Converts the price received to `inUSD` if necessary.
    /// @param asset The address of the asset to retrieve the price for.
    /// @param adaptor The address of the pricing adaptor to use for pricing
    ///                `asset`.
    /// @param inUSD Specifies whether the price format should be in
    ///              USD (true) or a chain's native token (false).
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if there are two adaptor dependencies.
    /// @return uint256 The current price of `asset`.
    /// @return bool Whether the adaptor ran into an error when pricing.
    function _getPriceFromAdaptor(
        address asset,
        address adaptor,
        bool inUSD,
        bool getLower
    ) internal view returns (uint256, bool) {
        _checkIsApprovedAdaptor(adaptor);

        IOracleAdaptor.PricingResult memory result = IOracleAdaptor(adaptor)
            .getPrice(asset, inUSD, getLower);

        // If we had an error pricing the asset, bubble up we had a error.
        if (result.hadError) {
            return (0, true);
        }

        // If the adaptor's price denomination is not in the proper form,
        // modify it.
        if (result.inUSD != inUSD) {
            uint256 newPrice;
            (newPrice, result.hadError) =
                _getNativeUSD(inUSD ? getLower : !getLower);
            if (result.hadError) {
                return (0, true);
            }

            return (
                _convertNativeUSD(result.price, newPrice, result.inUSD, getLower),
                result.hadError
            );
        }

        return (result.price, result.hadError);
    }

    /// @notice Queries the current price of a chain's native token in USD
    ///         using the Oracle Manager.
    /// @dev The price is deemed valid if the data from the Oracle Manager
    ///      is fresh and a positive value.
    /// @param getLower Whether the lower or higher price should be returned
    ///                 if there are two adaptor dependencies.
    /// @return price The current price of `native`.
    /// @return hadError Whether the adaptor ran into an error when pricing
    ///                  `native`.
    function _getNativeUSD(
        bool getLower
    ) internal view returns (uint256 price, bool hadError) {
        uint256 errorCode;
        (price, errorCode) = _getPrice(native, true, getLower);

        // If somehow an adaptor returns a price of 0, make sure a BAD_SOURCE
        // flag is bubbled up.
        if (price == 0 && errorCode < BAD_SOURCE) {
            errorCode = BAD_SOURCE;
        }

        // If there was any error while querying native token price,
        // bubble up an error.
        hadError = errorCode != NO_ERROR;
    }

    /// @notice Check whether a sequencer is valid or down.
    /// @return True if sequencer is valid.
    function _isSequencerValid() internal view returns (bool) {
        address sequencerUptimeFeed = centralRegistry.SEQUENCER_ORACLE();

        if (sequencerUptimeFeed != address(0)) {
            (, int256 answer, uint256 startedAt, , ) =
                IChainlink(sequencerUptimeFeed).latestRoundData();

            // Answer == 0: Sequencer is up.
            // Check that the sequencer is up or the grace period has passed
            // after the sequencer is back up.
            if (startedAt == 0) {
                return false;
            }

            uint256 timeSinceUp = block.timestamp - startedAt;
            if (answer != 0 || timeSinceUp <= GRACE_PERIOD_TIME) {
                return false;
            }
        }

        return true;
    }

    /// @notice Converts a given price between a chain's native token
    ///         and USD.
    /// @dev Depending on the currentFormatInUSD parameter,
    ///      this function either converts the price from native token
    ///      to USD (if true) or from USD to native (if false) using the
    ///      provided conversion rate.
    /// @param currentPrice The price to convert.
    /// @param conversionRate The rate to use for the conversion.
    /// @param currentlyInUSD Specifies whether the current format of the
    ///                       price is in USD.
    ///                       If true -> Convert the price from USD to
    ///                       native token.
    ///                       If false -> Convert the price from native token
    ///                       to USD.
    /// @param getLower Whether the lower or higher price should be returned.
    /// @return The converted price.
    function _convertNativeUSD(
        uint256 currentPrice,
        uint256 conversionRate,
        bool currentlyInUSD,
        bool getLower
    ) internal pure returns (uint256) {
        if (!currentlyInUSD) {
            // The price denomination is in native token and we want USD.
            if (getLower) {
                return FixedPointMathLib.mulDiv(currentPrice, conversionRate, WAD);
            }

            return FixedPointMathLib.mulDivUp(currentPrice, conversionRate, WAD);
        }

        // The price denomination is in USD and we want native token.
        if (getLower) {
            return FixedPointMathLib.mulDiv(currentPrice, WAD, conversionRate);
        }
        
        return FixedPointMathLib.mulDivUp(currentPrice, WAD, conversionRate);
    }

    /// @notice Sets a new maximum deviation for pricing adaptors before
    ///         CAUTION or BAD_SOURCE error codes are activated for `asset`.
    /// @dev Only allowed if there are two adaptor dependencies configured
    ///      already.
    /// @param asset The address of the asset to set pricing deviation values
    ///              for.
    /// @param badSourceBoundUSD The new maximum price deviation before a
    ///                          `BAD_SOURCE` error code is returned for USD
    ///                          pricing.
    /// @param cautionBoundUSD The new maximum price deviation before a
    ///                        `CAUTION` error code is returned for USD
    ///                        pricing.
    /// @param badSourceBoundNative The new maximum price deviation before a
    ///                             `BAD_SOURCE` error code is returned for
    ///                             native pricing.
    /// @param cautionBoundNative The new maximum price deviation before a
    ///                           `CAUTION` error code is returned for native
    ///                           pricing.
    function _setDeviationBounds(
        address asset,
        PricingConfig storage config,
        uint256 badSourceBoundUSD,
        uint256 cautionBoundUSD,
        uint256 badSourceBoundNative,
        uint256 cautionBoundNative
    ) internal {
        // Validate that the `CAUTION` error code will not trigger too
        // closely to `BAD_SOURCE` error code for USD bounds.
        if (badSourceBoundUSD < cautionBoundUSD + MIN_CAUTION_TO_BAD_SOURCE_DELTA) {
            revert OracleManager__InvalidParameter();
        }

        // Validate that the `CAUTION` error code will not trigger too
        // closely to `BAD_SOURCE` error code for native bounds.
        if (badSourceBoundNative < cautionBoundNative + MIN_CAUTION_TO_BAD_SOURCE_DELTA) {
            revert OracleManager__InvalidParameter();
        }

        // Validate USD bound values are within acceptable value range.
        if (
            cautionBoundUSD < MIN_DEVIATION_BOUND ||
            badSourceBoundUSD > MAX_DEVIATION_BOUND
        ) {
            revert OracleManager__InvalidParameter();
        }

        // Validate native bound values are within acceptable value range.
        if (
            cautionBoundNative < MIN_DEVIATION_BOUND ||
            badSourceBoundNative > MAX_DEVIATION_BOUND
        ) {
            revert OracleManager__InvalidParameter();
        }

        // Add `BPS` to the value to save converting to a BPS premium
        // e.g. 10200 for 2% at runtime.
        config.badSourceBoundUSD = uint16(badSourceBoundUSD + BPS);
        config.cautionBoundUSD = uint16(cautionBoundUSD + BPS);
        config.badSourceBoundNative = uint16(badSourceBoundNative + BPS);
        config.cautionBoundNative = uint16(cautionBoundNative + BPS);

        emit AssetDeviationBoundsSet(asset, badSourceBoundUSD, cautionBoundUSD, badSourceBoundNative, cautionBoundNative);
    }

    /// @notice Reviews the report prices from both pricing adaptors,
    ///         returning an appropriate error code if the deviation between
    ///         prices is significant enough.
    /// @dev If the deviation is less than `cautionBound`, returns `NO_ERROR`.
    ///      If the deviation is more than `cautionBound` but less than
    ///      `badSourceBound`, returns `CAUTION`.
    ///      If the deviation is more than `badSourceBound`, returns
    ///      `BAD_SOURCE`.
    /// @param a The price reported by the first adaptor.
    /// @param b The price reported by the second adaptor.
    /// @param badSourceBound The bound value where deviation in price
    ///                       between `a` and `b` should return the
    ///                       `BAD_SOURCE` error code.
    /// @param cautionBound The bound value where deviation in price between
    ///                     `a` and `b` should return the `CAUTION` error
    ///                     code.
    /// @return Returns the appropriate error code depending on deviation
    ///         between adaptor's reported prices.
    function _checkBounds(
        uint256 a,
        uint256 b,
        uint256 badSourceBound,
        uint256 cautionBound
    ) internal pure returns (uint256) {
        if (a <= b) {
            // Check if both adaptor are within `cautionBound` of each other.
            if (((a * cautionBound) / BPS) < b) {
                // Notify that the price is dangerous and to treat data as
                // invalid because we are outside the accepted range of
                // deviation.
                if (((a * badSourceBound) / BPS) < b) {
                    return BAD_SOURCE;
                }

                // Notify that the price should be taken with caution because
                // we are outside the accepted range of deviation.
                return CAUTION;
            }

            return NO_ERROR;
        }

        // Check if both feeds are within `cautionBound` of each other.
        if (((b * cautionBound) / BPS) < a) {
            // Notify that the price is dangerous and to treat data as invalid
            // because we are outside the accepted range of deviation.
            if (((b * badSourceBound) / BPS) < a) {
                return BAD_SOURCE;
            }

            // Notify that the price should be taken with caution because
            // we are outside the accepted range of deviation.
            return CAUTION;
        }

        return NO_ERROR;
    }

    /// @notice Checks whether `adaptor` is an approved adaptor or not.
    ///         Reverts if `adaptor` is not approved.
    /// @param adaptor The address of the adaptor to check.
    function _checkIsApprovedAdaptor(address adaptor) internal view {
        if (!isApprovedAdaptor[adaptor]) {
            revert OracleManager__AdaptorIsNotApproved();
        }
    }

    /// @dev Checks whether the caller has sufficient permissioning.
    function _checkElevatedPermissions() internal view {
        if (!centralRegistry.hasElevatedPermissions(msg.sender)) {
            revert OracleManager__Unauthorized();
        }
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"OracleManager__AdaptorIsNotApproved","type":"error"},{"inputs":[],"name":"OracleManager__ErrorCodeFlagged","type":"error"},{"inputs":[],"name":"OracleManager__InvalidParameter","type":"error"},{"inputs":[],"name":"OracleManager__NotSupported","type":"error"},{"inputs":[],"name":"OracleManager__Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"adaptor","type":"address"}],"name":"AdaptorDependencyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"address","name":"adaptor","type":"address"}],"name":"AdaptorDependencyRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"AssetDeviationBoundsSet","type":"event"},{"inputs":[],"name":"GRACE_PERIOD_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DEVIATION_BOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CAUTION_TO_BAD_SOURCE_DELTA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEVIATION_BOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adaptorToAdd","type":"address"}],"name":"addApprovedAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"adaptor","type":"address"},{"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"addAssetPricingAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCToken","type":"address"}],"name":"addCTokenSupport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetPricingConfig","outputs":[{"internalType":"uint16","name":"badSourceBoundUSD","type":"uint16"},{"internalType":"uint16","name":"cautionBoundUSD","type":"uint16"},{"internalType":"uint16","name":"badSourceBoundNative","type":"uint16"},{"internalType":"uint16","name":"cautionBoundNative","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"inUSD","type":"bool"},{"internalType":"bool","name":"getLower","type":"bool"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"errorCode","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"},{"internalType":"uint256","name":"errorCodeBreakpoint","type":"uint256"}],"name":"getPriceIsolatedPair","outputs":[{"internalType":"uint256","name":"collateralSharesPrice","type":"uint256"},{"internalType":"uint256","name":"debtUnderlyingPrice","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"uint256","name":"errorCodeBreakpoint","type":"uint256"}],"name":"getPricesForMarket","outputs":[{"components":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"bool","name":"isCollateral","type":"bool"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"uint256","name":"debtBalance","type":"uint256"}],"internalType":"struct AccountSnapshot[]","name":"","type":"tuple[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getPricingAdaptors","outputs":[{"internalType":"address[]","name":"result","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isApprovedAdaptor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSequencerValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isSupportedAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"native","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"notifyFeedRemoval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adaptorToRemove","type":"address"}],"name":"removeApprovedAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"adaptor","type":"address"}],"name":"removeAssetPricingAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cTokenToRemove","type":"address"}],"name":"removeCTokenSupport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adaptorToRemove","type":"address"},{"internalType":"address","name":"adaptorToAdd","type":"address"}],"name":"replaceApprovedAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"adaptorToRemove","type":"address"},{"internalType":"address","name":"adaptorToAdd","type":"address"},{"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"replaceAssetPricingAdaptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"badSourceBoundUSD","type":"uint256"},{"internalType":"uint256","name":"cautionBoundUSD","type":"uint256"},{"internalType":"uint256","name":"badSourceBoundNative","type":"uint256"},{"internalType":"uint256","name":"cautionBoundNative","type":"uint256"}],"name":"setDeviationBounds","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405234801561000f575f5ffd5b5060405161273138038061273183398101604081905261002e91610154565b61003781610048565b6001600160a01b031660805261017a565b610059816399011ef160e01b610079565b610076576040516369b5e45b60e11b815260040160405180910390fd5b50565b5f6100838361009b565b8015610094575061009483836100ce565b9392505050565b5f6100ad826301ffc9a760e01b6100ce565b80156100c857506100c6826001600160e01b03196100ce565b155b92915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f51905082801561013e575060208210155b801561014957505f81115b979650505050505050565b5f60208284031215610164575f5ffd5b81516001600160a01b0381168114610094575f5ffd5b6080516125916101a05f395f818161038a015281816110b6015261139801526125915ff3fe608060405234801561000f575f5ffd5b506004361061016c575f3560e01c806371e41254116100d95780639ae37a2811610093578063e04e7d701161006e578063e04e7d70146103ee578063e73af84614610401578063ed2f860314610414578063ff133d6d1461021e575f5ffd5b80639ae37a28146103b55780639be918e6146103c8578063ce16237c146103db575f5ffd5b806371e41254146103085780637f0ecd3c1461031b5780638c0b09d01461033d5780638d6fbb9e146103655780638f73dcfa146103855780639407d08f146103ac575f5ffd5b80632b12aaa91161012a5780632b12aaa91461023457806334abc11d146102475780635ae69163146102b7578063663158f5146102ca5780636b61db18146102dd5780637194ed42146102f0575f5ffd5b8062082f1414610170578063013ed4cd1461019b578063035e6c19146101b057806311b0b42d146101d85780631b4f30e51461020b5780631f42a45f1461021e575b5f5ffd5b61018361017e366004611f19565b61041d565b60405161019293929190611fdd565b60405180910390f35b6101ae6101a9366004612086565b61079a565b005b6101c36101be3660046120bd565b6107b0565b60408051928352602083019190915201610192565b6101f373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b039091168152602001610192565b6101ae610219366004612086565b61092c565b610226601481565b604051908152602001610192565b6101ae6102423660046120fb565b6109b0565b6102896102553660046120fb565b60016020525f908152604090205461ffff808216916201000081048216916401000000008204811691600160301b90041684565b6040805161ffff95861681529385166020850152918416918301919091529091166060820152608001610192565b6101c36102c536600461212a565b610af6565b6101ae6102d83660046120fb565b610c39565b6101ae6102eb366004612172565b610c9d565b6102f8610cfa565b6040519015158152602001610192565b6101ae6103163660046120fb565b610d08565b6102f86103293660046120fb565b5f6020819052908152604090205460ff1681565b6101f361034b3660046120fb565b60026020525f90815260409020546001600160a01b031681565b6103786103733660046120fb565b610e64565b60405161019291906121b2565b6101f37f000000000000000000000000000000000000000000000000000000000000000081565b61022661015e81565b6101ae6103c33660046121fd565b610eda565b6102f86103d63660046120fb565b610f29565b6101ae6103e93660046120fb565b610f90565b6101ae6103fc366004612252565b610fc1565b6101ae61040f3660046120fb565b61104d565b61022661012c81565b6060805f6104296110b2565b61044657604051637c70f82f60e01b815260040160405180910390fd5b845f8167ffffffffffffffff811115610461576104616122bb565b6040519080825280602002602001820160405280156104bf57816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282525f1990920191018161047f5790505b5090505f8267ffffffffffffffff8111156104dc576104dc6122bb565b604051908082528060200260200182016040528015610505578160200160208202803683370190505b5090505f5f5f5b85811015610787578b8b82818110610526576105266122cf565b905060200201602081019061053b91906120fb565b60405163cf6af22d60e01b81526001600160a01b038f811660048301529193509083169063cf6af22d9060240160c0604051808303815f875af1158015610584573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a89190612328565b8582815181106105ba576105ba6122cf565b60200260200101819052508481815181106105d7576105d76122cf565b602002602001015160600151156106e1576106118582815181106105fd576105fd6122cf565b6020026020010151602001516001806111f6565b858381518110610623576106236122cf565b602002602001018195508281525050506106be848281518110610648576106486122cf565b6020026020010151836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b091906123a8565b670de0b6b3a764000061135f565b8482815181106106d0576106d06122cf565b60200260200101818152505061072d565b61070a8582815181106106f6576106f66122cf565b60200260200101516020015160015f6111f6565b85838151811061071c5761071c6122cf565b602002602001018195508281525050505b83818151811061073f5761073f6122cf565b60200260200101515f1480156107555750600283105b1561075f57600292505b89831061077f57604051637c70f82f60e01b815260040160405180910390fd5b60010161050c565b50929b919a509298509650505050505050565b6107a2611383565b6107ac8282611428565b5050565b5f5f6107ba6110b2565b6107d757604051637c70f82f60e01b815260040160405180910390fd5b6001600160a01b038086165f9081526002602052604081205490911680610811576040516337ccbfb560e01b815260040160405180910390fd5b61081d816001806111f6565b809350819550505061086684886001600160a01b031663f41102916040518163ffffffff1660e01b81526004016020604051808303815f875af115801561068c573d5f5f3e3d5ffd5b9350831580156108765750600282105b1561088057600291505b8482106108a057604051637c70f82f60e01b815260040160405180910390fd5b506001600160a01b038086165f9081526002602052604090205416806108d9576040516337ccbfb560e01b815260040160405180910390fd5b6108e58160015f6111f6565b9093509150821580156108f85750600282105b1561090257600291505b84821061092257604051637c70f82f60e01b815260040160405180910390fd5b5050935093915050565b610934611383565b6001600160a01b0381165f9081526020819052604090205460ff161561096d57604051631f0d085960e11b815260040160405180910390fd5b6109768261166c565b6001600160a01b039182165f90815260208190526040808220805460ff199081169091559290931681529190912080549091166001179055565b6109b8611383565b806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1891906123bf565b505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a56573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7a91906123da565b6001600160a01b038381165f9081526002602052604090205491925016151580610aab57506001600160a01b038116155b15610ac957604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b039182165f90815260026020526040902080546001600160a01b03191691909216179055565b5f5f610b006110b2565b610b0f57505f90506002610c31565b6001600160a01b038086165f908152600260205260408120549091168015610b3657959050855b610b418787876111f6565b90945092506001600160a01b03821615610c17578415610ba257610b9b84836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b9350610c17565b610c1484836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0691906123a8565b670de0b6b3a76400006116a7565b93505b83158015610c255750600283105b15610922576002925050505b935093915050565b610c41611383565b6001600160a01b0381165f9081526020819052604090205460ff1615610c7a57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f908152602081905260409020805460ff19166001179055565b610ca5611383565b6001600160a01b0385165f9081526001602081905260409091209081015460021115610ce457604051631f0d085960e11b815260040160405180910390fd5b610cf28682878787876116d3565b505050505050565b5f610d036110b2565b905090565b335f9081526020819052604090205460ff16610d215750565b6001600160a01b0381165f90815260016020818152604080842090920180548351818402810184019094528084529091830182828015610d8857602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610d6a575b50508351939450505060018211159050610e1257336001600160a01b0316825f81518110610db857610db86122cf565b60200260200101516001600160a01b031614158015610e035750336001600160a01b031682600181518110610def57610def6122cf565b60200260200101516001600160a01b031614155b15610e0d57505050565b610e55565b805f03610e1e57505050565b336001600160a01b0316825f81518110610e3a57610e3a6122cf565b60200260200101516001600160a01b031614610e5557505050565b610e5f8333611428565b505050565b6001600160a01b0381165f90815260016020818152604092839020909101805483518184028101840190945280845260609392830182828015610ece57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610eb0575b50505050509050919050565b610ee2611383565b610eec868661187d565b6001600160a01b0386165f9081526001602081905260409091208082015490911015610f2057610f208782878787876116d3565b50505050505050565b6001600160a01b038082165f908152600260205260408120549091168015610f6e576001600160a01b03165f9081526001602081905260409091200154151592915050565b50506001600160a01b03165f9081526001602081905260409091200154151590565b610f98611383565b610fa18161166c565b6001600160a01b03165f908152602081905260409020805460ff19169055565b610fc9611383565b846001600160a01b0316866001600160a01b031603610ffb57604051631f0d085960e11b815260040160405180910390fd5b6110058787611428565b61100f878661187d565b6001600160a01b0387165f9081526001602081905260409091208082015490911015611043576110438882878787876116d3565b5050505050505050565b611055611383565b6001600160a01b038181165f908152600260205260409020541661108c57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f90815260026020526040902080546001600160a01b0319169055565b5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b0ff43f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611110573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061113491906123da565b90506001600160a01b038116156111ee575f5f826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611183573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111a7919061240e565b50509250925050805f036111be575f935050505090565b5f6111c98242612470565b9050821515806111db575061012c8111155b156111ea575f94505050505090565b5050505b600191505090565b5f806001600160a01b03851661121f576040516337ccbfb560e01b815260040160405180910390fd5b6001600160a01b0385165f908152600160208181526040808420815160a081018352815461ffff80821683526201000082048116838701526401000000008204811683860152600160301b90910416606082015293810180548351818602810186019094528084529193608086019392908301828280156112c757602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116112a9575b50505050508152505090505f8160800151519050805f036112fb576040516337ccbfb560e01b815260040160405180910390fd5b600181111561131a5761131087838888611b64565b9094509250610922565b5f6113448884608001515f81518110611335576113356122cf565b60200260200101518989611ca3565b9095509050801561135457600293505b505050935093915050565b5f825f19048411830215820261137c5763ad251c275f526004601cfd5b5091020490565b60405163de0c7a7160e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063de0c7a7190602401602060405180830381865afa1580156113e5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061140991906123bf565b611426576040516317a1ac7960e01b815260040160405180910390fd5b565b6001600160a01b0382165f90815260016020819052604082200180549091819003611466576040516337ccbfb560e01b815260040160405180910390fd5b600181111561159957826001600160a01b0316825f8154811061148b5761148b6122cf565b5f918252602090912001546001600160a01b0316148015906114dc5750826001600160a01b0316826001815481106114c5576114c56122cf565b5f918252602090912001546001600160a01b031614155b156114fa576040516337ccbfb560e01b815260040160405180910390fd5b826001600160a01b0316825f81548110611516576115166122cf565b5f918252602090912001546001600160a01b0316036115945781600181548110611542576115426122cf565b5f91825260208220015483546001600160a01b03909116918491611568576115686122cf565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6115e7565b826001600160a01b0316825f815481106115b5576115b56122cf565b5f918252602090912001546001600160a01b0316146115e7576040516337ccbfb560e01b815260040160405180910390fd5b818054806115f7576115f7612489565b5f8281526020902081015f1990810180546001600160a01b03191690550190556040517f125899ecb1260d173333573459b1a7a9cfb3817b130b413b4aa06a9ff31e4e809061165e90869086906001600160a01b0392831681529116602082015260400190565b60405180910390a150505050565b6001600160a01b0381165f9081526020819052604090205460ff166116a457604051633927310f60e11b815260040160405180910390fd5b50565b5f825f1904841183021582026116c45763ad251c275f526004601cfd5b50910281810615159190040190565b6116de60148461249d565b8410156116fe57604051631f0d085960e11b815260040160405180910390fd5b61170960148261249d565b82101561172957604051631f0d085960e11b815260040160405180910390fd5b6014831080611739575061015e84115b1561175757604051631f0d085960e11b815260040160405180910390fd5b6014811080611767575061015e82115b1561178557604051631f0d085960e11b815260040160405180910390fd5b6117916127108561249d565b855461ffff191661ffff919091161785556117ae6127108461249d565b855461ffff91909116620100000263ffff0000199091161785556117d46127108361249d565b855461ffff919091166401000000000265ffff00000000199091161785556117fe6127108261249d565b855461ffff91909116600160301b0267ffff00000000000019909116178555604080516001600160a01b03881681526020810186905290810184905260608101839052608081018290527ff9a7f594d37202867f28057760f73a7685c973a02d6ad8a27906d7a8331f13059060a00160405180910390a1505050505050565b6118868161166c565b604051634df48c7360e11b81526001600160a01b038381166004830152821690639be918e690602401602060405180830381865afa1580156118ca573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ee91906123bf565b61190b57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b0382165f90815260016020819052604090912081018054909181111561194b57604051631f0d085960e11b815260040160405180910390fd5b80158015906119875750826001600160a01b0316825f81548110611971576119716122cf565b5f918252602090912001546001600160a01b0316145b156119a557604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b03858116600483015260016024830181905260448301525f9190851690635ae6916390606401606060405180830381865afa1580156119fa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a1e91906124b0565b80519091501580611a30575080604001515b15611a4e57604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b038681166004830152600160248301525f6044830152851690635ae6916390606401606060405180830381865afa158015611a9f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac391906124b0565b80519091501580611ad5575080604001515b15611af357604051631f0d085960e11b815260040160405180910390fd5b82546001810184555f84815260209081902090910180546001600160a01b0319166001600160a01b03878116918217909255604080519289168352928201527fd0fbbdc73d37c26b71504158457880a132e10105178f9286bbff8eea82a3f670910160405180910390a15050505050565b5f5f5f5f611b918888608001515f81518110611b8257611b826122cf565b60200260200101518888611ca3565b915091505f5f611bc18a8a60800151600181518110611bb257611bb26122cf565b60200260200101518a8a611ca3565b91509150828015611bcf5750805b15611be4575f60029550955050505050611c9a565b8280611bed5750805b15611c17578215611c075750935060019250611c9a915050565b8360019550955050505050611c9a565b5f88611c27578960400151611c2a565b89515b61ffff1690505f89611c40578a60600151611c46565b8a602001515b61ffff1690505f611c5987868585611dbc565b90508915611c8057868510611c6e5786611c70565b845b98509650611c9a95505050505050565b868511611c8d5786611c8f565b845b985096505050505050505b94509492505050565b5f5f611cae8561166c565b604051635ae6916360e01b81526001600160a01b038781166004830152851515602483015284151560448301525f9190871690635ae6916390606401606060405180830381865afa158015611d05573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d2991906124b0565b9050806040015115611d42575f60019250925050611c9a565b8415158160200151151514611da7575f611d6786611d61578515611e4e565b85611e4e565b1580156040850152909150611d84575f6001935093505050611c9a565b611d97825f015182846020015188611e97565b8260400151935093505050611c9a565b80516040909101519097909650945050505050565b5f838511611e175783612710611dd28488612525565b611ddc919061253c565b1015611e105783612710611df08588612525565b611dfa919061253c565b1015611e0857506002611e46565b506001611e46565b505f611e46565b84612710611e258487612525565b611e2f919061253c565b1015611e435784612710611df08587612525565b505f5b949350505050565b5f5f5f611e7173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001866111f6565b909350905082158015611e845750600281105b15611e8d575060025b9193911515925050565b5f82611ed0578115611ebd57611eb68585670de0b6b3a764000061135f565b9050611e46565b611eb68585670de0b6b3a76400006116a7565b8115611ee957611eb685670de0b6b3a76400008661135f565b611efc85670de0b6b3a7640000866116a7565b95945050505050565b6001600160a01b03811681146116a4575f5ffd5b5f5f5f5f60608587031215611f2c575f5ffd5b8435611f3781611f05565b9350602085013567ffffffffffffffff811115611f52575f5ffd5b8501601f81018713611f62575f5ffd5b803567ffffffffffffffff811115611f78575f5ffd5b8760208260051b8401011115611f8c575f5ffd5b949760209190910196509394604001359392505050565b5f8151808452602084019350602083015f5b82811015611fd3578151865260209586019590910190600101611fb5565b5093949350505050565b606080825284519082018190525f9060208601906080840190835b8181101561206057835180516001600160a01b0390811685526020808301519091168186015260408083015160ff16908601526060808301511515908601526080808301519086015260a091820151918501919091529093019260c090920191600101611ff8565b505083810360208501526120748187611fa3565b92505050826040830152949350505050565b5f5f60408385031215612097575f5ffd5b82356120a281611f05565b915060208301356120b281611f05565b809150509250929050565b5f5f5f606084860312156120cf575f5ffd5b83356120da81611f05565b925060208401356120ea81611f05565b929592945050506040919091013590565b5f6020828403121561210b575f5ffd5b813561211681611f05565b9392505050565b80151581146116a4575f5ffd5b5f5f5f6060848603121561213c575f5ffd5b833561214781611f05565b925060208401356121578161211d565b915060408401356121678161211d565b809150509250925092565b5f5f5f5f5f60a08688031215612186575f5ffd5b853561219181611f05565b97602087013597506040870135966060810135965060800135945092505050565b602080825282518282018190525f918401906040840190835b818110156121f25783516001600160a01b03168352602093840193909201916001016121cb565b509095945050505050565b5f5f5f5f5f5f60c08789031215612212575f5ffd5b863561221d81611f05565b9550602087013561222d81611f05565b95989597505050506040840135936060810135936080820135935060a0909101359150565b5f5f5f5f5f5f5f60e0888a031215612268575f5ffd5b873561227381611f05565b9650602088013561228381611f05565b9550604088013561229381611f05565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b60405160c0810167ffffffffffffffff8111828210171561231257634e487b7160e01b5f52604160045260245ffd5b60405290565b80516123238161211d565b919050565b5f60c0828403128015612339575f5ffd5b506123426122e3565b825161234d81611f05565b8152602083015161235d81611f05565b6020820152604083015160ff81168114612375575f5ffd5b604082015261238660608401612318565b60608201526080838101519082015260a0928301519281019290925250919050565b5f602082840312156123b8575f5ffd5b5051919050565b5f602082840312156123cf575f5ffd5b81516121168161211d565b5f602082840312156123ea575f5ffd5b815161211681611f05565b805169ffffffffffffffffffff81168114612323575f5ffd5b5f5f5f5f5f60a08688031215612422575f5ffd5b61242b866123f5565b60208701516040880151606089015192975090955093509150612450608087016123f5565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b818103818111156124835761248361245c565b92915050565b634e487b7160e01b5f52603160045260245ffd5b808201808211156124835761248361245c565b5f60608284031280156124c1575f5ffd5b506040516060810167ffffffffffffffff811182821017156124f157634e487b7160e01b5f52604160045260245ffd5b6040528251815260208301516125068161211d565b602082015260408301516125198161211d565b60408201529392505050565b80820281158282048414176124835761248361245c565b5f8261255657634e487b7160e01b5f52601260045260245ffd5b50049056fea2646970667358221220290a04e776ce97ada5d767820102edf4b9dfa7dbece0ac19525ff6987afd934464736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff

Deployed Bytecode

0x608060405234801561000f575f5ffd5b506004361061016c575f3560e01c806371e41254116100d95780639ae37a2811610093578063e04e7d701161006e578063e04e7d70146103ee578063e73af84614610401578063ed2f860314610414578063ff133d6d1461021e575f5ffd5b80639ae37a28146103b55780639be918e6146103c8578063ce16237c146103db575f5ffd5b806371e41254146103085780637f0ecd3c1461031b5780638c0b09d01461033d5780638d6fbb9e146103655780638f73dcfa146103855780639407d08f146103ac575f5ffd5b80632b12aaa91161012a5780632b12aaa91461023457806334abc11d146102475780635ae69163146102b7578063663158f5146102ca5780636b61db18146102dd5780637194ed42146102f0575f5ffd5b8062082f1414610170578063013ed4cd1461019b578063035e6c19146101b057806311b0b42d146101d85780631b4f30e51461020b5780631f42a45f1461021e575b5f5ffd5b61018361017e366004611f19565b61041d565b60405161019293929190611fdd565b60405180910390f35b6101ae6101a9366004612086565b61079a565b005b6101c36101be3660046120bd565b6107b0565b60408051928352602083019190915201610192565b6101f373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b039091168152602001610192565b6101ae610219366004612086565b61092c565b610226601481565b604051908152602001610192565b6101ae6102423660046120fb565b6109b0565b6102896102553660046120fb565b60016020525f908152604090205461ffff808216916201000081048216916401000000008204811691600160301b90041684565b6040805161ffff95861681529385166020850152918416918301919091529091166060820152608001610192565b6101c36102c536600461212a565b610af6565b6101ae6102d83660046120fb565b610c39565b6101ae6102eb366004612172565b610c9d565b6102f8610cfa565b6040519015158152602001610192565b6101ae6103163660046120fb565b610d08565b6102f86103293660046120fb565b5f6020819052908152604090205460ff1681565b6101f361034b3660046120fb565b60026020525f90815260409020546001600160a01b031681565b6103786103733660046120fb565b610e64565b60405161019291906121b2565b6101f37f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b61022661015e81565b6101ae6103c33660046121fd565b610eda565b6102f86103d63660046120fb565b610f29565b6101ae6103e93660046120fb565b610f90565b6101ae6103fc366004612252565b610fc1565b6101ae61040f3660046120fb565b61104d565b61022661012c81565b6060805f6104296110b2565b61044657604051637c70f82f60e01b815260040160405180910390fd5b845f8167ffffffffffffffff811115610461576104616122bb565b6040519080825280602002602001820160405280156104bf57816020015b6040805160c0810182525f8082526020808301829052928201819052606082018190526080820181905260a082015282525f1990920191018161047f5790505b5090505f8267ffffffffffffffff8111156104dc576104dc6122bb565b604051908082528060200260200182016040528015610505578160200160208202803683370190505b5090505f5f5f5b85811015610787578b8b82818110610526576105266122cf565b905060200201602081019061053b91906120fb565b60405163cf6af22d60e01b81526001600160a01b038f811660048301529193509083169063cf6af22d9060240160c0604051808303815f875af1158015610584573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105a89190612328565b8582815181106105ba576105ba6122cf565b60200260200101819052508481815181106105d7576105d76122cf565b602002602001015160600151156106e1576106118582815181106105fd576105fd6122cf565b6020026020010151602001516001806111f6565b858381518110610623576106236122cf565b602002602001018195508281525050506106be848281518110610648576106486122cf565b6020026020010151836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b091906123a8565b670de0b6b3a764000061135f565b8482815181106106d0576106d06122cf565b60200260200101818152505061072d565b61070a8582815181106106f6576106f66122cf565b60200260200101516020015160015f6111f6565b85838151811061071c5761071c6122cf565b602002602001018195508281525050505b83818151811061073f5761073f6122cf565b60200260200101515f1480156107555750600283105b1561075f57600292505b89831061077f57604051637c70f82f60e01b815260040160405180910390fd5b60010161050c565b50929b919a509298509650505050505050565b6107a2611383565b6107ac8282611428565b5050565b5f5f6107ba6110b2565b6107d757604051637c70f82f60e01b815260040160405180910390fd5b6001600160a01b038086165f9081526002602052604081205490911680610811576040516337ccbfb560e01b815260040160405180910390fd5b61081d816001806111f6565b809350819550505061086684886001600160a01b031663f41102916040518163ffffffff1660e01b81526004016020604051808303815f875af115801561068c573d5f5f3e3d5ffd5b9350831580156108765750600282105b1561088057600291505b8482106108a057604051637c70f82f60e01b815260040160405180910390fd5b506001600160a01b038086165f9081526002602052604090205416806108d9576040516337ccbfb560e01b815260040160405180910390fd5b6108e58160015f6111f6565b9093509150821580156108f85750600282105b1561090257600291505b84821061092257604051637c70f82f60e01b815260040160405180910390fd5b5050935093915050565b610934611383565b6001600160a01b0381165f9081526020819052604090205460ff161561096d57604051631f0d085960e11b815260040160405180910390fd5b6109768261166c565b6001600160a01b039182165f90815260208190526040808220805460ff199081169091559290931681529190912080549091166001179055565b6109b8611383565b806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a1891906123bf565b505f816001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a56573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7a91906123da565b6001600160a01b038381165f9081526002602052604090205491925016151580610aab57506001600160a01b038116155b15610ac957604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b039182165f90815260026020526040902080546001600160a01b03191691909216179055565b5f5f610b006110b2565b610b0f57505f90506002610c31565b6001600160a01b038086165f908152600260205260408120549091168015610b3657959050855b610b418787876111f6565b90945092506001600160a01b03821615610c17578415610ba257610b9b84836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa15801561068c573d5f5f3e3d5ffd5b9350610c17565b610c1484836001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be2573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0691906123a8565b670de0b6b3a76400006116a7565b93505b83158015610c255750600283105b15610922576002925050505b935093915050565b610c41611383565b6001600160a01b0381165f9081526020819052604090205460ff1615610c7a57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f908152602081905260409020805460ff19166001179055565b610ca5611383565b6001600160a01b0385165f9081526001602081905260409091209081015460021115610ce457604051631f0d085960e11b815260040160405180910390fd5b610cf28682878787876116d3565b505050505050565b5f610d036110b2565b905090565b335f9081526020819052604090205460ff16610d215750565b6001600160a01b0381165f90815260016020818152604080842090920180548351818402810184019094528084529091830182828015610d8857602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610d6a575b50508351939450505060018211159050610e1257336001600160a01b0316825f81518110610db857610db86122cf565b60200260200101516001600160a01b031614158015610e035750336001600160a01b031682600181518110610def57610def6122cf565b60200260200101516001600160a01b031614155b15610e0d57505050565b610e55565b805f03610e1e57505050565b336001600160a01b0316825f81518110610e3a57610e3a6122cf565b60200260200101516001600160a01b031614610e5557505050565b610e5f8333611428565b505050565b6001600160a01b0381165f90815260016020818152604092839020909101805483518184028101840190945280845260609392830182828015610ece57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610eb0575b50505050509050919050565b610ee2611383565b610eec868661187d565b6001600160a01b0386165f9081526001602081905260409091208082015490911015610f2057610f208782878787876116d3565b50505050505050565b6001600160a01b038082165f908152600260205260408120549091168015610f6e576001600160a01b03165f9081526001602081905260409091200154151592915050565b50506001600160a01b03165f9081526001602081905260409091200154151590565b610f98611383565b610fa18161166c565b6001600160a01b03165f908152602081905260409020805460ff19169055565b610fc9611383565b846001600160a01b0316866001600160a01b031603610ffb57604051631f0d085960e11b815260040160405180910390fd5b6110058787611428565b61100f878661187d565b6001600160a01b0387165f9081526001602081905260409091208082015490911015611043576110438882878787876116d3565b5050505050505050565b611055611383565b6001600160a01b038181165f908152600260205260409020541661108c57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b03165f90815260026020526040902080546001600160a01b0319169055565b5f5f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031663b0ff43f56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611110573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061113491906123da565b90506001600160a01b038116156111ee575f5f826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611183573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111a7919061240e565b50509250925050805f036111be575f935050505090565b5f6111c98242612470565b9050821515806111db575061012c8111155b156111ea575f94505050505090565b5050505b600191505090565b5f806001600160a01b03851661121f576040516337ccbfb560e01b815260040160405180910390fd5b6001600160a01b0385165f908152600160208181526040808420815160a081018352815461ffff80821683526201000082048116838701526401000000008204811683860152600160301b90910416606082015293810180548351818602810186019094528084529193608086019392908301828280156112c757602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116112a9575b50505050508152505090505f8160800151519050805f036112fb576040516337ccbfb560e01b815260040160405180910390fd5b600181111561131a5761131087838888611b64565b9094509250610922565b5f6113448884608001515f81518110611335576113356122cf565b60200260200101518989611ca3565b9095509050801561135457600293505b505050935093915050565b5f825f19048411830215820261137c5763ad251c275f526004601cfd5b5091020490565b60405163de0c7a7160e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063de0c7a7190602401602060405180830381865afa1580156113e5573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061140991906123bf565b611426576040516317a1ac7960e01b815260040160405180910390fd5b565b6001600160a01b0382165f90815260016020819052604082200180549091819003611466576040516337ccbfb560e01b815260040160405180910390fd5b600181111561159957826001600160a01b0316825f8154811061148b5761148b6122cf565b5f918252602090912001546001600160a01b0316148015906114dc5750826001600160a01b0316826001815481106114c5576114c56122cf565b5f918252602090912001546001600160a01b031614155b156114fa576040516337ccbfb560e01b815260040160405180910390fd5b826001600160a01b0316825f81548110611516576115166122cf565b5f918252602090912001546001600160a01b0316036115945781600181548110611542576115426122cf565b5f91825260208220015483546001600160a01b03909116918491611568576115686122cf565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6115e7565b826001600160a01b0316825f815481106115b5576115b56122cf565b5f918252602090912001546001600160a01b0316146115e7576040516337ccbfb560e01b815260040160405180910390fd5b818054806115f7576115f7612489565b5f8281526020902081015f1990810180546001600160a01b03191690550190556040517f125899ecb1260d173333573459b1a7a9cfb3817b130b413b4aa06a9ff31e4e809061165e90869086906001600160a01b0392831681529116602082015260400190565b60405180910390a150505050565b6001600160a01b0381165f9081526020819052604090205460ff166116a457604051633927310f60e11b815260040160405180910390fd5b50565b5f825f1904841183021582026116c45763ad251c275f526004601cfd5b50910281810615159190040190565b6116de60148461249d565b8410156116fe57604051631f0d085960e11b815260040160405180910390fd5b61170960148261249d565b82101561172957604051631f0d085960e11b815260040160405180910390fd5b6014831080611739575061015e84115b1561175757604051631f0d085960e11b815260040160405180910390fd5b6014811080611767575061015e82115b1561178557604051631f0d085960e11b815260040160405180910390fd5b6117916127108561249d565b855461ffff191661ffff919091161785556117ae6127108461249d565b855461ffff91909116620100000263ffff0000199091161785556117d46127108361249d565b855461ffff919091166401000000000265ffff00000000199091161785556117fe6127108261249d565b855461ffff91909116600160301b0267ffff00000000000019909116178555604080516001600160a01b03881681526020810186905290810184905260608101839052608081018290527ff9a7f594d37202867f28057760f73a7685c973a02d6ad8a27906d7a8331f13059060a00160405180910390a1505050505050565b6118868161166c565b604051634df48c7360e11b81526001600160a01b038381166004830152821690639be918e690602401602060405180830381865afa1580156118ca573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ee91906123bf565b61190b57604051631f0d085960e11b815260040160405180910390fd5b6001600160a01b0382165f90815260016020819052604090912081018054909181111561194b57604051631f0d085960e11b815260040160405180910390fd5b80158015906119875750826001600160a01b0316825f81548110611971576119716122cf565b5f918252602090912001546001600160a01b0316145b156119a557604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b03858116600483015260016024830181905260448301525f9190851690635ae6916390606401606060405180830381865afa1580156119fa573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a1e91906124b0565b80519091501580611a30575080604001515b15611a4e57604051631f0d085960e11b815260040160405180910390fd5b604051635ae6916360e01b81526001600160a01b038681166004830152600160248301525f6044830152851690635ae6916390606401606060405180830381865afa158015611a9f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac391906124b0565b80519091501580611ad5575080604001515b15611af357604051631f0d085960e11b815260040160405180910390fd5b82546001810184555f84815260209081902090910180546001600160a01b0319166001600160a01b03878116918217909255604080519289168352928201527fd0fbbdc73d37c26b71504158457880a132e10105178f9286bbff8eea82a3f670910160405180910390a15050505050565b5f5f5f5f611b918888608001515f81518110611b8257611b826122cf565b60200260200101518888611ca3565b915091505f5f611bc18a8a60800151600181518110611bb257611bb26122cf565b60200260200101518a8a611ca3565b91509150828015611bcf5750805b15611be4575f60029550955050505050611c9a565b8280611bed5750805b15611c17578215611c075750935060019250611c9a915050565b8360019550955050505050611c9a565b5f88611c27578960400151611c2a565b89515b61ffff1690505f89611c40578a60600151611c46565b8a602001515b61ffff1690505f611c5987868585611dbc565b90508915611c8057868510611c6e5786611c70565b845b98509650611c9a95505050505050565b868511611c8d5786611c8f565b845b985096505050505050505b94509492505050565b5f5f611cae8561166c565b604051635ae6916360e01b81526001600160a01b038781166004830152851515602483015284151560448301525f9190871690635ae6916390606401606060405180830381865afa158015611d05573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d2991906124b0565b9050806040015115611d42575f60019250925050611c9a565b8415158160200151151514611da7575f611d6786611d61578515611e4e565b85611e4e565b1580156040850152909150611d84575f6001935093505050611c9a565b611d97825f015182846020015188611e97565b8260400151935093505050611c9a565b80516040909101519097909650945050505050565b5f838511611e175783612710611dd28488612525565b611ddc919061253c565b1015611e105783612710611df08588612525565b611dfa919061253c565b1015611e0857506002611e46565b506001611e46565b505f611e46565b84612710611e258487612525565b611e2f919061253c565b1015611e435784612710611df08587612525565b505f5b949350505050565b5f5f5f611e7173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001866111f6565b909350905082158015611e845750600281105b15611e8d575060025b9193911515925050565b5f82611ed0578115611ebd57611eb68585670de0b6b3a764000061135f565b9050611e46565b611eb68585670de0b6b3a76400006116a7565b8115611ee957611eb685670de0b6b3a76400008661135f565b611efc85670de0b6b3a7640000866116a7565b95945050505050565b6001600160a01b03811681146116a4575f5ffd5b5f5f5f5f60608587031215611f2c575f5ffd5b8435611f3781611f05565b9350602085013567ffffffffffffffff811115611f52575f5ffd5b8501601f81018713611f62575f5ffd5b803567ffffffffffffffff811115611f78575f5ffd5b8760208260051b8401011115611f8c575f5ffd5b949760209190910196509394604001359392505050565b5f8151808452602084019350602083015f5b82811015611fd3578151865260209586019590910190600101611fb5565b5093949350505050565b606080825284519082018190525f9060208601906080840190835b8181101561206057835180516001600160a01b0390811685526020808301519091168186015260408083015160ff16908601526060808301511515908601526080808301519086015260a091820151918501919091529093019260c090920191600101611ff8565b505083810360208501526120748187611fa3565b92505050826040830152949350505050565b5f5f60408385031215612097575f5ffd5b82356120a281611f05565b915060208301356120b281611f05565b809150509250929050565b5f5f5f606084860312156120cf575f5ffd5b83356120da81611f05565b925060208401356120ea81611f05565b929592945050506040919091013590565b5f6020828403121561210b575f5ffd5b813561211681611f05565b9392505050565b80151581146116a4575f5ffd5b5f5f5f6060848603121561213c575f5ffd5b833561214781611f05565b925060208401356121578161211d565b915060408401356121678161211d565b809150509250925092565b5f5f5f5f5f60a08688031215612186575f5ffd5b853561219181611f05565b97602087013597506040870135966060810135965060800135945092505050565b602080825282518282018190525f918401906040840190835b818110156121f25783516001600160a01b03168352602093840193909201916001016121cb565b509095945050505050565b5f5f5f5f5f5f60c08789031215612212575f5ffd5b863561221d81611f05565b9550602087013561222d81611f05565b95989597505050506040840135936060810135936080820135935060a0909101359150565b5f5f5f5f5f5f5f60e0888a031215612268575f5ffd5b873561227381611f05565b9650602088013561228381611f05565b9550604088013561229381611f05565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b60405160c0810167ffffffffffffffff8111828210171561231257634e487b7160e01b5f52604160045260245ffd5b60405290565b80516123238161211d565b919050565b5f60c0828403128015612339575f5ffd5b506123426122e3565b825161234d81611f05565b8152602083015161235d81611f05565b6020820152604083015160ff81168114612375575f5ffd5b604082015261238660608401612318565b60608201526080838101519082015260a0928301519281019290925250919050565b5f602082840312156123b8575f5ffd5b5051919050565b5f602082840312156123cf575f5ffd5b81516121168161211d565b5f602082840312156123ea575f5ffd5b815161211681611f05565b805169ffffffffffffffffffff81168114612323575f5ffd5b5f5f5f5f5f60a08688031215612422575f5ffd5b61242b866123f5565b60208701516040880151606089015192975090955093509150612450608087016123f5565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b818103818111156124835761248361245c565b92915050565b634e487b7160e01b5f52603160045260245ffd5b808201808211156124835761248361245c565b5f60608284031280156124c1575f5ffd5b506040516060810167ffffffffffffffff811182821017156124f157634e487b7160e01b5f52604160045260245ffd5b6040528251815260208301516125068161211d565b602082015260408301516125198161211d565b60408201529392505050565b80820281158282048414176124835761248361245c565b5f8261255657634e487b7160e01b5f52601260045260245ffd5b50049056fea2646970667358221220290a04e776ce97ada5d767820102edf4b9dfa7dbece0ac19525ff6987afd934464736f6c634300081c0033

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

0000000000000000000000001310f352f1389969ece6741671c4b919523912ff

-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff


Deployed Bytecode Sourcemap

133728:49770:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;160065:2231;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;145333:175;;;;;;:::i;:::-;;:::i;:::-;;157444:1831;;;;;;:::i;:::-;;:::i;:::-;;;;3851:25:1;;;3907:2;3892:18;;3885:34;;;;3824:18;157444:1831:0;3677:248:1;136309:84:0;;136351:42;136309:84;;;;;-1:-1:-1;;;;;4094:32:1;;;4076:51;;4064:2;4049:18;136309:84:0;3930:203:1;149615:556:0;;;;;;:::i;:::-;;:::i;137212:60::-;;137270:2;137212:60;;;;;4284:25:1;;;4272:2;4257:18;137212:60:0;4138:177:1;147976:680:0;;;;;;:::i;:::-;;:::i;137754:59::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;137754:59:0;;;;;;;;;4825:6:1;4813:19;;;4795:38;;4869:19;;;4864:2;4849:18;;4842:47;4925:19;;;4905:18;;;4898:47;;;;4981:19;;;4976:2;4961:18;;4954:47;4782:3;4767:19;137754:59:0;4572:435:1;155421:1388:0;;;;;;:::i;:::-;;:::i;150370:334::-;;;;;;:::i;:::-;;:::i;152426:730::-;;;;;;:::i;:::-;;:::i;154027:102::-;;;:::i;:::-;;;6556:14:1;;6549:22;6531:41;;6519:2;6504:18;154027:102:0;6391:187:1;146520:786:0;;;;;;:::i;:::-;;:::i;137574:49::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;137880:42;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;137880:42:0;;;147527:168;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;137316:49::-;;;;;136726;;136772:3;136726:49;;140566:882;;;;;;:::i;:::-;;:::i;153471:331::-;;;;;;:::i;:::-;;:::i;150912:279::-;;;;;;:::i;:::-;;:::i;143347:1233::-;;;;;;:::i;:::-;;:::i;148919:347::-;;;;;;:::i;:::-;;:::i;136514:47::-;;136558:3;136514:47;;160065:2231;160228:24;160263:16;160290:7;160321:19;:17;:19::i;:::-;160316:93;;160364:33;;-1:-1:-1;;;160364:33:0;;;;;;;;;;;160316:93;160441:6;160421:17;160441:6;160502:32;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;160502:32:0;;-1:-1:-1;;160502:32:0;;;;;;;;;;;;160465:69;;160545:23;160585:9;160571:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;160571:24:0;;160545:50;;160606:17;160636:13;160665:9;160660:1579;160680:9;160676:1;:13;160660:1579;;;160719:6;;160726:1;160719:9;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;160758:42;;-1:-1:-1;;;160758:42:0;;-1:-1:-1;;;;;4094:32:1;;;160758:42:0;;;4076:51:1;160711:17:0;;-1:-1:-1;160758:33:0;;;;;;4049:18:1;;160758:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;160743:9;160753:1;160743:12;;;;;;;;:::i;:::-;;;;;;:57;;;;160821:9;160831:1;160821:12;;;;;;;;:::i;:::-;;;;;;;:25;;;160817:1044;;;161058:128;161090:9;161100:1;161090:12;;;;;;;;:::i;:::-;;;;;;;:23;;;161136:4;161163;161058:9;:128::i;:::-;161034:6;161041:1;161034:9;;;;;;;;:::i;:::-;;;;;;161033:153;;;;;;;;;161353;161400:6;161407:1;161400:9;;;;;;;;:::i;:::-;;;;;;;161440:5;-1:-1:-1;;;;;161432:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;636:4;161353:24;:153::i;:::-;161341:6;161348:1;161341:9;;;;;;;;:::i;:::-;;;;;;:165;;;;;160817:1044;;;161716:129;161748:9;161758:1;161748:12;;;;;;;;:::i;:::-;;;;;;;:23;;;161794:4;161821:5;161716:9;:129::i;:::-;161692:6;161699:1;161692:9;;;;;;;;:::i;:::-;;;;;;161691:154;;;;;;;;;160817:1044;162000:6;162007:1;162000:9;;;;;;;;:::i;:::-;;;;;;;162013:1;162000:14;:40;;;;;843:1;162018:9;:22;162000:40;161996:103;;;843:1;162061:22;;161996:103;162132:19;162119:9;:32;162115:113;;162179:33;;-1:-1:-1;;;162179:33:0;;;;;;;;;;;162115:113;160691:3;;160660:1579;;;-1:-1:-1;162259:9:0;;162270:6;;-1:-1:-1;162278:9:0;;-1:-1:-1;160065:2231:0;-1:-1:-1;;;;;;;160065:2231:0:o;145333:175::-;145420:27;:25;:27::i;:::-;145458:42;145485:5;145492:7;145458:26;:42::i;:::-;145333:175;;:::o;157444:1831::-;157609:29;157649:27;157700:19;:17;:19::i;:::-;157695:93;;157743:33;;-1:-1:-1;;;157743:33:0;;;;;;;;;;;157695:93;-1:-1:-1;;;;;157849:24:0;;;157800:17;157849:24;;;:7;:24;;;;;;157800:17;;157849:24;;157884:93;;157936:29;;-1:-1:-1;;;157936:29:0;;;;;;;;;;;157884:93;158026:83;158050:10;158075:4;158094;158026:9;:83::i;:::-;157989:120;;;;;;;;158146:150;158185:21;158229:15;-1:-1:-1;;;;;158221:44:0;;:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;158146:150;158122:174;-1:-1:-1;158424:26:0;;:52;;;;;843:1;158454:9;:22;158424:52;158420:107;;;843:1;158493:22;;158420:107;158556:19;158543:9;:32;158539:105;;158599:33;;-1:-1:-1;;;158599:33:0;;;;;;;;;;;158539:105;-1:-1:-1;;;;;;158669:18:0;;;;;;;:7;:18;;;;;;;;158698:93;;158750:29;;-1:-1:-1;;;158750:29:0;;;;;;;;;;;158698:93;158838:84;158862:10;158887:4;158906:5;158838:9;:84::i;:::-;158803:119;;-1:-1:-1;158803:119:0;-1:-1:-1;159050:24:0;;:50;;;;;843:1;159078:9;:22;159050:50;159046:105;;;843:1;159117:22;;159046:105;159180:19;159167:9;:32;159163:105;;159223:33;;-1:-1:-1;;;159223:33:0;;;;;;;;;;;159163:105;157684:1591;;157444:1831;;;;;;:::o;149615:556::-;149739:27;:25;:27::i;:::-;-1:-1:-1;;;;;149845:31:0;;:17;:31;;;;;;;;;;;;;149841:104;;;149900:33;;-1:-1:-1;;;149900:33:0;;;;;;;;;;;149841:104;150020:40;150044:15;150020:23;:40::i;:::-;-1:-1:-1;;;;;150080:34:0;;;:17;:34;;;;;;;;;;;150073:41;;-1:-1:-1;;150073:41:0;;;;;;150125:31;;;;;;;;;;:38;;;;;150073:41;150125:38;;;149615:556::o;147976:680::-;148041:27;:25;:27::i;:::-;148163:9;-1:-1:-1;;;;;148155:31:0;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;148406:21;148438:9;-1:-1:-1;;;;;148430:24:0;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;148471:18:0;;;148501:1;148471:18;;;:7;:18;;;;;;148406:50;;-1:-1:-1;148471:18:0;:32;;;:63;;-1:-1:-1;;;;;;148507:27:0;;;148471:63;148467:136;;;148558:33;;-1:-1:-1;;;148558:33:0;;;;;;;;;;;148467:136;-1:-1:-1;;;;;148615:18:0;;;;;;;:7;:18;;;;;:33;;-1:-1:-1;;;;;;148615:33:0;;;;;;;;147976:680::o;155421:1388::-;155536:13;155551:17;155586:19;:17;:19::i;:::-;155581:75;;-1:-1:-1;155630:1:0;;-1:-1:-1;843:1:0;155622:22;;155581:75;-1:-1:-1;;;;;155720:14:0;;;155668;155720;;;:7;:14;;;;;;155668;;155720;155802:30;;155798:116;;155886:16;155858:5;-1:-1:-1;155886:16:0;155798:116;155947:33;155957:5;155964;155971:8;155947:9;:33::i;:::-;155926:54;;-1:-1:-1;155926:54:0;-1:-1:-1;;;;;;156132:20:0;;;156128:460;;156173:8;156169:408;;;156210:150;156257:5;156293:6;-1:-1:-1;;;;;156285:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;156210:150;156202:158;;156169:408;;;156409:152;156458:5;156494:6;-1:-1:-1;;;;;156486:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;636:4;156409:26;:152::i;:::-;156401:160;;156169:408;156715:10;;:36;;;;;843:1;156729:9;:22;156715:36;156711:91;;;843:1;156768:22;;155570:1239;;155421:1388;;;;;;;:::o;150370:334::-;150440:27;:25;:27::i;:::-;-1:-1:-1;;;;;150546:31:0;;:17;:31;;;;;;;;;;;;;150542:104;;;150601:33;;-1:-1:-1;;;150601:33:0;;;;;;;;;;;150542:104;-1:-1:-1;;;;;150658:31:0;:17;:31;;;;;;;;;;:38;;-1:-1:-1;;150658:38:0;150692:4;150658:38;;;150370:334::o;152426:730::-;152651:27;:25;:27::i;:::-;-1:-1:-1;;;;;152720:25:0;;152689:28;152720:25;;;:18;:25;;;;;;;;152840:15;;;:22;152865:1;-1:-1:-1;152836:99:0;;;152890:33;;-1:-1:-1;;;152890:33:0;;;;;;;;;;;152836:99;152947:201;152981:5;153001:6;153022:17;153054:15;153084:20;153119:18;152947:19;:201::i;:::-;152640:516;152426:730;;;;;:::o;154027:102::-;154078:4;154102:19;:17;:19::i;:::-;154095:26;;154027:102;:::o;146520:786::-;146605:10;146587:17;:29;;;;;;;;;;;;;146582:69;;146520:786;:::o;146582:69::-;-1:-1:-1;;;;;146691:25:0;;146663;146691;;;:18;:25;;;;;;;;:34;;;146663:62;;;;;;;;;;;;;;;;;146691:34;;146663:62;;146691:34;146663:62;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;146663:62:0;;;;;;;;;;;;;;;;-1:-1:-1;;146758:15:0;;146663:62;;-1:-1:-1;;;146930:1:0;146916:15;;146912:331;;-1:-1:-1;146912:331:0;;146967:10;-1:-1:-1;;;;;146952:25:0;:8;146961:1;146952:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;146952:25:0;;;:54;;;;;146996:10;-1:-1:-1;;;;;146981:25:0;:8;146990:1;146981:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;146981:25:0;;;146952:54;146948:101;;;147027:7;;146520:786;:::o;146948:101::-;146912:331;;;147085:11;147100:1;147085:16;147081:63;;147122:7;;146520:786;:::o;147081:63::-;147179:10;-1:-1:-1;;;;;147164:25:0;:8;147173:1;147164:11;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;147164:25:0;;147160:72;;147210:7;;146520:786;:::o;147160:72::-;147253:45;147280:5;147287:10;147253:26;:45::i;:::-;146571:735;;146520:786;:::o;147527:168::-;-1:-1:-1;;;;;147653:25:0;;;;;;:18;:25;;;;;;;;;:34;;;147644:43;;;;;;;;;;;;;;;;;147608:23;;147644:43;;;147653:34;147644:43;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;147644:43:0;;;;;;;;;;;;;;;;;;;;;;;147527:168;;;:::o;140566:882::-;140821:27;:25;:27::i;:::-;140859:39;140883:5;140890:7;140859:23;:39::i;:::-;-1:-1:-1;;;;;141037:25:0;;141006:28;141037:25;;;:18;:25;;;;;;;;141157:15;;;:22;141037:25;;-1:-1:-1;141153:288:0;;;141200:229;141238:5;141262:6;141287:17;141323:15;141357:20;141396:18;141200:19;:229::i;:::-;140810:638;140566:882;;;;;;:::o;153471:331::-;-1:-1:-1;;;;;153579:14:0;;;153535:4;153579:14;;;:7;:14;;;;;;153535:4;;153579:14;153608:30;;153604:126;;-1:-1:-1;;;;;153662:36:0;153717:1;153662:36;;;:18;:36;;;;;;;;:45;:52;:56;;;153471:331;-1:-1:-1;;153471:331:0:o;153604:126::-;-1:-1:-1;;;;;;;153749:25:0;153793:1;153749:25;;;:18;:25;;;;;;;;:34;:41;:45;;;153471:331::o;150912:279::-;150988:27;:25;:27::i;:::-;151089:40;151113:15;151089:23;:40::i;:::-;-1:-1:-1;;;;;151149:34:0;:17;:34;;;;;;;;;;151142:41;;-1:-1:-1;;151142:41:0;;;150912:279::o;143347:1233::-;143645:27;:25;:27::i;:::-;143832:12;-1:-1:-1;;;;;143813:31:0;:15;-1:-1:-1;;;;;143813:31:0;;143809:104;;143868:33;;-1:-1:-1;;;143868:33:0;;;;;;;;;;;143809:104;143925:50;143952:5;143959:15;143925:26;:50::i;:::-;143986:44;144010:5;144017:12;143986:23;:44::i;:::-;-1:-1:-1;;;;;144169:25:0;;144138:28;144169:25;;;:18;:25;;;;;;;;144289:15;;;:22;144169:25;;-1:-1:-1;144285:288:0;;;144332:229;144370:5;144394:6;144419:17;144455:15;144489:20;144528:18;144332:19;:229::i;:::-;143634:946;143347:1233;;;;;;;:::o;148919:347::-;148992:27;:25;:27::i;:::-;-1:-1:-1;;;;;149110:23:0;;;149145:1;149110:23;;;:7;:23;;;;;;;149106:110;;149171:33;;-1:-1:-1;;;149171:33:0;;;;;;;;;;;149106:110;-1:-1:-1;;;;;149235:23:0;;;;;:7;:23;;;;;149228:30;;-1:-1:-1;;;;;;149228:30:0;;;148919:347::o;174642:787::-;174694:4;174711:27;174741:15;-1:-1:-1;;;;;174741:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;174711:64;-1:-1:-1;;;;;;174792:33:0;;;174788:610;;174845:13;174860:17;174913:19;-1:-1:-1;;;;;174902:47:0;;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;174842:109;;;;;;;175144:9;175157:1;175144:14;175140:67;;175186:5;175179:12;;;;;174642:787;:::o;175140:67::-;175223:19;175245:27;175263:9;175245:15;:27;:::i;:::-;175223:49;-1:-1:-1;175291:11:0;;;;:47;;;136558:3;175306:11;:32;;175291:47;175287:100;;;175366:5;175359:12;;;;;;174642:787;:::o;175287:100::-;174827:571;;;174788:610;175417:4;175410:11;;;174642:787;:::o;163396:948::-;163514:13;;-1:-1:-1;;;;;163563:19:0;;163559:88;;163606:29;;-1:-1:-1;;;163606:29:0;;;;;;;;;;;163559:88;-1:-1:-1;;;;;163689:25:0;;163659:27;163689:25;;;:18;:25;;;;;;;;163659:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;163659:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;163689:25;;163659:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;163659:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;163725:19;163747:6;:15;;;:22;163725:44;;163784:11;163799:1;163784:16;163780:85;;163824:29;;-1:-1:-1;;;163824:29:0;;;;;;;;;;;163780:85;163970:1;163956:11;:15;163952:385;;;164026:52;164047:5;164054:6;164062:5;164069:8;164026:20;:52::i;:::-;163988:90;;-1:-1:-1;163988:90:0;-1:-1:-1;163952:385:0;;;164111:13;164176:64;164197:5;164204:6;:15;;;164220:1;164204:18;;;;;;;;:::i;:::-;;;;;;;164224:5;164231:8;164176:20;:64::i;:::-;164139:101;;-1:-1:-1;164139:101:0;-1:-1:-1;164255:71:0;;;;843:1;164288:22;;164255:71;164096:241;163548:796;;163396:948;;;;;;:::o;7895:476::-;7967:9;8194:1;8190;8186:6;8182:14;8179:1;8176:21;8173:1;8169:29;8162:37;8159:1;8155:45;8145:172;;8234:10;8228:4;8221:24;8297:4;8291;8284:18;8145:172;-1:-1:-1;8340:9:0;;8336:17;;7895:476::o;183306:189::-;183373:50;;-1:-1:-1;;;183373:50:0;;183412:10;183373:50;;;4076:51:1;183373:15:0;-1:-1:-1;;;;;183373:38:0;;;;4049:18:1;;183373:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183368:120;;183447:29;;-1:-1:-1;;;183447:29:0;;;;;;;;;;;183368:120;183306:189::o;167642:1402::-;-1:-1:-1;;;;;167932:25:0;;167903:26;167932:25;;;:18;:25;;;;;;;:34;167999:15;;167932:34;;168029:16;;;168025:85;;168069:29;;-1:-1:-1;;;168069:29:0;;;;;;;;;;;168025:85;168140:1;168126:11;:15;168122:652;;;168280:7;-1:-1:-1;;;;;168265:22:0;:8;168274:1;168265:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168265:11:0;:22;;;;:48;;;168306:7;-1:-1:-1;;;;;168291:22:0;:8;168300:1;168291:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168291:11:0;:22;;168265:48;168261:125;;;168341:29;;-1:-1:-1;;;168341:29:0;;;;;;;;;;;168261:125;168563:7;-1:-1:-1;;;;;168548:22:0;:8;168557:1;168548:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168548:11:0;:22;168544:88;;168605:8;168614:1;168605:11;;;;;;;;:::i;:::-;;;;;;;;;;168591;;-1:-1:-1;;;;;168605:11:0;;;;168591:8;;:11;;;;:::i;:::-;;;;;;;;;:25;;;;;-1:-1:-1;;;;;168591:25:0;;;;;-1:-1:-1;;;;;168591:25:0;;;;;;168544:88;168122:652;;;168683:7;-1:-1:-1;;;;;168668:22:0;:8;168677:1;168668:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;168668:11:0;:22;168664:99;;168718:29;;-1:-1:-1;;;168718:29:0;;;;;;;;;;;168664:99;168966:8;:14;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;168966:14:0;;;;;-1:-1:-1;;;;;;168966:14:0;;;;;;168996:40;;;;;;169021:5;;169028:7;;-1:-1:-1;;;;;13183:32:1;;;13165:51;;13252:32;;13247:2;13232:18;;13225:60;13153:2;13138:18;;12991:300;168996:40:0;;;;;;;;167744:1300;;167642:1402;;:::o;183042:186::-;-1:-1:-1;;;;;183122:26:0;;:17;:26;;;;;;;;;;;;;183117:104;;183172:37;;-1:-1:-1;;;183172:37:0;;;;;;;;;;;183117:104;183042:186;:::o;8475:518::-;8549:9;8776:1;8772;8768:6;8764:14;8761:1;8758:21;8755:1;8751:29;8744:37;8741:1;8737:45;8727:172;;8816:10;8810:4;8803:24;8879:4;8873;8866:18;8727:172;-1:-1:-1;8961:9:0;;8936:17;;;8929:25;8922:33;8957:17;;;8918:57;;8475:518::o;178332:1927::-;178756:49;137270:2;178756:15;:49;:::i;:::-;178736:17;:69;178732:142;;;178829:33;;-1:-1:-1;;;178829:33:0;;;;;;;;;;;178732:142;179051:52;137270:2;179051:18;:52;:::i;:::-;179028:20;:75;179024:148;;;179127:33;;-1:-1:-1;;;179127:33:0;;;;;;;;;;;179024:148;136965:2;179275:15;:37;:93;;;;136772:3;179329:17;:39;179275:93;179257:190;;;179402:33;;-1:-1:-1;;;179402:33:0;;;;;;;;;;;179257:190;136965:2;179553:18;:40;:99;;;;136772:3;179610:20;:42;179553:99;179535:196;;;179686:33;;-1:-1:-1;;;179686:33:0;;;;;;;;;;;179535:196;179890:23;745:3;179890:17;:23;:::i;:::-;179856:58;;-1:-1:-1;;179856:58:0;;;;;;;;;179957:21;745:3;179957:15;:21;:::i;:::-;179925:54;;;;;;;;;-1:-1:-1;;179925:54:0;;;;;;180027:26;745:3;180027:20;:26;:::i;:::-;179990:64;;;;;;;;;-1:-1:-1;;179990:64:0;;;;;;180100:24;745:3;180100:18;:24;:::i;:::-;180065:60;;;;;;;-1:-1:-1;;;180065:60:0;-1:-1:-1;;180065:60:0;;;;;;180143:108;;;-1:-1:-1;;;;;13703:32:1;;13685:51;;13767:2;13752:18;;13745:34;;;13795:18;;;13788:34;;;13853:2;13838:18;;13831:34;;;13896:3;13881:19;;13874:35;;;180143:108:0;;13672:3:1;13657:19;180143:108:0;;;;;;;178332:1927;;;;;;:::o;164952:1937::-;165104:32;165128:7;165104:23;:32::i;:::-;165218:47;;-1:-1:-1;;;165218:47:0;;-1:-1:-1;;;;;4094:32:1;;;165218:47:0;;;4076:51:1;165218:40:0;;;;;4049:18:1;;165218:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165213:121;;165289:33;;-1:-1:-1;;;165289:33:0;;;;;;;;;;;165213:121;-1:-1:-1;;;;;165375:25:0;;165346:26;165375:25;;;:18;:25;;;;;;;;:34;;165442:15;;165375:34;;165578:15;;165574:88;;;165617:33;;-1:-1:-1;;;165617:33:0;;;;;;;;;;;165574:88;165964:16;;;;;:42;;;165999:7;-1:-1:-1;;;;;165984:22:0;:8;165993:1;165984:11;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;165984:11:0;:22;165964:42;165960:115;;;166030:33;;-1:-1:-1;;;166030:33:0;;;;;;;;;;;165960:115;166271:65;;-1:-1:-1;;;166271:65:0;;-1:-1:-1;;;;;14128:32:1;;;166271:65:0;;;14110:51:1;166325:4:0;14177:18:1;;;14170:50;;;14236:18;;;14229:50;166226:42:0;;166271:46;;;;;;14083:18:1;;166271:65:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;166353:12;;166226:110;;-1:-1:-1;166353:17:0;;:36;;;166374:6;:15;;;166353:36;166349:109;;;166413:33;;-1:-1:-1;;;166413:33:0;;;;;;;;;;;166349:109;166619:52;;-1:-1:-1;;;166619:52:0;;-1:-1:-1;;;;;14128:32:1;;;166619:52:0;;;14110:51:1;166659:4:0;14177:18:1;;;14170:50;166665:5:0;14236:18:1;;;14229:50;166619:32:0;;;;;14083:18:1;;166619:52:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;166688:12;;166610:61;;-1:-1:-1;166688:17:0;;:36;;;166709:6;:15;;;166688:36;166684:109;;;166748:33;;-1:-1:-1;;;166748:33:0;;;;;;;;;;;166684:109;166805:22;;;;;;;-1:-1:-1;166805:22:0;;;;;;;;;;;;;-1:-1:-1;;;;;;166805:22:0;-1:-1:-1;;;;;166805:22:0;;;;;;;;;166843:38;;;13183:32:1;;;13165:51;;13232:18;;;13225:60;166843:38:0;;13138:18:1;166843:38:0;;;;;;;165026:1863;;;164952:1937;;:::o;169946:1643::-;170113:7;170122;170143:14;170159:11;170174:88;170209:5;170216:6;:15;;;170232:1;170216:18;;;;;;;;:::i;:::-;;;;;;;170236:5;170243:8;170174:20;:88::i;:::-;170142:120;;;;170274:14;170290:11;170304:88;170339:5;170346:6;:15;;;170362:1;170346:18;;;;;;;;:::i;:::-;;;;;;;170366:5;170373:8;170304:20;:88::i;:::-;170273:119;;;;170521:6;:16;;;;;170531:6;170521:16;170517:70;;;170561:1;843;170553:22;;;;;;;;;;170517:70;170706:6;:16;;;;170716:6;170706:16;170702:388;;;170971:6;170967:71;;;-1:-1:-1;171006:6:0;-1:-1:-1;952:1:0;;-1:-1:-1;170998:24:0;;-1:-1:-1;;170998:24:0;170967:71;171062:6;952:1;171054:24;;;;;;;;;;170702:388;171102:22;171127:5;:75;;171175:6;:27;;;171127:75;;;171148:24;;171127:75;171102:100;;;;171213:20;171236:5;:71;;171282:6;:25;;;171236:71;;;171257:6;:22;;;171236:71;171213:94;;;;171320:17;171353:58;171366:6;171374;171382:14;171398:12;171353;:58::i;:::-;171320:91;;171426:8;171422:94;;;171468:6;171459;:15;:33;;171486:6;171459:33;;;171477:6;171459:33;171451:53;-1:-1:-1;171494:9:0;-1:-1:-1;171451:53:0;;-1:-1:-1;;;;;;171451:53:0;171422:94;171545:6;171536;:15;:33;;171563:6;171536:33;;;171554:6;171536:33;171528:53;-1:-1:-1;171571:9:0;-1:-1:-1;;;;;;;169946:1643:0;;;;;;;;:::o;172322:1080::-;172477:7;172486:4;172503:32;172527:7;172503:23;:32::i;:::-;172593:70;;-1:-1:-1;;;172593:70:0;;-1:-1:-1;;;;;14128:32:1;;;172593:70:0;;;14110:51:1;14204:14;;14197:22;14177:18;;;14170:50;14263:14;;14256:22;14236:18;;;14229:50;172548:42:0;;172593:46;;;;;;14083:18:1;;172593:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;172548:115;;172756:6;:15;;;172752:64;;;172796:1;172799:4;172788:16;;;;;;;172752:64;172946:5;172930:21;;:6;:12;;;:21;;;172926:418;;172968:16;173046:43;173060:5;:28;;173080:8;173079:9;173046:13;:43::i;173060:28::-;173068:8;173046:13;:43::i;:::-;172999:90;;;173010:15;;;172999:90;;;-1:-1:-1;173104:72:0;;173152:1;173155:4;173144:16;;;;;;;;173104:72;173218:65;173236:6;:12;;;173250:8;173260:6;:12;;;173274:8;173218:17;:65::i;:::-;173302:6;:15;;;173192:140;;;;;;;;172926:418;173364:12;;173378:15;;;;;173364:12;;173378:15;;-1:-1:-1;172322:1080:0;-1:-1:-1;;;;;172322:1080:0:o;181396:1449::-;181552:7;181581:1;181576;:6;181572:679;;181711:1;745:3;181684:16;181688:12;181684:1;:16;:::i;:::-;181683:24;;;;:::i;:::-;181682:30;181678:530;;;181948:1;745:3;181919:18;181923:14;181919:1;:18;:::i;:::-;181918:26;;;;:::i;:::-;181917:32;181913:98;;;-1:-1:-1;843:1:0;181974:17;;181913:98;-1:-1:-1;952:1:0;182178:14;;181678:530;-1:-1:-1;1036:1:0;182224:15;;181572:679;182369:1;745:3;182342:16;182346:12;182342:1;:16;:::i;:::-;182341:24;;;;:::i;:::-;182340:30;182336:474;;;182574:1;745:3;182545:18;182549:14;182545:1;:18;:::i;182336:474::-;-1:-1:-1;1036:1:0;181396:1449;;;;;;;:::o;173959:569::-;174036:13;174051;174077:17;174126:33;136351:42;174144:4;174150:8;174126:9;:33::i;:::-;174105:54;;-1:-1:-1;174105:54:0;-1:-1:-1;174287:10:0;;:36;;;;;843:1;174301:9;:22;174287:36;174283:91;;;-1:-1:-1;843:1:0;174283:91;173959:569;;174499:21;;;;-1:-1:-1;;173959:569:0:o;176374:803::-;176549:7;176574:14;176569:322;;176684:8;176680:115;;;176720:59;176745:12;176759:14;636:4;176720:24;:59::i;:::-;176713:66;;;;176680:115;176818:61;176845:12;176859:14;636:4;176818:26;:61::i;176569:322::-;176978:8;176974:107;;;177010:59;177035:12;636:4;177054:14;177010:24;:59::i;176974:107::-;177108:61;177135:12;636:4;177154:14;177108:26;:61::i;:::-;177101:68;176374:803;-1:-1:-1;;;;;176374:803:0:o;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:865;254:6;262;270;278;331:2;319:9;310:7;306:23;302:32;299:52;;;347:1;344;337:12;299:52;386:9;373:23;405:31;430:5;405:31;:::i;:::-;455:5;-1:-1:-1;511:2:1;496:18;;483:32;538:18;527:30;;524:50;;;570:1;567;560:12;524:50;593:22;;646:4;638:13;;634:27;-1:-1:-1;624:55:1;;675:1;672;665:12;624:55;715:2;702:16;741:18;733:6;730:30;727:50;;;773:1;770;763:12;727:50;826:7;821:2;811:6;808:1;804:14;800:2;796:23;792:32;789:45;786:65;;;847:1;844;837:12;786:65;150:865;;878:2;870:11;;;;;-1:-1:-1;900:6:1;;979:2;964:18;951:32;;150:865;-1:-1:-1;;;150:865:1:o;1020:420::-;1073:3;1111:5;1105:12;1138:6;1133:3;1126:19;1170:4;1165:3;1161:14;1154:21;;1209:4;1202:5;1198:16;1232:1;1242:173;1256:6;1253:1;1250:13;1242:173;;;1317:13;;1305:26;;1360:4;1351:14;;;;1388:17;;;;1278:1;1271:9;1242:173;;;-1:-1:-1;1431:3:1;;1020:420;-1:-1:-1;;;;1020:420:1:o;1445:1321::-;1807:2;1819:21;;;1889:13;;1792:18;;;1911:22;;;1759:4;;2003;1991:17;;;1964:3;1949:19;;;1759:4;2036:563;2050:6;2047:1;2044:13;2036:563;;;2109:13;;2151:9;;-1:-1:-1;;;;;2147:35:1;;;2135:48;;2237:4;2229:13;;;2223:20;2219:46;;;2203:14;;;2196:70;2320:4;2312:13;;;2306:20;2328:4;2302:31;2286:14;;;2279:55;2396:2;2388:11;;;2382:18;2375:26;2368:34;2354:12;;;2347:56;2452:3;2444:12;;;2438:19;2423:13;;;2416:42;2170:3;2500:13;;;2494:20;2478:14;;;2471:44;;;;2572:17;;;;2544:4;2535:14;;;;2179:1;2065:9;2036:563;;;2040:3;;2646:9;2641:3;2637:19;2630:4;2619:9;2615:20;2608:49;2674:41;2711:3;2703:6;2674:41;:::i;:::-;2666:49;;;;2753:6;2746:4;2735:9;2731:20;2724:36;1445:1321;;;;;;:::o;2771:388::-;2839:6;2847;2900:2;2888:9;2879:7;2875:23;2871:32;2868:52;;;2916:1;2913;2906:12;2868:52;2955:9;2942:23;2974:31;2999:5;2974:31;:::i;:::-;3024:5;-1:-1:-1;3081:2:1;3066:18;;3053:32;3094:33;3053:32;3094:33;:::i;:::-;3146:7;3136:17;;;2771:388;;;;;:::o;3164:508::-;3241:6;3249;3257;3310:2;3298:9;3289:7;3285:23;3281:32;3278:52;;;3326:1;3323;3316:12;3278:52;3365:9;3352:23;3384:31;3409:5;3384:31;:::i;:::-;3434:5;-1:-1:-1;3491:2:1;3476:18;;3463:32;3504:33;3463:32;3504:33;:::i;:::-;3164:508;;3556:7;;-1:-1:-1;;;3636:2:1;3621:18;;;;3608:32;;3164:508::o;4320:247::-;4379:6;4432:2;4420:9;4411:7;4407:23;4403:32;4400:52;;;4448:1;4445;4438:12;4400:52;4487:9;4474:23;4506:31;4531:5;4506:31;:::i;:::-;4556:5;4320:247;-1:-1:-1;;;4320:247:1:o;5012:118::-;5098:5;5091:13;5084:21;5077:5;5074:32;5064:60;;5120:1;5117;5110:12;5135:517;5206:6;5214;5222;5275:2;5263:9;5254:7;5250:23;5246:32;5243:52;;;5291:1;5288;5281:12;5243:52;5330:9;5317:23;5349:31;5374:5;5349:31;:::i;:::-;5399:5;-1:-1:-1;5456:2:1;5441:18;;5428:32;5469:30;5428:32;5469:30;:::i;:::-;5518:7;-1:-1:-1;5577:2:1;5562:18;;5549:32;5590:30;5549:32;5590:30;:::i;:::-;5639:7;5629:17;;;5135:517;;;;;:::o;5657:729::-;5752:6;5760;5768;5776;5784;5837:3;5825:9;5816:7;5812:23;5808:33;5805:53;;;5854:1;5851;5844:12;5805:53;5893:9;5880:23;5912:31;5937:5;5912:31;:::i;:::-;5962:5;6040:2;6025:18;;6012:32;;-1:-1:-1;6143:2:1;6128:18;;6115:32;;6246:2;6231:18;;6218:32;;-1:-1:-1;6349:3:1;6334:19;6321:33;;-1:-1:-1;5657:729:1;-1:-1:-1;;;5657:729:1:o;6583:637::-;6773:2;6785:21;;;6855:13;;6758:18;;;6877:22;;;6725:4;;6956:15;;;6930:2;6915:18;;;6725:4;6999:195;7013:6;7010:1;7007:13;6999:195;;;7078:13;;-1:-1:-1;;;;;7074:39:1;7062:52;;7143:2;7169:15;;;;7134:12;;;;7110:1;7028:9;6999:195;;;-1:-1:-1;7211:3:1;;6583:637;-1:-1:-1;;;;;6583:637:1:o;7457:871::-;7561:6;7569;7577;7585;7593;7601;7654:3;7642:9;7633:7;7629:23;7625:33;7622:53;;;7671:1;7668;7661:12;7622:53;7710:9;7697:23;7729:31;7754:5;7729:31;:::i;:::-;7779:5;-1:-1:-1;7836:2:1;7821:18;;7808:32;7849:33;7808:32;7849:33;:::i;:::-;7457:871;;7901:7;;-1:-1:-1;;;;7981:2:1;7966:18;;7953:32;;8084:2;8069:18;;8056:32;;8187:3;8172:19;;8159:33;;-1:-1:-1;8291:3:1;8276:19;;;8263:33;;-1:-1:-1;7457:871:1:o;8333:1013::-;8446:6;8454;8462;8470;8478;8486;8494;8547:3;8535:9;8526:7;8522:23;8518:33;8515:53;;;8564:1;8561;8554:12;8515:53;8603:9;8590:23;8622:31;8647:5;8622:31;:::i;:::-;8672:5;-1:-1:-1;8729:2:1;8714:18;;8701:32;8742:33;8701:32;8742:33;:::i;:::-;8794:7;-1:-1:-1;8853:2:1;8838:18;;8825:32;8866:33;8825:32;8866:33;:::i;:::-;8333:1013;;;;-1:-1:-1;8918:7:1;;8998:2;8983:18;;8970:32;;-1:-1:-1;9101:3:1;9086:19;;9073:33;;9205:3;9190:19;;9177:33;;-1:-1:-1;9309:3:1;9294:19;;;9281:33;;-1:-1:-1;8333:1013:1;-1:-1:-1;;8333:1013:1:o;9351:127::-;9412:10;9407:3;9403:20;9400:1;9393:31;9443:4;9440:1;9433:15;9467:4;9464:1;9457:15;9483:127;9544:10;9539:3;9535:20;9532:1;9525:31;9575:4;9572:1;9565:15;9599:4;9596:1;9589:15;9615:344;9682:2;9676:9;9724:3;9712:16;;9758:18;9743:34;;9779:22;;;9740:62;9737:185;;;9844:10;9839:3;9835:20;9832:1;9825:31;9879:4;9876:1;9869:15;9907:4;9904:1;9897:15;9737:185;9938:2;9931:22;9615:344;:::o;9964:132::-;10040:13;;10062:28;10040:13;10062:28;:::i;:::-;9964:132;;;:::o;10101:987::-;10204:6;10264:3;10252:9;10243:7;10239:23;10235:33;10280:2;10277:22;;;10295:1;10292;10285:12;10277:22;-1:-1:-1;10337:17:1;;:::i;:::-;10384:9;10378:16;10403:33;10428:7;10403:33;:::i;:::-;10445:22;;10512:2;10497:18;;10491:25;10525:33;10491:25;10525:33;:::i;:::-;10585:2;10574:14;;10567:31;10643:2;10628:18;;10622:25;10691:4;10678:18;;10666:31;;10656:59;;10711:1;10708;10701:12;10656:59;10742:2;10731:14;;10724:31;10787:46;10829:2;10814:18;;10787:46;:::i;:::-;10782:2;10771:14;;10764:70;10900:3;10885:19;;;10879:26;10921:15;;;10914:32;11012:3;10997:19;;;10991:26;11033:15;;;11026:32;;;;-1:-1:-1;10775:5:1;10101:987;-1:-1:-1;10101:987:1:o;11093:230::-;11163:6;11216:2;11204:9;11195:7;11191:23;11187:32;11184:52;;;11232:1;11229;11222:12;11184:52;-1:-1:-1;11277:16:1;;11093:230;-1:-1:-1;11093:230:1:o;11328:245::-;11395:6;11448:2;11436:9;11427:7;11423:23;11419:32;11416:52;;;11464:1;11461;11454:12;11416:52;11496:9;11490:16;11515:28;11537:5;11515:28;:::i;11578:251::-;11648:6;11701:2;11689:9;11680:7;11676:23;11672:32;11669:52;;;11717:1;11714;11707:12;11669:52;11749:9;11743:16;11768:31;11793:5;11768:31;:::i;11834:179::-;11912:13;;11965:22;11954:34;;11944:45;;11934:73;;12003:1;12000;11993:12;12018:571;12121:6;12129;12137;12145;12153;12206:3;12194:9;12185:7;12181:23;12177:33;12174:53;;;12223:1;12220;12213:12;12174:53;12246:39;12275:9;12246:39;:::i;:::-;12325:2;12310:18;;12304:25;12391:2;12376:18;;12370:25;12485:2;12470:18;;12464:25;12236:49;;-1:-1:-1;12304:25:1;;-1:-1:-1;12370:25:1;-1:-1:-1;12464:25:1;-1:-1:-1;12534:49:1;12578:3;12563:19;;12534:49;:::i;:::-;12524:59;;12018:571;;;;;;;;:::o;12594:127::-;12655:10;12650:3;12646:20;12643:1;12636:31;12686:4;12683:1;12676:15;12710:4;12707:1;12700:15;12726:128;12793:9;;;12814:11;;;12811:37;;;12828:18;;:::i;:::-;12726:128;;;;:::o;12859:127::-;12920:10;12915:3;12911:20;12908:1;12901:31;12951:4;12948:1;12941:15;12975:4;12972:1;12965:15;13296:125;13361:9;;;13382:10;;;13379:36;;;13395:18;;:::i;14290:905::-;14390:6;14450:2;14438:9;14429:7;14425:23;14421:32;14465:2;14462:22;;;14480:1;14477;14470:12;14462:22;-1:-1:-1;14549:2:1;14543:9;14591:2;14579:15;;14624:18;14609:34;;14645:22;;;14606:62;14603:185;;;14710:10;14705:3;14701:20;14698:1;14691:31;14745:4;14742:1;14735:15;14773:4;14770:1;14763:15;14603:185;14804:2;14797:22;14860:16;;14885:21;;14951:2;14936:18;;14930:25;14964:30;14930:25;14964:30;:::i;:::-;15022:2;15010:15;;15003:32;15080:2;15065:18;;15059:25;15093:30;15059:25;15093:30;:::i;:::-;15151:2;15139:15;;15132:32;15143:6;14290:905;-1:-1:-1;;;14290:905:1:o;15200:168::-;15273:9;;;15304;;15321:15;;;15315:22;;15301:37;15291:71;;15342:18;;:::i;15373:217::-;15413:1;15439;15429:132;;15483:10;15478:3;15474:20;15471:1;15464:31;15518:4;15515:1;15508:15;15546:4;15543:1;15536:15;15429:132;-1:-1:-1;15575:9:1;;15373:217::o

Swarm Source

ipfs://290a04e776ce97ada5d767820102edf4b9dfa7dbece0ac19525ff6987afd9344

Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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