MON Price: $0.019049 (-0.25%)

Contract

0x830D40CDFdc494BC1A2729a7381bfCe44326c944

Overview

MON Balance

Monad Chain LogoMonad Chain LogoMonad Chain Logo0 MON

MON Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Add Position Man...446263062025-12-26 19:15:3929 days ago1766776539IN
0x830D40CD...44326c944
0 MON0.01122316102.25
Remove Position ...446262752025-12-26 19:15:2729 days ago1766776527IN
0x830D40CD...44326c944
0 MON0.00722334102.25
Add Position Man...427571282025-12-18 3:03:4437 days ago1766027024IN
0x830D40CD...44326c944
0 MON0.0112708102.68402032
Remove Position ...427571172025-12-18 3:03:3937 days ago1766027019IN
0x830D40CD...44326c944
0 MON0.007254102.68402032
Update Token Con...400873532025-12-05 16:51:2950 days ago1764953489IN
0x830D40CD...44326c944
0 MON0.05120232104
Update Token Con...394319122025-12-02 15:39:4953 days ago1764689989IN
0x830D40CD...44326c944
0 MON0.05204305104
Update Token Con...394317592025-12-02 15:38:4753 days ago1764689927IN
0x830D40CD...44326c944
0 MON0.0512044104
Set Mint Paused379556922025-11-25 18:34:2360 days ago1764095663IN
0x830D40CD...44326c944
0 MON0.00744732103.05
Set Mint Paused379556862025-11-25 18:34:2160 days ago1764095661IN
0x830D40CD...44326c944
0 MON0.00744732103.05
Update Token Con...378329342025-11-25 4:50:5960 days ago1764046259IN
0x830D40CD...44326c944
0 MON0.05925369103.74
Update Token Con...378329292025-11-25 4:50:5760 days ago1764046257IN
0x830D40CD...44326c944
0 MON0.04696548103.74
Set Mint Paused378329242025-11-25 4:50:5560 days ago1764046255IN
0x830D40CD...44326c944
0 MON0.00749749103.74
Set Mint Paused378329202025-11-25 4:50:5360 days ago1764046253IN
0x830D40CD...44326c944
0 MON0.00749749103.74
List Tokens378329152025-11-25 4:50:5160 days ago1764046251IN
0x830D40CD...44326c944
0 MON0.08622059103.74
Add Position Man...378328632025-11-25 4:50:3060 days ago1764046230IN
0x830D40CD...44326c944
0 MON0.0113867103.74

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MarketManagerIsolated

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, BSL 1.1 license
/**
 *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/IActionRegistry.sol

interface IActionRegistry {
    /// @notice Checks whether `user` has transferability enabled or disabled
    ///         for their tokens.
    /// @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);

    /// @notice Checks whether `user` has disabled creating new delegations
    ///         for actions inside Curvance.
    /// @param user The address to check whether delegation is enabled or
    ///             disabled for.
    /// @return result Indicates whether `user` has delegation disabled
    ///                or not, true = disabled, false = not disabled.
    function checkNewDelegationDisabled(
        address user
    ) external view returns (bool result);

    /// @notice Returns `user`'s approval index.
    /// @dev The approval index is a way to revoke approval on all tokens,
    ///      and features at once if a malicious delegation was allowed by
    ///      `user`.
    /// @param user The user to check delegated approval index for.
    /// @return result The `user`'s current approval index value.
    function userApprovalIndex(
        address user
    ) external view returns (uint256 result);
}

// 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/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/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/ERC165.sol

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

// 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/market/isolated/LiquidityManagerIsolated.sol

/// @title Curvance Liquidity Manager.
/// @notice Calculates liquidity of an account in various positions.
/// @dev NOTE: Only use this as an abstract contract as no account
///            data is written here.
abstract contract LiquidityManagerIsolated {
    /// TYPES ///

    /// @notice Storage structure for Account data involving liquidity
    ///         positions, and pending redemption cooldown.
    /// @param cooldownTimestamp Timestamp corresponding to when the last time
    ///                          `account` performed a liquidity focused
    ///                          action, which activates a cooldown period on
    ///                          redemptions/repayment/collateral removal.
    /// @param assets Array containing all Curvance tokens an account has
    ///               active liquidity positions in.
    struct AccountData {
        uint256 cooldownTimestamp;
        address[] assets;
    }

    /// @notice Storage configuration for how a Curvance token should behave
    ///         in the liquidity manager.
    /// @param isListed Whether or not this Curvance token is listed.
    /// @dev false = unlisted; true = listed.
    /// @param mintPaused Whether token minting is paused.
    /// @dev Token Address => 0 or 1 = unpaused; 2 = paused.
    /// @param collateralizationPaused Whether token collateralization is paused.
    /// @dev Token Address => 0 or 1 = unpaused; 2 = paused.
    /// @param borrowPaused Whether token borrowing is paused.
    /// @dev Token Address => 0 or 1 = unpaused; 2 = paused.
    /// @param collRatio The ratio at which this token can be borrowed against
    ///                  when collateralized.
    /// @dev In `BPS`, e.g. 0.8e18 = 80% collateral value borrowable.
    /// @param collReqSoft The collateral requirement where dipping below this
    ///                    will cause a soft liquidation.
    /// @dev In `BPS`, e.g. 1.2e18 = 120% collateral vs debt value.
    /// @param collReqHard The collateral requirement where dipping below
    ///                    this will cause a hard liquidation.
    /// @dev In `BPS`, e.g. 1.1e18 = 110% collateral vs debt value.
    /// @param liqIncBase The base ratio at which this token will be
    ///                   compensated on soft liquidation.
    /// @dev In `BPS`, stored as Incentive + BPS e.g. 1.05e18 = 5% incentive.
    /// @param liqIncCurve The liquidation incentive curve length between
    ///                    soft liquidation to hard liquidation.
    ///                    e.g. 5% base incentive with 8% curve length results
    ///                    in 13% liquidation incentive on hard liquidation.
    /// @dev In `BPS`, e.g. 0.05e18 = 5% maximum additional incentive.
    /// @param liqIncMin The minimum possible liquidation incentive for
    ///                  during an auction.
    /// @dev In `BPS`, stored as Incentive + BPS e.g. 1.03e18 = 3% incentive.
    /// @param liqIncMax The maximum possible liquidation incentive for
    ///                  during an auction.
    /// @dev In `BPS`, stored as Incentive + BPS e.g. 1.07e18 = 7% incentive.
    /// @param closeFactorBase Maximum % that a liquidator can repay when soft
    ///                        liquidating an account.
    /// @dev In `BPS` format, e.g. 0.1e18 = 10% base close factor.
    /// @param closeFactorCurve Curve length between soft liquidation and hard
    ///                         liquidation, should be equal to
    ///                         100% - `closeFactorBase`.
    /// @dev In `BPS` format, e.g. 0.9e18 = 90% distance between
    ///      `closeFactorBase`, and 100%.
    /// @param closeFactorMin The minimum possible close factor for during an
    ///                       auction.
    /// @dev In `BPS` format, e.g. 0.2e18 = 20% minimum close factor.
    /// @param closeFactorMax The maximum possible close factor for during an 
    ///                       auction.
    /// @dev In `BPS` format, e.g. 0.4e18 = 40% maximum close factor.
    struct CurvanceToken {
        bool isListed;
        uint8 mintPaused;
        uint8 collateralizationPaused;
        uint8 borrowPaused;
        uint24 collRatio;
        uint24 collReqSoft;
        uint24 collReqHard;
        uint16 liqIncBase;
        uint16 liqIncCurve;
        uint16 liqIncMin;
        uint16 liqIncMax;
        uint16 closeFactorBase;
        uint16 closeFactorCurve;
        uint16 closeFactorMin;
        uint16 closeFactorMax;
    }

    /// @notice Data structure containing information on hypothetical action
    ///         to execute.
    /// @param cTokenModified The cToken to hypothetically redeem/borrow.
    /// @param redemptionShares The number of tokens to hypothetically redeem,
    ///                         in `shares`.
    /// @param borrowAssets The amount of underlying to hypothetically borrow,
    ///                     in `assets`.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert. We reuse
    ///                            `errorCodeBreakpoint` as a return variable
    ///                            as a garbage collection flag to minimize
    ///                            local variables.
    struct HypotheticalAction {
        address cTokenModified;
        uint256 redemptionShares;
        uint256 borrowAssets;
        uint256 errorCodeBreakpoint;
    }

    /// @notice Data structure returned on liquidation threshold calculation
    ///         containing an accounts collateral values under specific
    ///         (soft liquidation versus hard liquidation) methodology
    ///         that will lead to liquidations.
    /// @param cSoft The account's soft collateral value (collateral adjusted
    ///              by soft requirements).
    /// @param cHard The account's hard collateral value (collateral adjusted
    ///              by hard requirements).
    /// @param debt The account's total outstanding debt.
    struct AccountLiqResult {
        uint256 cSoft;
        uint256 cHard;
        uint256 debt;
    }

    /// @notice Data structure returned on querying a liquidation's current
    ///         configuration based on the auction liquidation system.
    /// @param lFactor The liquidation factor for an account, indicating the
    ///                severity of a liquidation, between 0 and WAD.
    /// @param debtBalance An account's outstanding debt to a cToken.
    /// @param liqInc The ratio at which debt repayment will be compensated on
    ///               liquidation.
    /// @param liqIncBase The base ratio at which this token will be
    ///                   compensated on soft liquidation.
    /// @param liqIncCurve The liquidation incentive curve length between soft
    ///                 liquidation to hard liquidation.
    /// @param closeFactor Maximum debt % that a liquidator can repay
    ///                    during a liquidation of an account.
    /// @param closeFactorBase Maximum % that a liquidator can repay when soft
    ///                        liquidating an account.
    /// @param closeFactorCurve Curve length between soft liquidation and hard
    ///                         liquidation, should be equal to
    ///                         100% - `closeFactorBase`.
    struct AccountLiqData {
        uint256 lFactor;
        uint256 debtBalance;
        uint256 liqInc;
        uint256 liqIncBase;
        uint256 liqIncCurve;
        uint256 closeFactor;
        uint256 closeFactorBase;
        uint256 closeFactorCurve;
    }

    /// @notice Data structure returned on querying a liquidation's current
    ///         configuration based on the aggregate liquidation system.
    /// @param collateralToken The address of the Curvance token to be seized
    ///                        during in the liquidation.
    /// @param collateralExchangeRate The exchange rate of `collateralToken`'s
    ///                               underlying token to the cToken itself.
    /// @param collateralReqSoft The collateral requirement where dipping
    ///                          below this will cause a soft liquidation.
    /// @param collateralReqHard The collateral requirement where dipping
    ///                          below this will cause a hard liquidation.
    /// @param collateralSharesPrice The current price of `collateralToken`,
    ///                              in `shares`.
    /// @param collateralDecimals The decimals that `collateralToken` is
    ///                           measured in.
    /// @param debtToken The address of the Curvance token to be repaid during
    ///                  the liquidation.
    /// @param debtDecimals The decimals that `debtToken` is measured in.
    /// @param debtUnderlyingPrice The current price of the underlying token
    ///                            of `debtToken`, in `assets`.
    /// @param auctionBuffer The current buffer that `cSoft` and `cHard` are 
    ///                      multiplied against, 10 bps, or 0 if not an 
    ///                      auction-based liquidation.
    struct TokenLiqData {
        address collateralToken;
        uint256 collateralReqSoft;
        uint256 collateralReqHard;
        uint256 collateralSharesPrice;
        uint256 collateralDecimals;
        address debtToken;
        uint256 debtDecimals;
        uint256 debtUnderlyingPrice;
        uint256 auctionBuffer;
    }

    /// CONSTANTS ///

    /// @notice Maximum collateralization ratio, in `BPS`.
    /// @dev 9750 = 97.50%.
    ///      ~40x leverage calculated from: 1 / (1 - Collateralization Ratio).
    uint256 public constant MAX_COLL_RATIO_CORRELATED = 9750;
    /// @notice Maximum collateralization ratio, in `BPS`.
    /// @dev 9696 = 96.96%.
    ///      ~33x leverage calculated from: 1 / (1 - Collateralization Ratio).
    uint256 public constant MAX_COLL_RATIO_UNCORRELATED = 9696;
    /// @notice Buffer to ensure orderflow auction-based liquidations have
    ///         priority versus basic liquidations, for correlated assets,
    ///         in `BPS`.
    /// @dev 9990 = 99.9%. Multiplied then divided by `BPS` = 10 bps buffer
    ///                    auction liquidation priority for correlated assets.
    uint256 public constant AUCTION_BUFFER_CORRELATED = 9990;
    /// @notice Buffer to ensure orderflow auction-based liquidations have
    ///         priority versus basic liquidations, for uncorrelated assets,
    ///         in `BPS`.
    /// @dev 9950 = 99.5%. Multiplied then divided by `BPS` = 50 bps buffer
    ///                    auction liquidation priority for uncorrelated assets.
    uint256 public constant AUCTION_BUFFER_UNCORRELATED = 9950;
    /// @notice Minimum Liquidity buffer provided to maximally leveraged users
    ///         before a liquidation can occur. This value is adjusted by
    ///         `AUCTION_BUFFER` to calculate `MIN_LIQUIDATION_BUFFER_REQUIRED`
    ///         inside a market, in `BPS`.
    /// @dev 9960 = 0.4% buffer. An additional 40 basis points buffer before a
    ///      liquidation can trigger (Then modified by `AUCTION_BUFFER`).
    uint256 public constant EXTRA_BUFFER_BEFORE_LIQUIDATION = 9960;

    /// @notice Enforced buffer provided to maximally leveraged users before a
    ///         liquidation can occur, stored in `BPS`^2.
    /// @dev 99,500,000 = ~99.5% bps^2 = 0.5% buffer. An additional 50 basis
    ///      points buffer before a liquidation can trigger.
    uint256 public immutable MIN_LIQUIDATION_BUFFER;
    /// @notice Whether this market is for correlated assets or not, this
    ///         impacts auction buffer and maximum theoretical
    ///         collateralization ratio allowed.
    bool public immutable IS_CORRELATED_ASSET_MARKET;
    /// @notice Maximum collateralization ratio ratio allowed for any asset
    ///         inside this market, in `BPS`, e.g. 9696 = 96.96%, or ~33x
    ///         leverage calculated from: 1 / (1 - Collateralization Ratio).
    uint256 public immutable MAX_COLL_RATIO;
    /// @notice Buffer to ensure auction-based liquidations have priority
    ///         versus basic liquidations by multiplying a user's active
    ///         collateral $ value by `AUCTION_BUFFER` then dividing by `BPS`.
    ///         Denominated in `BPS`, e.g. 9990 = 99.9% -> 10 bps priority.
    uint256 public immutable AUCTION_BUFFER;
    /// @notice Minimum excess collateral requirement before soft liquidation
    ///         can occur, in `BPS`, e.g. 9950 = 99.5% -> 50 bps drop before a
    ///         liquidation can step in, used during `updateTokenConfig`.
    uint256 public immutable MIN_LIQUIDATION_BUFFER_REQUIRED;
    /// @notice Minimum loan size allowed inside Curvance that can be created
    ///         from a new line of credit inside a market.
    /// @dev This restriction is to minimize the potential of debt positions
    ///      being created that cannot not be profitably closed.
    uint256 public immutable MIN_LOAN_SIZE;
    /// @notice Curvance DAO hub.
    ICentralRegistry public immutable centralRegistry;

    /// STORAGE ///

    /// @notice Curvance token data including listing status,
    ///         action enablement, collateralization configuration,
    ///         and liquidation configuration.
    /// @dev Curvance Token Address => CurvanceToken struct.
    mapping(address => CurvanceToken) internal _tokenConfig;

    // ACCOUNT LIQUIDITY DATA //

    /// @notice Value that indicates whether an account has an
    ///         active position in the token.
    /// @dev Curvance Token address => Account address => Active position
    ///      status. 0 or 1 for no; 2 for yes.
    mapping(address => mapping(address => uint256)) public accountPositions;
    /// @notice Assets and redemption cooldown data for an account.
    /// @dev Account => AccountData struct.
    mapping(address => AccountData) public accountAssets;

    /// ERRORS ///

    error LiquidityManager__InsufficientLoanSize();
    error LiquidityManager__PriceError();

    /// @param cr The address of the Protocol Central Registry.
    /// @param minLoanSize The minimum active loan size for this isolated
    ///                    market, must be between $10 - $100 in `WAD`.
    /// @param isCorrelatedMarket Whether this market is for correlated assets
    ///                           or not, this impacts auction buffer and
    ///                           maximum theoretical collateralization
    ///                           ratio allowed.
    constructor(
        ICentralRegistry cr,
        uint256 minLoanSize,
        bool isCorrelatedMarket
    ) {
        if (minLoanSize < 10e18 || minLoanSize > 100e18) {
            revert LiquidityManager__InsufficientLoanSize();
        }
        CentralRegistryLib._isCentralRegistry(cr);

        centralRegistry = cr;
        MIN_LOAN_SIZE = minLoanSize;
        IS_CORRELATED_ASSET_MARKET = isCorrelatedMarket;
        MAX_COLL_RATIO = isCorrelatedMarket ?
            MAX_COLL_RATIO_CORRELATED :
            MAX_COLL_RATIO_UNCORRELATED;
        AUCTION_BUFFER = isCorrelatedMarket ? AUCTION_BUFFER_CORRELATED :
            AUCTION_BUFFER_UNCORRELATED;
        
        // Calculates the minimum liquidation buffer the market needs to give
        // users before liquidation. E.g. 9960 extra buffer * 10 bps auction
        // buffer = 9960 * 9990 = 99.5 bps^2 or ~50 bps buffer from max
        // leverage to liquidation.
        MIN_LIQUIDATION_BUFFER =
            EXTRA_BUFFER_BEFORE_LIQUIDATION * AUCTION_BUFFER;
    }

    /// @notice Determine `account`'s current status between collateral,
    ///         debt, and additional liquidity.
    /// @param account The account to determine liquidity for.
    /// @return collateral Total value of `account`'s collateral across
    ///                    all positions.
    /// @return maxDebt The maximum amount of debt `account`
    ///                 could take on based on `collateral`.
    /// @return debt Total value of `account`'s current outstanding
    ///              debt across all positions.
    function _statusOf(address account) internal returns (
        uint256 collateral,
        uint256 maxDebt,
        uint256 debt
    ) {
        (
            AccountSnapshot[] memory snapshots,
            uint256[] memory prices,
            uint256 numAssets
        ) = _assetDataOf(account, BAD_SOURCE);
        AccountSnapshot memory snap;

        for (uint256 i; i < numAssets; ++i) {
            snap = snapshots[i];

            if (snap.isCollateral) {
                uint256 collateralValue = _assetValue(
                    snap.collateralPosted,
                    prices[i],
                    10 ** snap.decimals,
                    true
                );
                collateral += collateralValue;
                maxDebt += _mulDiv(
                    collateralValue,
                    _tokenConfig[snap.asset].collRatio,
                    BPS
                );
            } else {
                // If they have a debt balance, increment their debt.
                if (snap.debtBalance > 0) {
                    debt += _assetValue(
                        snap.debtBalance,
                        prices[i],
                        10 ** snap.decimals,
                        false
                    );
                }
            }
        }
    }

    /// @notice Calculates hypothetical liquidity for an account after a
    ///         potential action such as redemption and borrowing.
    /// @param account The address of the account being evaluated for `action`
    ///                being done.
    /// @param action Instructions for a hypothetical action containing:
    ///               cTokenModified The address of the token being modified
    ///                              by the action.
    ///               redemptionShares The amount of tokens to hypothetically
    ///                                redeem, in `shares`.
    ///               borrowAssets The amount of underlying to hypothetically
    ///                            borrow, in `assets`.
    ///               errorCodeBreakpoint The error code that will cause
    ///                                   liquidity operations to revert.
    /// @return uint256 Excess collateral capacity after the action.
    ///         uint256 Shortfall in collateral capacity after the action.
    function _hypotheticalLiquidityOf(
        address account,
        HypotheticalAction memory action
    ) internal returns (uint256, uint256) {
        (
            AccountSnapshot[] memory snapshots,
            uint256[] memory prices,
            uint256 numAssets
        ) = _assetDataOf(account, action.errorCodeBreakpoint);
        AccountSnapshot memory snap;
        uint256 maxDebt;
        uint256 newDebt;
        
        for (uint256 i; i < numAssets; ++i) {
            snap = snapshots[i];

            // Generally `isCollateral` tells us if an entry is collateral or
            // debt, but, on a fresh borrow position snapshot misreports
            // `isCollateral` as true until its action is fully processed
            // because debtBalance still equals 0 at getSnapshotUpdated level.
            if (
                action.cTokenModified == snap.asset && snap.isCollateral &&
                action.borrowAssets > 0
            ) {
                uint256 errorCode;
                (prices[i], errorCode) =
                    CommonLib._oracleManager(centralRegistry).
                        getPrice(snap.underlying, true, false);

                if (errorCode >= action.errorCodeBreakpoint) {
                    revert LiquidityManager__PriceError();
                }

                // Adjust `isCollateral` to be false since this is a debt
                // entry not a collateral entry.
                delete snap.isCollateral;
            }

            if (snap.isCollateral) {
                // If the user is redeeming collateral, offset their
                // collateral posted.
                if (action.cTokenModified == snap.asset) {
                    snap.collateralPosted -= action.redemptionShares;
                }

                // CASE: There is no collateral posted. Either the position
                // will be closed through a full redemption, or the user
                // already had their position closed via liquidation.
                if (snap.collateralPosted > 0) {
                    // CASE: There is collateral posted in this cToken,
                    // the user can take on more debt from lenders.
                    maxDebt += _mulDiv(
                        _assetValue(
                            snap.collateralPosted,
                            prices[i],
                            10 ** snap.decimals,
                            true
                        ),
                        _tokenConfig[snap.asset].collRatio,
                        BPS
                    );
                }
            } else {
                if (action.cTokenModified == snap.asset) {
                    snap.debtBalance += action.borrowAssets;
                }

                // CASE: There is no outstanding debt, clean up the position
                // entry as the user was liquidated, otherwise add to the
                // user's outstanding debt.
                if (snap.debtBalance > 0) {
                    // CASE: There is outstanding debt to lenders, add it to
                    // `newDebt` to check against `maxDebt`.
                    newDebt += _assetValue(
                        snap.debtBalance,
                        prices[i],
                        10 ** snap.decimals,
                        false
                    );

                    // Check `newDebt` to make sure the loan size will not be
                    // too small for us to allow issuing the loan.
                    if (newDebt < MIN_LOAN_SIZE) {
                        revert LiquidityManager__InsufficientLoanSize();
                    }
                }
            }
        }

        // Returns excess liquidity on hypothetical positions.
        if (maxDebt > newDebt) {
            return (maxDebt - newDebt, 0);
        }

        // Returns shortfall on hypothetical positions.
        return (0, newDebt - maxDebt);
    }

    /// @notice Evaluates an account's collateral and debt positions to
    ///         determine liquidation factor using cached data.
    /// @param account The address of the account being evaluated for
    ///                 liquidation.
    /// @param tData A TokenLiqData struct containing:
    ///              collateralToken The token which is used as collateral
    ///                               by `account` and may be seized.
    ///              collateralExchangeRate The exchange rate of
    ///                                     `collateralToken` underlying token
    ///                                     to `collateralToken`.
    ///              collateralReqSoft The collateral requirement where
    ///                                dipping below this will cause a soft
    ///                                liquidation.
    ///              collateralReqHard The collateral requirement where
    ///                                dipping below this will cause a hard
    ///                                liquidation.
    ///              collateralUnderlyingPrice The current price of the
    ///                                        underlying token of
    ///                                        `collateralToken`.
    ///              collateralDecimals The decimals that `collateralToken`
    ///                                 is measured in.
    ///              debtToken The token to potentially repay which has
    ///                        outstanding debt by `account`.
    ///              debtDecimals The decimals that `debtToken` is measured
    ///                           in.
    ///              debtUnderlyingPrice The current price of the underlying
    ///                                  token of `debtToken`.
    ///              auctionBuffer The current buffer that `cSoft` and `cHard` 
    ///                            are multiplied against, 10 bps, or 0 if not
    ///                            an auction-based liquidation.
    ///  @return lFactor The liquidation factor where:
    ///                  0: No liquidation (account is healthy).
    ///                  1 to WAD - 1: Soft liquidation (partial liquidation
    ///                                allowed).
    ///                  WAD: Hard liquidation (full liquidation, possibly
    ///                       including bad debt).
    ///  @return debt The current debt position in `liqData.debtToken` for
    ///               `account`.
    function _liquidationValuesOf(
        address account,
        TokenLiqData memory tData
    ) internal view returns (uint256 lFactor, uint256 debt) {
        AccountLiqResult memory r;
        address[] memory assets = accountAssets[account].assets;

        address asset;
        uint256 numAssets = assets.length;
        for (uint256 i; i < numAssets; ) {
            asset = assets[i++];
            if (asset == tData.collateralToken) {
                (r.cSoft, r.cHard) = _addLiquidationValues(
                    tData.collateralDecimals,
                    tData.collateralReqSoft,
                    tData.collateralReqHard,
                    tData.collateralSharesPrice,
                    ICToken(tData.collateralToken).collateralPosted(account),
                    r.cSoft,
                    r.cHard
                );
            } else {
                // If the asset is not `collateralToken`, the asset must
                // be the `debtToken` debt position because this market
                // only has two tokens.
                debt =
                    IBorrowableCToken(tData.debtToken).debtBalance(account);

                // If they have a debt balance, document additional
                // collateral requirements.
                if (debt > 0) {
                    r.debt += _assetValue(
                        debt,
                        tData.debtUnderlyingPrice,
                        tData.debtDecimals,
                        false
                    );
                }
            }
        }
        
        // If this is a potential liquidation from an auction, apply the
        // auction buffer to collateral values, discounting collateral values.
        if (tData.auctionBuffer != 0) {
            r.cSoft = _mulDiv(r.cSoft, tData.auctionBuffer, BPS);
            r.cHard = _mulDiv(r.cHard, tData.auctionBuffer, BPS);
        }

        // Get `account` lFactor.
        if (r.cSoft >= r.debt) {
            // Indicates no liquidation.
            lFactor = 0;
        } else {
            lFactor = r.debt >= r.cHard ? WAD // Indicates hard liquidation.
            // Indicates soft liquidation, we round up here in favor of the
            // protocol, we know that we wont run into a value > WAD due to
            // cHard being at least 1 higher than debt.
            : FixedPointMathLib.mulDivUp(r.debt - r.cSoft, WAD, r.cHard - r.cSoft);
        }
    }

    /// @notice Retrieves the prices and account data of multiple assets
    ///         inside this market.
    /// @param account The account to retrieve data for.
    /// @param errorCodeBreakpoint The error code that will cause liquidity
    ///                            operations to revert.
    /// @return Assets data for `account`.
    /// @return Prices for `account` assets.
    /// @return The number of assets `account` is in.
    function _assetDataOf(address account, uint256 errorCodeBreakpoint)
        internal
        returns (AccountSnapshot[] memory, uint256[] memory, uint256) {
        return CommonLib._oracleManager(centralRegistry).getPricesForMarket(
            account,
            accountAssets[account].assets,
            errorCodeBreakpoint
        );
    }

    /// @notice Calculates an assets value based on its `price`,
    ///         `amount`, and adjusts for decimals.
    /// @param amount The asset amount to calculate asset value from.
    /// @param price The asset price to calculate asset value from, in `WAD`.
    /// @param decimals The asset decimals to adjust asset value
    ///                 into proper form.
    /// @param increasesCollateral Whether the asset adds positive value or
    ///        not to the liquidity check, we round down when increasing
    ///        collateral value and round up when increasing collateral
    ///        value/increasing debt.
    /// @return The calculated asset value.
    function _assetValue(
        uint256 amount,
        uint256 price,
        uint256 decimals,
        bool increasesCollateral
    ) internal pure returns (uint256) {
        if (increasesCollateral) {
            return _mulDiv(amount, price, decimals);
        }

        return FixedPointMathLib.mulDivUp(amount, price, decimals);
    }

    /// @notice Calculates and adds soft and hard collateral values for
    ///         liquidation assessment with cached data.
    /// @param decimals The number of decimals for the collateral token.
    /// @param collReqSoft The soft collateral requirement ratio, in WAD.
    /// @param collReqHard The hard collateral requirement ratio, in WAD.
    /// @param price The price of the underlying asset, in `WAD`.
    /// @param collateralPosted The amount of collateral token posted as
    ///                         collateral by the account.
    /// @param softSumPrior The previous sum of soft collateral values.
    /// @param hardSumPrior The previous sum of hard collateral values.
    /// @return softSum The updated sum of soft collateral values.
    /// @return hardSum The updated sum of hard collateral values.
    function _addLiquidationValues(
        uint256 decimals,
        uint256 collReqSoft,
        uint256 collReqHard,
        uint256 price,
        uint256 collateralPosted,
        uint256 softSumPrior,
        uint256 hardSumPrior
    ) internal pure returns (uint256 softSum, uint256 hardSum) {
        uint256 assetValue = _assetValue(
            collateralPosted,
            price,
            decimals,
            true
        ) * BPS;

        softSum = softSumPrior + (assetValue / collReqSoft);
        hardSum = hardSumPrior + (assetValue / collReqHard);
    }

    /// @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) {
        z = FixedPointMathLib.mulDiv(x, y, d);
    }

    /// @dev Internal helper for reverting efficiently.
    function _revert(uint256 s) internal pure {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, s)
            revert(0x1c, 0x04)
        }
    }
}

// contracts/market/isolated/MarketManagerIsolated.sol

/// @title Curvance DAO Market Manager.
/// @notice Manages risk within the Curvance DAO markets.
/// @dev Curvance Market Managers are built as "thesis driven" micro
///      ecosystems. This means that a market may be focused specifically
///      on interest-bearing stablecoins, or bluechip long market exposure,
///      volatile LP tokens for a particular dex or perpetual platform. This
///      minimizes systemic risk by having many market managers with unique
///      opportunities and risk profiles.
///
///      All management of token actions are managed by the Market Manager.
///      These tokens are collectively referred to as Curvance tokens,
///      or cTokens. Each market has a maximum number of supportable assets
///      this is to minimize systemic risk and gas costs on liquidity checks.
///
///      Curvance offers the ability to store unlimited tokens inside Curvance
///      token contracts while restricting the scale of exogenous risk.
///      Every collateral asset has a "Collateral Cap", measured in shares.
///      As collateral is posted, the `collateralPosted` invariant increases,
///      and is compared to `collateralCaps`. By measuring collateral posted
///      in shares, this allows collateral caps to grow proportionally with
///      any auto compounding mechanism strategy attached to the token.
///
///      It is important to note that, in theory, collateral caps can be
///      decreased below current market collateral posted levels. This would
///      restrict the addition of new exogenous risk being added to the
///      system, but will not result in forced unwinding of user positions.
///
///      Curvance also employs a 20-minute minimum duration of posting of
///      collateral and borrowing of tokens. This restriction improves
///      the security model of Curvance and allows for more advanced
///      interest rate methodology.
///
///      Additionally, a new "Dynamic Liquidation Engine" or DLE
///      allows for more nuanced position management inside the system.
///      The DLE facilitates aggressive asset support and elevated
///      collateralization ratios paired with reduced minimum liquidation
///      penalties. In periods of low volatility, users will experience soft
///      liquidations. But, when volatility is elevated, users may experience
///      more aggressive or complete liquidation of positions.
///
///      Bad debt is minimized via a "Bad Debt Socialization" system.
///      When a user's debt is greater than their collateral assets,
///      the entire user's account can be liquidated with lenders paying any
///      collateral shortfall.
///
contract MarketManagerIsolated is
    LiquidityManagerIsolated,
    IMarketManager,
    ERC165,
    Multicall
{
    /// TYPES ///

    struct TokenConfig {
        address cToken;
        uint256 collRatio;
        uint256 collReqSoft;
        uint256 collReqHard;
        uint256 liqIncBase;
        uint256 liqIncHard;
        uint256 liqIncMin;
        uint256 liqIncMax;
        uint256 closeFactorBase;
        uint256 closeFactorMin;
        uint256 closeFactorMax;
        uint256 collateralCap;
        uint256 debtCap;
    }

    /// CONSTANTS ///

    /// @notice Maximum collateral requirement to avoid liquidation, in `BPS`.
    /// @dev 23400 = 234%. Resulting in 1 / (BPS + 2.34 BPS),
    ///      or ~30% maximum LTV soft liquidation level.
    uint256 public constant MAX_COLLATERAL_REQUIREMENT = 23400;
    /// @notice Minimum excess collateral requirement on top of liquidation
    ///         incentives, in `BPS`.
    /// @dev 100 = 1.0%.
    uint256 public constant MIN_EXCESS_COLL_REQUIRED = 100;
    /// @notice Minimum excess collateral requirement before soft liquidation
    ///         can occur, in `BPS`.
    /// @notice The maximum liquidation incentive, in `BPS`.
    /// @dev 3000 = 30%.
    uint256 public constant MAX_LIQUIDATION_INCENTIVE = 3000;
    /// @notice The maximum base cFactor, in `BPS`.
    /// @dev 5000 = 50%. NOTE: This can NEVER be changed to 100% or offchain
    ///      parameters can be unintentionally ignored.
    uint256 public constant MAX_BASE_CFACTOR = 5000;
    /// @notice The minimum base cFactor, in `BPS`.
    /// @dev 1000 = 10%.
    uint256 public constant MIN_BASE_CFACTOR = 1000;
    /// @notice Minimum hold time to minimize external risks, in seconds.
    /// @dev 20 minutes = 1,200 seconds.
    ///      The 20 minute holding period is intentionally set so that every
    ///      borrower experiences a minimum 2 interest rate adjustments from a
    ///      standard borrow action (10 minute interest rate adjustment rate).
    uint256 public constant MIN_HOLD_PERIOD = 20 minutes;

    /// @dev Limit for market debt cap to max sure outstanding user debt
    ///      never overflows `outstandingDebt` value inside _debtOf.
    uint256 internal constant _MAX_DEBT_CAP = type(uint136).max;
    /// @dev `bytes4(keccak256(bytes("MarketManager__InvalidParameter()")))`
    uint256 internal constant _INVALID_PARAMETER_SELECTOR = 0x65513fc1;
    /// @dev `bytes4(keccak256(bytes("MarketManager__Unauthorized()")))`
    uint256 internal constant _UNAUTHORIZED_SELECTOR = 0x37cf6ad5;
    /// @dev `bytes4(keccak256(bytes("MarketManager__InvariantError()")))`
    uint256 internal constant _INVARIANT_ERROR_SELECTOR = 0x5518d5cb;
    /// @dev A fixed key to use in transient storage for offchain liquidation
    ///      configuration.
    ///      Key value = `uint256(keccak256(_TRANSIENT_LIQUIDATION_CONFIG_KEY))`.
    ///      Bits Layout:
    ///      - [0..159]   `COLLATERAL_UNLOCKED`.
    ///      - [160..175] `LIQ_INCENTIVE`.
    ///      - [176..191] `CLOSE_FACTOR`.
    uint256 internal constant _TRANSIENT_LIQUIDATION_CONFIG_KEY
        = 0x1966ec4daf81281b2aba49348128e9b155301b8486bde131e0db16a52b730b82;
    uint256 internal constant _BITMASK_COLLATERAL_UNLOCKED = (1 << 160) - 1;
    /// @dev The bit position of `LIQ_INCENTIVE` in
    ///      `_TRANSIENT_LIQUIDATION_CONFIG_KEY`.
    uint256 internal constant _BITPOS_LIQ_INCENTIVE = 160;
    /// @dev The bit position of `CLOSE_FACTOR` in
    ///      `_TRANSIENT_LIQUIDATION_CONFIG_KEY`.
    uint256 internal constant _BITPOS_CLOSE_FACTOR = 176;
    
    /// STORAGE ///

    /// @notice A list of all tokens inside this market for
    ///         offchain querying.
    address[] public tokensListed;

    /// MARKET STATE

    /// @notice Whether market-wide liquidations are paused.
    /// @dev 1 = unpaused; 2 = paused.
    uint8 public liquidationPaused = 1;
    /// @notice Whether market-wide token redemptions are paused.
    /// @dev 1 = unpaused; 2 = paused.
    uint8 public redeemPaused = 1;
    /// @notice Whether market-wide token transfers are paused.
    /// @dev 1 = unpaused; 2 = paused.
    uint8 public transferPaused = 1;

    /// @notice The total amount of `cToken` that can be posted as collateral,
    ///         in shares.
    /// @dev Token Address => Market-wide Collateral Cap, in shares.
    mapping(address => uint256) public collateralCaps;
    /// @notice The total amount of `cToken` underlying that can be borrowed,
    ///         in assets.
    /// @dev Token Address => Market-wide Debt Cap, in assets.
    mapping(address => uint256) public debtCaps;

    /// @notice Whether an address is an authorized position manager or not.
    /// @dev Address => Is an approved position management operator.
    mapping(address => bool) public isPositionManager;

    /// EVENTS ///

    event PositionUpdated(address cToken, address account, bool open);
    event TokenListed(address cToken);
    event TokenConfigUpdated(TokenConfig config);
    event PositionManagerUpdated(address positionManager, bool addPerms);
    event ActionPaused(string action, bool pauseState);
    event TokenActionPaused(address cToken, string action, bool pauseState);

    /// ERRORS ///

    error MarketManager__Unauthorized();
    error MarketManager__UnauthorizedLiquidation();
    error MarketManager__TokenNotListed();
    error MarketManager__Paused();
    error MarketManager__InsufficientCollateral();
    error MarketManager__NoLiquidationAvailable();
    error MarketManager__PriceError();
    error MarketManager__CapReached();
    error MarketManager__MarketManagerMismatch();
    error MarketManager__InvalidParameter();
    error MarketManager__MinimumHoldPeriod();
    error MarketManager__InvariantError();
    
    /// CONSTRUCTOR ///

    /// @param cr The address of the Protocol Central Registry.
    /// @param minLoanSize The minimum active loan size for this isolated
    ///                    market (must be between $10-$100 in WAD).
    /// @param isCorrelatedMarket Whether this market is for correlated assets
    ///                           or not, this impacts auction buffer and
    ///                           maximum theoretical collateralization
    ///                           ratio allowed.
    constructor(
        ICentralRegistry cr,
        uint256 minLoanSize,
        bool isCorrelatedMarket
    ) LiquidityManagerIsolated(cr, minLoanSize, isCorrelatedMarket) {}

    /// EXTERNAL FUNCTIONS ///

    /// @notice Returns whether `cToken` is listed in the lending market.
    /// @param cToken The address of a token to check for listing status.
    /// @return result Whether `cToken` is listed inside this lending market
    ///                or not.
    function isListed(address cToken) external view returns (bool result) {
        result = _tokenConfig[cToken].isListed;
    }

    /// @notice Returns whether minting, collateralization, borrowing of
    ///         `cToken` is disabled.
    /// @param cToken The address of the Curvance token to return
    ///               action statuses of.
    /// @return mintPaused Whether minting `cToken` is paused or not.
    /// @return collateralizationPaused Whether collateralization `cToken`
    ///                                 is paused or not.
    /// @return borrowPaused Whether borrowing `cToken` is paused or not.
    function actionsPaused(address cToken) external view returns (
        bool mintPaused,
        bool collateralizationPaused,
        bool borrowPaused
    ) {
        CurvanceToken storage c = _tokenConfig[cToken];
        mintPaused = c.mintPaused == 2;
        collateralizationPaused = c.collateralizationPaused == 2;
        borrowPaused = c.borrowPaused == 2;
    }

    /// @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, in `BPS`.
    /// @return The collateral requirement where dipping below this
    ///         will cause a soft liquidation, in `BPS`.
    /// @return The collateral requirement where dipping below
    ///         this will cause a hard liquidation, in `BPS`.
    function collConfig(address cToken) external view returns (
         uint256, uint256, uint256
    ) {
        CurvanceToken storage c = _tokenConfig[cToken];
        return (c.collRatio, c.collReqSoft, c.collReqHard);
    }

    /// @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 `BPS`. 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 `BPS`.
    /// @return The maximum possible liquidation incentive for during an
    ///         auction, in `BPS`.
    /// @return Maximum % that a liquidator can repay when soft
    ///         liquidating an account, in `BPS`.
    /// @return Curve length between soft liquidation and hard liquidation,
    ///         should be equal to 100% - `closeFactorBase`, in `BPS`.
    /// @return The minimum possible close factor for during an auction,
    ///         in `BPS`.
    /// @return The maximum possible close factor for during an auction,
    ///         in `BPS`.
    function liquidationConfig(address cToken) external view returns (
        uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
    ) {
        CurvanceToken storage c = _tokenConfig[cToken];
        return (
            c.liqIncBase,
            c.liqIncCurve,
            c.liqIncMin,
            c.liqIncMax,
            c.closeFactorBase,
            c.closeFactorCurve,
            c.closeFactorMin,
            c.closeFactorMax
        );
    }

    /// @notice Helper function for querying the current Curvance tokens listed
    ///         inside this market.
    /// @return r Array containing list of all Curvance token addresses
    ///           listed in this market.
    function queryTokensListed() external view returns (address[] memory r) {
        r = tokensListed;
    }

    /// ACCOUNT SPECIFIC FUNCTIONS ///

    /// @notice Returns the assets `account` has an open position in.
    /// @param account The address of the account to pull assets for.
    /// @return result An array containing the assets `account` has
    ///                positions in.
    function assetsOf(
        address account
    ) external view returns (address[] memory result) {
        result = accountAssets[account].assets;
    }

    /// @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) {
        return _statusOf(account);
    }

    /// @notice Checks if the account should be allowed to mint tokens
    ///         in the given market.
    /// @param cToken The Curvance token to verify mintability of.
    function canMint(address cToken) external view virtual {
        if (_tokenConfig[cToken].mintPaused == 2) {
            revert MarketManager__Paused();
        }

        _checkIsListedToken(cToken);
    }

    /// @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 collateralToken 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 collateralToken,
        address account,
        uint256 newNetCollateral
    ) external {
        _checkIsToken(collateralToken);
        // Can skip token listing check since collateralCaps[collateralToken]
        // can only be set above 0 if `debtToken` is listed already, so we
        // only need to check that `newNetCollateral` != 0 instead, which
        // should be impossible but only costs 2 gas.

        /// @solidity memory-safe-assembly
        assembly {
            if iszero(newNetCollateral) {
                mstore(0x00, _INVARIANT_ERROR_SELECTOR)
                // Return bytes 29-32 for the selector.
                revert(0x1c, 0x04)
            }
        }

        if (_tokenConfig[collateralToken].collateralizationPaused == 2) {
            revert MarketManager__Paused();
        }

        // This also acts as a check that collateralization ratio is > 0,
        // since collateralCaps can only be raised above zero if the
        // its collateralization ratio is > 0.
        if (newNetCollateral > collateralCaps[collateralToken]) {
            revert MarketManager__CapReached();
        }

        // On collateral posting:
        // We need to flip their cooldown flag to prevent flashloan attacks.
        accountAssets[account].cooldownTimestamp = block.timestamp;
        // If `account` does not have a position in `collateralToken`,
        // open one.
        if (accountPositions[collateralToken][account] != 2) {
            accountPositions[collateralToken][account] = 2;
            accountAssets[account].assets.push(collateralToken);

            emit PositionUpdated(collateralToken, account, true);
        }
    }

    /// @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.
    /// @return collateralRedeemed The amount of collateral shares redeemed.
    function canRedeemWithCollateralRemoval(
        address cToken,
        uint256 shares,
        address account,
        uint256 balanceOf,
        uint256 collateralPosted,
        bool forceRedeemCollateral
    ) external returns (uint256 collateralRedeemed) {
        _checkIsToken(cToken);
        if (redeemPaused == 2) {
            revert MarketManager__Paused();
        }

        collateralRedeemed = _canRedeem(
            cToken,
            shares,
            account,
            balanceOf,
            collateralPosted,
            true,
            forceRedeemCollateral
        );
    }

    /// @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 the 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 {
        _canBorrow(cToken, assets, account, newNetDebt);
    }

    /// @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 token to verify borrowability of.
    /// @param assets The amount of underlying the 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 {
        accountAssets[account].cooldownTimestamp = block.timestamp;
        _canBorrow(cToken, assets, account, newNetDebt);
    }

    /// @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 cToken that the account is borrowing.
    /// @param account The address of the account that has just borrowed.
    function notifyBorrow(address cToken, address account) external {
        _checkIsToken(cToken);
        _checkIsListedToken(cToken);

        accountAssets[account].cooldownTimestamp = block.timestamp;
    }

    /// @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 {
        _checkIsToken(cToken);
        _checkIsListedToken(cToken);
        _checkHoldPeriod(account);

        // Validate `account` actually has a debt position in `cToken`.
        if (accountPositions[cToken][account] != 2) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // If `account` is fully repaying their debt, we can skip loan size
        // check.
        if (newNetDebt == 0) {
            return;
        }
        // We round down to favor the protocol here even though typically
        // we use !getLower for debt.
        (uint256 price, uint256 errorCode) =
            CommonLib._oracleManager(centralRegistry)
                .getPrice(debtAsset, true, true);

        // If there an issue pricing we should bubble up an error since we
        // cannot validate the loan size.
        if (errorCode != NO_ERROR) {
            revert MarketManager__PriceError();
        }

        // Check `account`'s new debt position in $ and review if the loan
        // size is too small for us to allow issuing the loan.
        if (
            _assetValue(newNetDebt, price, 10 ** decimals, true) <
            MIN_LOAN_SIZE
        ) {
            revert LiquidityManager__InsufficientLoanSize();
        }
    }

    /// @notice Validates and processes batch liquidations for multiple
    ///         accounts, calculating collateral seizure amounts, debt
    ///         repayment, and bad debt based on account health and market
    ///         parameters.
    /// @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 Instructions for a liquidation action 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.
    ///               liquidatedShares 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 Hypothetical results for an action 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 (
        IMarketManager.LiqResult memory result,
        uint256[] memory
    ) {
        if (liquidationPaused == 2) {
            revert MarketManager__Paused();
        }

        _checkIsToken(action.debtToken);
        _checkIsListedToken(action.collateralToken);
        _checkIsListedToken(action.debtToken);

        (TokenLiqData memory tData, AccountLiqData memory aData) =
            _getLiquidationConfig(action.collateralToken, action.debtToken);

        // Amounts array is empty since the max amount possible
        // will be liquidated.
        result.liquidatedShares = new uint256[](action.numAccounts);
        address cachedAccount;
        address priorAccount;
        for (uint256 i; i < action.numAccounts; ++i) {
            cachedAccount = accounts[i];
            
            // Do not let an account liquidate themselves.
            if (liquidator == cachedAccount) {
                _revert(_UNAUTHORIZED_SELECTOR);
            }

            // Liquidators MUST sort the token addresses offchain from
            // smallest to largest to validate there are no duplicate
            // liquidations.
            if (priorAccount >= cachedAccount) {
                _revert(_UNAUTHORIZED_SELECTOR);
            }

            (
                action.liquidatedShares,
                action.debtRepaid,
                action.badDebt
            ) = _canLiquidate(
                debtAmounts[i],
                cachedAccount,
                tData,
                aData,
                action.liquidateExact
            );

            // We optimistically update values even if they are setting from
            // 0 -> 0 to act as an invariant check for the sum of all debt
            // values in `debtAmounts` equal to `debtRepaid`.
            result.debtRepaid += action.debtRepaid;
            result.liquidatedShares[i] = action.liquidatedShares;

            if (action.badDebt > 0) {
                result.badDebtRealized += action.badDebt;
                // Add the bad debt to debt to remove from the liquidated
                // account.
                action.debtRepaid += action.badDebt;
            }

            // If its an exact liquidation this will be a redundant setter
            // but anticipation is majority of liquidators will use
            // non-exact so checking for liquidateExact each time is a
            // waste.
            debtAmounts[i] = action.debtRepaid;

            // Update prior account to current account.
            priorAccount = cachedAccount;
        }

        // If theres no debt to repay then there were no liquidations.
        if (result.debtRepaid == 0) {
            revert MarketManager__NoLiquidationAvailable();
        }

        return (result, debtAmounts);
    }

    /// @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 view {
        _checkIsListedToken(collateralToken);
        _checkIsListedToken(debtToken);

        if (
            ICToken(collateralToken).marketManager() !=
            ICToken(debtToken).marketManager()
        ) {
            revert MarketManager__MarketManagerMismatch();
        }
    }

    /// @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.
    /// @return collateralRedeemed The amount of collateral shares redeemed
    ///                            on transfer.
    function canTransfer(
        address cToken,
        uint256 shares,
        address account,
        uint256 balanceOf,
        uint256 collateralPosted,
        bool isCollateral
    ) external returns (uint256 collateralRedeemed) {
        _checkIsToken(cToken);
        if (transferPaused == 2) {
            revert MarketManager__Paused();
        }

        collateralRedeemed = _canRedeem(
            cToken,
            shares,
            account,
            balanceOf,
            collateralPosted,
            isCollateral,
            false
        );
    }

    /// PERMISSIONED EXTERNAL FUNCTIONS ///

    /// @notice List isolated Curvance token pair to the market and enable
    ///         deposits.
    /// @dev Admin function to set isListed for token pair and add support
    ///      for the market. Only callable once due to isolated market design.
    ///      Emits {TokenListed} event twice.
    /// @param token0 The address of the first Curvance token to list in this
    ///               isolated market.
    /// @param token1 The address of the second Curvance token to list in this
    ///               isolated market.
    function listTokens(address token0, address token1) external {
        _checkMarketPermissions();

        // The same token cannot be listed twice in a market.
        if (token0 == token1) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // The same underlying asset cannot be listed twice in a market.
        if (ICToken(token0).asset() == ICToken(token1).asset()) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate that tokens are not already listed inside this market.
        if (tokensListed.length != 0) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // At least one of the two tokens has to be borrowable or the
        // market does not make any sense to create.
        if (!ICToken(token0).isBorrowable() && !ICToken(token1).isBorrowable()) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // List the tokens, we do this prior since some _afterDeposit
        // hooks could require listing.
        _tokenConfig[token0].isListed = true;
        _tokenConfig[token1].isListed = true;

        // Immediately deposits into the cToken before anyone else can,
        // preventing any rounding attack vectors.
        if (!ICToken(token0).initializeDeposits(msg.sender)) {
            _revert(_INVARIANT_ERROR_SELECTOR);
        }
        
        if (!ICToken(token1).initializeDeposits(msg.sender)) {
            _revert(_INVARIANT_ERROR_SELECTOR);
        }

        // Update `tokenListed` array and emit events for any frontends that
        // need this information.
        tokensListed.push(token0);
        tokensListed.push(token1);
        
        emit TokenListed(token0);
        emit TokenListed(token1);
    }

    /// @notice Sets token liquidity configuration values for
    ///         `newConfig.cToken` a listed cToken inside this market.
    /// @dev Emits a {TokenConfigUpdated} event.
    /// @param newConfig A TokenConfig struct containing:
    ///                  cToken The Curvance token to update liquidity
    ///                         configuration values of.
    ///                  collRatio The ratio at which $1 of collateral can be
    ///                            borrowed against, for `newConfig.cToken`,
    ///                            in `BPS`.
    ///                  collReqSoft The premium of excess collateral required
    ///                              to avoid soft liquidation, in `BPS`.
    ///                  collReqHard The premium of excess collateral required
    ///                              to avoid hard liquidation, in `BPS`.
    ///                  liqIncBase The default liquidation incentive for
    ///                             `newConfig.cToken`, in `BPS`.
    ///                  liqIncHard The hard liquidation incentive for
    ///                             `newConfig.cToken`, in `BPS`.
    ///                  liqIncMin The minimum possible liquidation incentive
    ///                            for `newConfig.cToken` during an auction,
    ///                            in `BPS`.
    ///                  liqIncMax The maximum possible liquidation incentive
    ///                            for `newConfig.cToken` during an auction,
    ///                            in `BPS`.
    ///                  closeFactorBase Maximum % that a liquidator can repay
    ///                                  when soft liquidating
    ///                                  `newConfig.cToken` for an account.
    ///                  closeFactorMin The minimum possible close factor for
    ///                                 `newConfig.cToken` during an auction,
    ///                                 in `BPS`.
    ///                  closeFactorMax The maximum possible close factor for
    ///                                 `newConfig.cToken` during an auction,
    ///                                 in `BPS`.
    ///                  collateralCap The maximum amount of shares that can
    ///                                be collateralized of `newConfig.cToken`
    ///                                inside this market.
    ///                  debtCap The maximum amount of assets that can be
    ///                          borrowed of `newConfig.cToken` inside this
    ///                          market.
    function updateTokenConfig(TokenConfig memory newConfig) external {
        _checkIsListedToken(newConfig.cToken);
        _checkMarketPermissions();

        // Validate collateralization ratio is not above the maximum allowed,
        // and that hard liquidation collateral requirement is not above
        // the soft liquidation requirement. Liquidations occur when
        // collateral dries up so hard liquidation should be less collateral
        // than soft liquidation.
        if (
            newConfig.collRatio > MAX_COLL_RATIO ||
            newConfig.collReqSoft > MAX_COLLATERAL_REQUIREMENT ||
            newConfig.collReqHard >= newConfig.collReqSoft
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate hard liquidation incentive is higher than the soft
        // liquidation incentive. We should give heavier incentives when
        // collateral is running out to reduce lender delta exposure.
        // The maximum dynamic penalty is not greater than the base
        // liquidation incentive and that the minimum dynamic penalty is not
        // less than the base liquidation incentive.
        // Validate maximum liquidation incentive and default is
        // equal or higher than the minimum liquidation incentive.
        // Validate minimum liquidation incentive is non-zero to ensure
        // liquidators have economic incentive to perform liquidations.
        // Validate both hard and max liquidation incentives do not exceed
        // the protocol maximum.
        if (
            newConfig.liqIncBase >= newConfig.liqIncHard ||
            newConfig.liqIncBase > newConfig.liqIncMax ||
            newConfig.liqIncBase < newConfig.liqIncMin ||
            newConfig.liqIncMin >= newConfig.liqIncMax ||
            newConfig.liqIncMax > MAX_LIQUIDATION_INCENTIVE ||
            newConfig.liqIncMin == 0 ||
            newConfig.liqIncHard > MAX_LIQUIDATION_INCENTIVE
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate hard and max liquidation collateral requirements are larger
        // than the hard liquidation incentive. We cannot give more incentives
        // than are available. We do not need to check soft liquidation as the
        // restrictions are thinner than this case.
        if (
            newConfig.liqIncHard + MIN_EXCESS_COLL_REQUIRED > newConfig.collReqHard ||
            newConfig.liqIncMax + MIN_EXCESS_COLL_REQUIRED > newConfig.collReqHard
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate that soft liquidation is within acceptable bounds.
        if (
            newConfig.closeFactorBase > MAX_BASE_CFACTOR ||
            newConfig.closeFactorBase < MIN_BASE_CFACTOR
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate closeFactorMin and closeFactorMax are properly configured.
        // closeFactorBase should be between min and max, min should be less
        // than max, but greater than 0, and max cannot exceed BPS.
        if (
            newConfig.closeFactorBase > newConfig.closeFactorMax ||
            newConfig.closeFactorBase < newConfig.closeFactorMin ||
            newConfig.closeFactorMin >= newConfig.closeFactorMax ||
            newConfig.closeFactorMin == 0 ||
            newConfig.closeFactorMax > BPS
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate the soft liquidation collateral premium is not stricter
        // than its `collRatio` and has a sufficient buffer against
        // soft liquidation.
        if (
            newConfig.collRatio >
            (MIN_LIQUIDATION_BUFFER / (BPS + newConfig.collReqSoft))
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate that collateral is not trying to be turned on without
        // setting a collateralization ratio.
        if (newConfig.collRatio == 0 && newConfig.collateralCap > 0) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Do not let people borrow assets if they are not intended to be.
        if (newConfig.debtCap > 0) {
            if (
                newConfig.debtCap > _MAX_DEBT_CAP ||
                !ICToken(newConfig.cToken).isBorrowable()
            ) {
                _revert(_INVALID_PARAMETER_SELECTOR);
            }
        }

        CurvanceToken storage storedConfig = _tokenConfig[newConfig.cToken];

        // If this token already has collateralization enabled,
        // we cannot turn collateralization off completely as this
        // would cause downstream effects to the DLE.
        if (storedConfig.collRatio != 0 && newConfig.collRatio == 0) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate we get a safe price when pricing both as a debt or
        // collateral asset, even if the asset cannot be collateralized.
        (, uint256 errorCode) = CommonLib._oracleManager(centralRegistry)
            .getPrice(newConfig.cToken, true, true);

        // Validate a safe price for our more important action, liquidations.
        if (errorCode == BAD_SOURCE) {
            revert MarketManager__PriceError();
        }

        (, errorCode) = CommonLib._oracleManager(centralRegistry)
            .getPrice(newConfig.cToken, true, false);

        // Validate a safe price for our more important action, liquidations.
        if (errorCode == BAD_SOURCE) {
            revert MarketManager__PriceError();
        }

        // Set new collateralization ratio.
        // Note that a collateralization ratio of 0 corresponds to
        // no collateralization of `cToken`.
        storedConfig.collRatio = uint24(newConfig.collRatio);

        // Store the collateral requirement as a premium above `BPS`,
        // that way we can calculate solvency via division
        // efficiently in _liquidationStatusOf.
        storedConfig.collReqSoft = uint24(newConfig.collReqSoft + BPS);
        storedConfig.collReqHard = uint24(newConfig.collReqHard + BPS);

        // We use the liquidation incentive values as a premium in
        // `_canLiquidate`, so it needs to be 1 + incentive.
        storedConfig.liqIncBase = uint16(BPS + newConfig.liqIncBase);
        storedConfig.liqIncMin = uint16(BPS + newConfig.liqIncMin);
        storedConfig.liqIncMax = uint16(BPS + newConfig.liqIncMax);

        // Store the distance between liquidation incentive A & B,
        // so we can quickly scale between [base, 100%] based on lFactor.
        storedConfig.liqIncCurve = uint16(newConfig.liqIncHard - newConfig.liqIncBase);

        // Assign the base cFactor.
        storedConfig.closeFactorBase = uint16(newConfig.closeFactorBase);
        // Store the distance between base cFactor and 100%,
        // that way we can quickly scale between [base, 100%] based on lFactor.
        storedConfig.closeFactorCurve = uint16(BPS - newConfig.closeFactorBase);

        // Assign the min and max effective closeFactor.
        storedConfig.closeFactorMin = uint16(newConfig.closeFactorMin);
        storedConfig.closeFactorMax = uint16(newConfig.closeFactorMax);

        // Assign the collateral posted cap of `newConfig.cToken`.
        collateralCaps[newConfig.cToken] = newConfig.collateralCap;

        // Assign the outstanding debt cap of `newConfig.cToken`.
        debtCaps[newConfig.cToken] = newConfig.debtCap;

        emit TokenConfigUpdated(newConfig);
    }

    /// @notice Admin function to set market-wide liquidation status.
    /// @dev Requires market permissions, corresponding contracts may restrict
    ///      `state` input. Emits an {ActionPaused} event.
    /// @param state Whether the desired action is pausing or unpausing.
    function setLiquidationPaused(bool state) external {
        _checkMarketPermissions();

        liquidationPaused = state ? 2 : 1;
        emit ActionPaused("Liquidation Paused", state);
    }

    /// @notice Admin function to set market-wide redemption status.
    /// @dev Requires market permissions, corresponding contracts may restrict
    ///      `state` input. Emits an {ActionPaused} event.
    /// @param state Whether redemptions should be paused or unpaused.
    function setRedeemPaused(bool state) external {
        _checkMarketPermissions();

        redeemPaused = state ? 2 : 1;
        emit ActionPaused("Redeem Paused", state);
    }

    /// @notice Admin function to set market-wide transfer status.
    /// @dev Requires market permissions, corresponding contracts may restrict
    ///      `state` input. Emits an {ActionPaused} event.
    /// @param state Whether transfers should be paused or unpaused.
    function setTransferPaused(bool state) external {
        _checkMarketPermissions();

        transferPaused = state ? 2 : 1;
        emit ActionPaused("Transfer Paused", state);
    }

    /// @notice Admin function to set token-specific Curvance token
    ///         minting status.
    /// @dev Requires market permissions, corresponding contracts may restrict
    ///      `state` input. Emits a {TokenActionPaused} event.
    /// @param cToken The Curvance token to set minting status for.
    /// @param state Whether minting should be paused or unpaused.
    function setMintPaused(address cToken, bool state) external {
        _checkMarketPermissions();
        _checkIsListedToken(cToken);

        _tokenConfig[cToken].mintPaused = state ? 2 : 1;
        emit TokenActionPaused(cToken, "Mint Paused", state);
    }

    /// @notice Admin function to set token-specific Curvance token
    ///         collateralization status.
    /// @dev Requires market permissions, corresponding contracts may restrict
    ///      `state` input. Emits a {TokenActionPaused} event.
    /// @param cToken The Curvance token to set collateralization status for.
    /// @param state Whether collateralization should be paused or unpaused.
    function setCollateralizationPaused(address cToken, bool state) external {
        _checkMarketPermissions();
        _checkIsListedToken(cToken);

        _tokenConfig[cToken].collateralizationPaused = state ? 2 : 1;
        emit TokenActionPaused(cToken, "Collateralization Paused", state);
    }

    /// @notice Admin function to set token-specific Curvance token
    ///         borrowing status.
    /// @dev Requires market permissions, corresponding contracts may restrict
    ///      `state` input. Emits a {TokenActionPaused} event.
    /// @param cToken The Curvance token to set borrowing status for.
    /// @param state Whether borrowing should be paused or unpaused.
    function setBorrowPaused(address cToken, bool state) external {
        _checkMarketPermissions();
        _checkIsListedToken(cToken);

        _tokenConfig[cToken].borrowPaused = state ? 2 : 1;
        emit TokenActionPaused(cToken, "Borrow Paused", state);
    }

    /// @notice Adds a new position manager address for complex
    ///         position actions.
    /// @dev Requires timelock authority.
    ///      Emits a {PositionManagerUpdated} event.
    /// @param newPM The address to add position manager permissions for.
    function addPositionManager(address newPM) external {
        _checkMarketPermissions();

        if (
            !ERC165Checker
                .supportsInterface(newPM, type(IPositionManager).interfaceId)
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate `newPM` does not have permissions.
        if (isPositionManager[newPM]) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Add `isPositionManager` permissions to `newPM`.
        isPositionManager[newPM] = true;

        emit PositionManagerUpdated(newPM, true);
    }

    /// @notice Removes a current position manager address from complex
    ///         position actions.
    /// @dev Requires timelock authority.
    ///      Emits a {PositionManagerUpdated} event.
    /// @param oldPM The address to remove position manager permissions for.
    function removePositionManager(address oldPM) external {
        _checkMarketPermissions();

        // Validate `oldPM` already has permissions.
        if (!isPositionManager[oldPM]) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Remove `isPositionManager` permissions.
        delete isPositionManager[oldPM];

        emit PositionManagerUpdated(oldPM, false);
    }

    /// @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 {
        _checkAuctionPermissions();
        _checkIsListedToken(cToken);

         CurvanceToken memory c = _tokenConfig[cToken];

        // Make sure this token actually can be liquidated, by being
        // collateralizable in the first place.
        if (c.collRatio == 0) {
            revert MarketManager__UnauthorizedLiquidation();
        }

        // Validate `incentive` is within configured incentive bounds, unless
        // zero is passed to signal protocol-derived values should be used.
        // This also validates `incentive` is not > the 16 bits we have allocated.
        if (
            incentive != 0 &&
            (incentive < c.liqIncMin || incentive > c.liqIncMax)
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Validate `closeFactor` is within configured allowed close factor
        // range, unless zero is passed to signal protocol-derived values
        // should be used. This also validates `closeFactor` is not > the 16
        // bits we have allocated.
        if (
            closeFactor != 0 &&
            (closeFactor < c.closeFactorMin || closeFactor > c.closeFactorMax)
        ) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        uint256 liqConfig = uint256(uint160(cToken));
        assembly {
            // Mask `liqConfig` to the lower 160 bits, in case the upper bits
            // somehow are not clean.
            liqConfig := and(liqConfig, _BITMASK_COLLATERAL_UNLOCKED)
            // Equals: liqConfig | (incentive << _BITPOS_LIQ_INCENTIVE) |
            //         closeFactor << _BITPOS_CLOSE_FACTOR.
            liqConfig := or(
                liqConfig,
                or(
                    shl(_BITPOS_LIQ_INCENTIVE, incentive),
                    shl(_BITPOS_CLOSE_FACTOR, closeFactor)
                )  
            )

            tstore(_TRANSIENT_LIQUIDATION_CONFIG_KEY, liqConfig)
        }
    }

    /// @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 {
        _checkAuctionPermissions();

        /// @solidity memory-safe-assembly
        assembly {
            tstore(_TRANSIENT_LIQUIDATION_CONFIG_KEY, 0)
        }
    }

    /// PUBLIC FUNCTIONS ///

    /// @notice Returns the current liquidation configuration in an active
    ///         transaction.
    /// @dev If a liquidation configuration value is set in transient storage,
    ///      that value is returned, 0 is returned if no set value.
    /// @return cTokenUnlocked The Curvance token unlocked for auction-based
    ///                        liquidations.
    /// @return incentive The liquidation incentive value, in `BPS`.
    /// @return closeFactor The close factor value, in `BPS`.
    function getTransientLiquidationConfig() public view returns (
        address cTokenUnlocked,
        uint256 incentive,
        uint256 closeFactor
    ) {
        uint256 liqConfig;
        /// @solidity memory-safe-assembly
        assembly {
            liqConfig := tload(_TRANSIENT_LIQUIDATION_CONFIG_KEY)
        }

        cTokenUnlocked = address(uint160(liqConfig));
        incentive = uint16(liqConfig >> _BITPOS_LIQ_INCENTIVE);
        closeFactor = uint16(liqConfig >> _BITPOS_CLOSE_FACTOR);
    }

    /// @dev Returns true that this contract implements both IMarketManager
    ///      and ERC165 interfaces.
    /// @param interfaceId The interface ID to check.
    /// @return result Whether the contract implements the interface.
    function supportsInterface(
        bytes4 interfaceId
    ) public view override returns (bool result) {
        result = interfaceId == type(IMarketManager).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /// INTERNAL FUNCTIONS ///

    /// @notice Checks if the account should be allowed to borrow
    ///         the underlying asset of the given market.
    /// @dev Will natively revert if a hypothetical new borrow will result in
    ///      a loan less than `MIN_LOAN_SIZE`,
    ///      set in `LiquidityManager`. May emit a {PositionUpdated} event.
    /// @param debtToken The token to borrow from.
    /// @param assets The amount of underlying the 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 debtToken,
        uint256 assets,
        address account,
        uint256 newNetDebt
    ) internal {
        _checkIsToken(debtToken);
        // Can skip token listing check since debtCaps[debtToken] can only
        // be set above 0 if `debtToken` is listed already, so we only need
        // to check that `newNetDebt` != 0 instead, which should be impossible
        // but only costs 2 gas.

        /// @solidity memory-safe-assembly
        assembly {
            if iszero(newNetDebt) {
                mstore(0x00, _INVARIANT_ERROR_SELECTOR)
                // Return bytes 29-32 for the selector.
                revert(0x1c, 0x04)
            }
        }

        if (_tokenConfig[debtToken].borrowPaused == 2) {
            revert MarketManager__Paused();
        }

        // Validates that newNetDebt is not an empty value and this borrow
        // action will not push net debt above the debt limit.
        // DEV: By rounding up the debt of each user, up to 1 wei for each
        // time a user has their interest accrued, the actual sum of user
        // debts may exceed marketOutstandingDebt and thus debtCap.
        if (newNetDebt > debtCaps[debtToken]) {
            revert MarketManager__CapReached();
        }

        // Check if the user already has an outstanding debt position in
        // `debtToken`.
        if (accountPositions[debtToken][account] != 2) {
            // The account does not have outstanding debt position in
            // `debtToken`, so add `debtToken` as an active position for
            // `account`.
            accountPositions[debtToken][account] = 2;
            accountAssets[account].assets.push(debtToken);

            emit PositionUpdated(debtToken, account, true);
        }

        // Check if the user has sufficient liquidity to borrow,
        // with heavier error code scrutiny.
        (, uint256 liquidityDeficit) = _hypotheticalLiquidityOf(
                account,
                HypotheticalAction({
                    cTokenModified: debtToken,
                    redemptionShares: 0,
                    borrowAssets: assets,
                    errorCodeBreakpoint: CAUTION
                })
            );

        // Validate that `account` will not run out of collateral based
        // on their collateralization ratio(s).
        if (liquidityDeficit > 0) {
            revert MarketManager__InsufficientCollateral();
        }
    }

    /// @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 balance The current cToken share balance of `account`.
    /// @param collateralPosted The current cToken shares posted as
    ///                         collateral by `account`.
    /// @param isCollateral Boolean indicating whether the token is currently
    ///                     being used as collateral.
    /// @param forceRedeemCollateral Whether the collateral should be force
    ///                              reduced, used if isCollateral is true.
    /// @return collateralRedeemed The amount of collateral shares redeemed.
    function _canRedeem(
        address cToken,
        uint256 shares,
        address account,
        uint256 balance,
        uint256 collateralPosted,
        bool isCollateral,
        bool forceRedeemCollateral
    ) internal returns (uint256 collateralRedeemed) {
        _checkIsListedToken(cToken);
        _checkTransfersAllowed(account);

        if (isCollateral) {
            // If collateral is being directly removed by user intention,
            // or liquidation we can skip balance checks.
            if (forceRedeemCollateral) {
                // Explicitly revert here if trying to redeem too much
                // collateral rather than panic revert.
                if (shares > collateralPosted) {
                    revert MarketManager__InsufficientCollateral();
                }

                collateralRedeemed = shares;
            } else {
                // We know that shares <= balance because of
                // `_checkRedemption` check inside cToken contracts prior so
                // no need for overflow check here. If they want to redeem
                // more `cToken` shares than they have idle, calculate how
                // much posted collateral will be redeemed from the delta.
                // Otherwise `collateralRedeemed` = 0 is correct. 
                if (collateralPosted + shares >= balance) {
                    collateralRedeemed = collateralPosted + shares - balance;
                }
            }
        }

        // If `collateralRedeemed` is 0 or the account does not have an
        // active position in `cToken`, we can bypass the liquidity check.
        if (collateralRedeemed == 0 || accountPositions[cToken][account] != 2) {
            return collateralRedeemed;
        }

        // Check account liquidity with hypothetical cToken redemption.
        (, uint256 liquidityDeficit) = _hypotheticalLiquidityOf(
                account,
                HypotheticalAction({
                    cTokenModified: cToken,
                    redemptionShares: collateralRedeemed,
                    borrowAssets: 0,
                    errorCodeBreakpoint: CAUTION
                })
            );

        // Validate that `account` will not run out of collateral based
        // on their collateralization ratio(s).
        if (liquidityDeficit > 0) {
            revert MarketManager__InsufficientCollateral();
        }
    }

    /// @notice Determines if an account can be liquidated and calculates
    ///         liquidation parameters. Computes liquidation amounts,
    ///         collateral seizure, and potential bad debt based on `account`
    ///         health.
    /// @param debtAmount The amount of debt to repay, used only if
    ///                   `liquidateExact` is true, in assets.
    /// @param account The address of the account being evaluated for
    ///                liquidation.
    /// @param tData A TokenLiqData struct containing:
    ///              collateralToken The token which is used as collateral
    ///                               by `account` and may be seized.
    ///              collateralExchangeRate The exchange rate of
    ///                                     `collateralToken` underlying token
    ///                                     to `collateralToken`.
    ///              collateralReqSoft The collateral requirement where
    ///                                dipping below this will cause a soft
    ///                                liquidation.
    ///              collateralReqHard The collateral requirement where
    ///                                dipping below this will cause a hard
    ///                                liquidation.
    ///              collateralUnderlyingPrice The current price of the
    ///                                        underlying token of
    ///                                        `collateralToken`.
    ///              collateralDecimals The decimals that `collateralToken`
    ///                                 is measured in.
    ///              debtToken The token to potentially repay which has
    ///                        outstanding debt by `account`.
    ///              debtDecimals The decimals that `debtToken` is measured
    ///                           in.
    ///              debtUnderlyingPrice The current price of the underlying
    ///                                  token of `debtToken`.
    ///              auctionBuffer The current buffer that `cSoft` and `cHard` are
    ///                            multiplied against, 10 bps, or 0 if not an
    ///                            auction-based liquidation.
    /// @param aData An AccountLiqData struct containing:
    ///              lFactor Empty variable to hold an account's liquidation
    ///                      factor later.
    ///              debtBalance Empty variable to hold an account's debt's 
    ///                          active debt to `tData.debtToken` later.
    ///              liqInc The ratio at which debt repayment will be
    ///                     compensated on liquidation.
    ///              liqIncBase The base ratio at which debt repayment will be
    ///                         compensated on soft liquidation.
    ///              liqIncCurve The liquidation incentive curve length
    ///                          between soft liquidation to hard liquidation.
    ///              closeFactor Maximum debt % that a liquidator can repay
    ///                          during a liquidation of an account.
    ///              closeFactorBase Maximum debt % that a liquidator can
    ///                              repay when soft liquidating an account.
    ///              closeFactorCurve Curve length between soft liquidation
    ///                               and hard liquidation, should be equal
    ///                               to 100% - `closeFactorBase`.
    /// @param liquidateExact If true, liquidate exactly `debtAmount`; if
    ///                       false, liquidate maximum possible.
    /// @return liquidatedShares The amount of `tData.collateralToken`
    ///                          that will be seized as collateral.
    /// @return uint256 The amount of `debtToken` outstanding debt that will be
    ///                 repaid.
    /// @return badDebt The amount of bad debt to recognize as part of the
    ///                 liquidation (if any).
    function _canLiquidate(
        uint256 debtAmount,
        address account,
        TokenLiqData memory tData,
        AccountLiqData memory aData,
        bool liquidateExact
    ) internal view returns (
        uint256 liquidatedShares,
        uint256,
        uint256 badDebt
    ) {
        // Calculate the users lFactor and bubble up their active debt.
        (aData.lFactor, aData.debtBalance) =
            _liquidationValuesOf(account, tData);

        if (aData.lFactor == 0) {
            return (0, 0, 0);
        }

        // If this liquidation does not have offchain submitted parameters
        // then closeFactorCurve and liqIncCurve will not be 0. Because
        // closeFactorCurve is BPS - closeFactorBase and closeFactorBase is
        // limited to MAX_BASE_CFACTOR meaning closeFactorCurve cannot ever be
        // 0. liqIncCurve cannot be zero due to the `updateTokenConfig`
        // c.liqIncBase >= c.liqIncHard inline check.
        if (aData.closeFactorCurve != 0) {
            aData.closeFactor = aData.closeFactorBase +
                _mulDiv(aData.closeFactorCurve, aData.lFactor, WAD);
        }

        if (aData.liqIncCurve != 0) {
            aData.liqInc = aData.liqIncBase +
                _mulDiv(aData.liqIncCurve, aData.lFactor, WAD);
        }
        
        // Get the exchange rate, and calculate the number of collateralized
        // shares to seize.
        // Convert liqInc to WAD via `WAD_SQUARED_BPS_OFFSET` so we dont run
        // into precision loss from only multiplying into WAD_SQUARED form.
        uint256 debtToCollateral = FixedPointMathLib.fullMulDiv(
            FixedPointMathLib.fullMulDiv(
                aData.liqInc * tData.debtUnderlyingPrice,
                WAD_SQUARED_BPS_OFFSET,
                tData.collateralSharesPrice
            ),
            tData.collateralDecimals,
            tData.debtDecimals
        );
        uint256 maxDebt = (aData.closeFactor * aData.debtBalance) / BPS;
        // If they want to liquidate an exact amount, liquidate `debtAmount`,
        // otherwise liquidate the maximum amount possible.
        if (!liquidateExact) {
            debtAmount = maxDebt;
        }
        
        // Calculate how many shares should be liquidated.
        liquidatedShares = FixedPointMathLib.fullMulDiv(
            debtAmount,
            debtToCollateral,
            WAD_SQUARED
        );

        // Cache `account`'s collateral posted of
        // `tData.collateralToken`.
        uint256 sharesPosted =
            ICToken(tData.collateralToken).collateralPosted(account);

        // If the user wants to liquidate an exact amount, make sure theres
        // enough collateral available to liquidate, otherwise
        // liquidate as much as possible.
        if (liquidateExact) {
            if (debtAmount > maxDebt || liquidatedShares > sharesPosted) {
                // Make sure that the liquidation limit,
                // and collateral posted >= amount.
                _revert(_INVALID_PARAMETER_SELECTOR);
            }
        } else {
            // If there is not enough shares available for liquidation,
            // liquidate what is available.
            if (liquidatedShares > sharesPosted) {
                debtAmount = FixedPointMathLib.fullMulDivUp(
                    debtAmount,
                    sharesPosted,
                    liquidatedShares
                );
                liquidatedShares = sharesPosted;
            }
        }

        // If the necessary collateral shares to liquidate `account`'s debt is
        // more than their shares posted, there is bad debt that should be
        // socialized among lenders, calculate using the same formula we used
        // for `liquidatedShares`.
        uint256 sharesNeeded = FixedPointMathLib.fullMulDivUp(
            aData.debtBalance,
            debtToCollateral,
            WAD_SQUARED
        );
        if (sharesNeeded > sharesPosted) {
            // Calculate total debt necessary to compensate liquidators
            // in full based on `sharesNeeded` vs `sharesPosted`.
            // `sharesPosted` = `sharesNeeded` / 2 means 50%
            // of debt should be recognized as bad debt, so this 
            // intermediary step for `badDebt` would be 2x `debtAmount`.
            badDebt = FixedPointMathLib
                .fullMulDivUp(debtAmount, sharesNeeded, sharesPosted);

            // Calculate if compensation calculation will overflow, this can
            // happen in scenarios where collateral goes to near 0.
            // If it would cause an underflow -> clamp the bad debt down,
            // siding with lenders over liquidators.
            if (badDebt > aData.debtBalance) {
                // CASE: Unhappy path, collateral went to near zero, reduce
                // bad debt and keep liquidator's `debtAmount` consistent.
                badDebt = aData.debtBalance - debtAmount;
            } else {
                // CASE: Happy path, normal calculation of recognizing bad
                // debt pro-rata based on shortfall of `sharesNeeded` versus
                // sharesPosted.
                badDebt = badDebt - debtAmount;
            }
        }

        // Calculate the maximum amount of debt that can be liquidated
        // and what collateral will be received. As well as any bad debt
        // to recognize.
        return (liquidatedShares, debtAmount, badDebt);
    }

    /// @notice Retrieves and caches liquidation configuration data for a
    ///         given token pair.
    /// @param collateralToken The address of the Curvance token to be seized
    ///                        during in the liquidation.
    /// @param debtToken The address of the Curvance token to be repaid during
    ///                  the liquidation.
    /// @return tData A TokenLiqData struct containing:
    ///               collateralToken The token which is used as collateral
    ///                               by `account` and may be seized.
    ///               collateralExchangeRate The exchange rate of
    ///                                      `collateralToken` underlying
    ///                                      token to `collateralToken`.
    ///               collateralReqSoft The collateral requirement where
    ///                                 dipping below this will cause a soft
    ///                                 liquidation.
    ///               collateralReqHard The collateral requirement where
    ///                                 dipping below this will cause a hard
    ///                                 liquidation.
    ///               collateralUnderlyingPrice The current price of the
    ///                                         underlying token of
    ///                                         `collateralToken`.
    ///               collateralDecimals The decimals that `collateralToken`
    ///                                  is measured in.
    ///               debtToken The token to potentially repay which has
    ///                         outstanding debt by `account`.
    ///               debtDecimals The decimals that `debtToken` is measured
    ///                            in.
    ///               debtUnderlyingPrice The current price of the underlying
    ///                                   token of `debtToken`.
    ///               auctionBuffer The current buffer that `cSoft` and `cHard` are
    ///                             multiplied against, 10 bps, or 0 if not an
    ///                             an auction-based liquidation.
    /// @return aData An AccountLiqData struct containing:
    ///               lFactor Empty variable to hold an account's liquidation
    ///                       factor later.
    ///               debtBalance Empty variable to hold an account's debt's 
    ///                           active debt to `tData.debtToken` later.
    ///               liqInc The ratio at which debt repayment will be
    ///                      compensated on liquidation.
    ///               liqIncBase The base ratio at which debt repayment will
    ///                          be compensated on soft liquidation.
    ///               liqIncCurve The liquidation incentive curve length
    ///                           between soft liquidation to hard
    ///                           liquidation.
    ///               closeFactor Maximum debt % that a liquidator can repay
    ///                           during a liquidation of an account.
    ///               closeFactorBase Maximum debt % that a liquidator can
    ///                               repay when soft liquidating an account.
    ///               closeFactorCurve Curve length between soft liquidation
    ///                                and hard liquidation, should be equal
    ///                                to 100% - `closeFactorBase`.
    function _getLiquidationConfig(
        address collateralToken,
        address debtToken
    ) internal returns (
        TokenLiqData memory tData,
        AccountLiqData memory aData
    ) {
        CurvanceToken memory c = _tokenConfig[collateralToken];
        // Do not let people liquidate 0% collateralization ratio assets.
        if (c.collRatio == 0) {
            _revert(_INVALID_PARAMETER_SELECTOR);
        }

        // Will revert if this liquidation is an attempted auction liquidator
        // and liquidator has chosen incorrect collateral or market.
        // Pulls any relevant offchain liquidation configuration.
        (tData.auctionBuffer, aData.liqInc, aData.closeFactor) =
            _checkLiquidationConfig(collateralToken);

        // Liquidations are only blocked if an error code of 2 (NO_SOURCE)
        // is calculated.
        (tData.collateralSharesPrice, tData.debtUnderlyingPrice) =
            CommonLib._oracleManager(centralRegistry)
                .getPriceIsolatedPair(collateralToken, debtToken, BAD_SOURCE);

        // Cache all variables needed for computing liquidation levels.
        tData.collateralToken = collateralToken;
        tData.collateralReqSoft = c.collReqSoft;
        tData.collateralReqHard = c.collReqHard;
        tData.collateralDecimals = 10 ** IERC20(collateralToken).decimals();
        tData.debtToken = debtToken;
        tData.debtDecimals = 10 ** IERC20(debtToken).decimals();

        // We only need to cache these variables if we did not receive close
        // factor/liquidation incentive from `getLiquidationConfig`.
        if (aData.closeFactor == 0) {
            aData.closeFactorBase = c.closeFactorBase;
            aData.closeFactorCurve = c.closeFactorCurve;
        }

        if (aData.liqInc == 0) {
            aData.liqIncBase = c.liqIncBase;
            aData.liqIncCurve = c.liqIncCurve;
        }
    }

    /// @notice Check whether the hold period is met.
    /// @param account The account to check the hold period for.
    function _checkHoldPeriod(address account) internal view {
        // We require a `minimumHoldPeriod` to break flashloan
        // and multi-block price manipulations if the dynamic dual oracle
        // fails to protect the market somehow.
        if (
            accountAssets[account].cooldownTimestamp + MIN_HOLD_PERIOD >
            block.timestamp
        ) {
            revert MarketManager__MinimumHoldPeriod();
        }
    }

    /// @notice Checks whether `token` is listed in this Market Manager.
    /// @param token The token to check whether it's listed or not.
    function _checkIsListedToken(address token) internal view {
        if (!_tokenConfig[token].isListed) {
            revert MarketManager__TokenNotListed();
        }
    }

    /// @dev Checks whether the caller is `token`.
    function _checkIsToken(address token) internal view {
        /// @solidity memory-safe-assembly
        assembly {
            // Equal to if (msg.sender != token)
            if iszero(eq(caller(), token)) {
                mstore(0x00, _UNAUTHORIZED_SELECTOR)
                // Return bytes 29-32 for the selector.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Checks whether `account` has token transfers enabled.
    function _checkTransfersAllowed(address account) internal view {
        if (centralRegistry.checkTransfersDisabled(account)) {
            _revert(_UNAUTHORIZED_SELECTOR);
        }

        _checkHoldPeriod(account);
    }

    /// @notice Will revert and block liquidations of collateral that are not
    ///         currently allowed by Auction, only if this is an Auction tx.
    /// @param cToken The address of the collateral token to liquidate.
    /// @return The buffer priority value to apply as a discount to collateral
    ///         during auctioned liquidations.
    function _checkLiquidationConfig(
        address cToken
    ) internal view returns (uint256, uint256, uint256) {
        (address unlockedCToken, uint256 liqIncentive, uint256 closeFactor) =
            getTransientLiquidationConfig();

        bool unlockedMarket = centralRegistry.isMarketUnlocked();
        bool unlockedCollateral = unlockedCToken == cToken;

        if (unlockedMarket || unlockedCollateral) {
            // This is an attempted auction liquidation, and is configured
            // correctly so give them the auction priority buffer.
            if (unlockedMarket && unlockedCollateral) {
                return (AUCTION_BUFFER, liqIncentive, closeFactor);
            }

            // This is an attempted auction liquidation, but its misconfigured
            // and unauthorized because of this.
            revert MarketManager__UnauthorizedLiquidation();
        }

        // This is not an attempted auction liquidation, so approve the
        // liquidation, but without any offchain liquidation config values.
        return (0, 0, 0);
    }

    /// @dev Checks whether the caller has sufficient permissioning.
    ///      NOTE: Market Permissioned contracts should have corresponding
    ///            restrictions handled within the contract itself such as
    ///            enforcing a specific party to pause but not unpause
    ///            markets.
    function _checkMarketPermissions() internal view virtual {
        if (!centralRegistry.hasMarketPermissions(msg.sender)) {
            _revert(_UNAUTHORIZED_SELECTOR);
        }
    }

    /// @dev Checks whether the caller has sufficient permissioning.
    function _checkAuctionPermissions() internal view {
        if (!centralRegistry.hasAuctionPermissions(msg.sender)) {
            _revert(_UNAUTHORIZED_SELECTOR);
        }
    }

    /// @dev Returns the Protocol Central Registry contract in interface
    ///      form.
    function _getCentralRegistry()
        internal
        view
        override
        returns (ICentralRegistry)
    {
        return centralRegistry;
    }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract ICentralRegistry","name":"cr","type":"address"},{"internalType":"uint256","name":"minLoanSize","type":"uint256"},{"internalType":"bool","name":"isCorrelatedMarket","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CentralRegistryLib__InvalidCentralRegistry","type":"error"},{"inputs":[],"name":"LiquidityManager__InsufficientLoanSize","type":"error"},{"inputs":[],"name":"LiquidityManager__PriceError","type":"error"},{"inputs":[],"name":"LowLevelCallsHelper__CallFailed","type":"error"},{"inputs":[],"name":"MarketManager__CapReached","type":"error"},{"inputs":[],"name":"MarketManager__InsufficientCollateral","type":"error"},{"inputs":[],"name":"MarketManager__InvalidParameter","type":"error"},{"inputs":[],"name":"MarketManager__InvariantError","type":"error"},{"inputs":[],"name":"MarketManager__MarketManagerMismatch","type":"error"},{"inputs":[],"name":"MarketManager__MinimumHoldPeriod","type":"error"},{"inputs":[],"name":"MarketManager__NoLiquidationAvailable","type":"error"},{"inputs":[],"name":"MarketManager__Paused","type":"error"},{"inputs":[],"name":"MarketManager__PriceError","type":"error"},{"inputs":[],"name":"MarketManager__TokenNotListed","type":"error"},{"inputs":[],"name":"MarketManager__Unauthorized","type":"error"},{"inputs":[],"name":"MarketManager__UnauthorizedLiquidation","type":"error"},{"inputs":[],"name":"Multicall__InvalidTarget","type":"error"},{"inputs":[],"name":"Multicall__UnknownCalldata","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"positionManager","type":"address"},{"indexed":false,"internalType":"bool","name":"addPerms","type":"bool"}],"name":"PositionManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"open","type":"bool"}],"name":"PositionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"TokenActionPaused","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"collRatio","type":"uint256"},{"internalType":"uint256","name":"collReqSoft","type":"uint256"},{"internalType":"uint256","name":"collReqHard","type":"uint256"},{"internalType":"uint256","name":"liqIncBase","type":"uint256"},{"internalType":"uint256","name":"liqIncHard","type":"uint256"},{"internalType":"uint256","name":"liqIncMin","type":"uint256"},{"internalType":"uint256","name":"liqIncMax","type":"uint256"},{"internalType":"uint256","name":"closeFactorBase","type":"uint256"},{"internalType":"uint256","name":"closeFactorMin","type":"uint256"},{"internalType":"uint256","name":"closeFactorMax","type":"uint256"},{"internalType":"uint256","name":"collateralCap","type":"uint256"},{"internalType":"uint256","name":"debtCap","type":"uint256"}],"indexed":false,"internalType":"struct MarketManagerIsolated.TokenConfig","name":"config","type":"tuple"}],"name":"TokenConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cToken","type":"address"}],"name":"TokenListed","type":"event"},{"inputs":[],"name":"AUCTION_BUFFER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AUCTION_BUFFER_CORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AUCTION_BUFFER_UNCORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTRA_BUFFER_BEFORE_LIQUIDATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IS_CORRELATED_ASSET_MARKET","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BASE_CFACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLLATERAL_REQUIREMENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLL_RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLL_RATIO_CORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COLL_RATIO_UNCORRELATED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LIQUIDATION_INCENTIVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_BASE_CFACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_EXCESS_COLL_REQUIRED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_HOLD_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LIQUIDATION_BUFFER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LIQUIDATION_BUFFER_REQUIRED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LOAN_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountAssets","outputs":[{"internalType":"uint256","name":"cooldownTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"accountPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"actionsPaused","outputs":[{"internalType":"bool","name":"mintPaused","type":"bool"},{"internalType":"bool","name":"collateralizationPaused","type":"bool"},{"internalType":"bool","name":"borrowPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newPM","type":"address"}],"name":"addPositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"assetsOf","outputs":[{"internalType":"address[]","name":"result","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"newNetDebt","type":"uint256"}],"name":"canBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"newNetDebt","type":"uint256"}],"name":"canBorrowWithNotify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"newNetCollateral","type":"uint256"}],"name":"canCollateralize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"debtAmounts","type":"uint256[]"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"components":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"},{"internalType":"uint256","name":"numAccounts","type":"uint256"},{"internalType":"bool","name":"liquidateExact","type":"bool"},{"internalType":"uint256","name":"liquidatedShares","type":"uint256"},{"internalType":"uint256","name":"debtRepaid","type":"uint256"},{"internalType":"uint256","name":"badDebt","type":"uint256"}],"internalType":"struct IMarketManager.LiqAction","name":"action","type":"tuple"}],"name":"canLiquidate","outputs":[{"components":[{"internalType":"uint256[]","name":"liquidatedShares","type":"uint256[]"},{"internalType":"uint256","name":"debtRepaid","type":"uint256"},{"internalType":"uint256","name":"badDebtRealized","type":"uint256"}],"internalType":"struct IMarketManager.LiqResult","name":"result","type":"tuple"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"canMint","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balanceOf","type":"uint256"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"bool","name":"forceRedeemCollateral","type":"bool"}],"name":"canRedeemWithCollateralRemoval","outputs":[{"internalType":"uint256","name":"collateralRedeemed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"newNetDebt","type":"uint256"},{"internalType":"address","name":"debtAsset","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"canRepayWithReview","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"}],"name":"canSeize","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balanceOf","type":"uint256"},{"internalType":"uint256","name":"collateralPosted","type":"uint256"},{"internalType":"bool","name":"isCollateral","type":"bool"}],"name":"canTransfer","outputs":[{"internalType":"uint256","name":"collateralRedeemed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"centralRegistry","outputs":[{"internalType":"contract ICentralRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"collConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collateralCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"debtCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransientLiquidationConfig","outputs":[{"internalType":"address","name":"cTokenUnlocked","type":"address"},{"internalType":"uint256","name":"incentive","type":"uint256"},{"internalType":"uint256","name":"closeFactor","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"isListed","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPositionManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"}],"name":"liquidationConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationPaused","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"name":"listTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isPriceUpdate","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Multicall.MulticallAction[]","name":"calls","type":"tuple[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"notifyBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queryTokensListed","outputs":[{"internalType":"address[]","name":"r","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeemPaused","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldPM","type":"address"}],"name":"removePositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetTransientLiquidationConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setBorrowPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setCollateralizationPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setLiquidationPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setMintPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setRedeemPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"setTransferPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"incentive","type":"uint256"},{"internalType":"uint256","name":"closeFactor","type":"uint256"}],"name":"setTransientLiquidationConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"statusOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokensListed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferPaused","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"cToken","type":"address"},{"internalType":"uint256","name":"collRatio","type":"uint256"},{"internalType":"uint256","name":"collReqSoft","type":"uint256"},{"internalType":"uint256","name":"collReqHard","type":"uint256"},{"internalType":"uint256","name":"liqIncBase","type":"uint256"},{"internalType":"uint256","name":"liqIncHard","type":"uint256"},{"internalType":"uint256","name":"liqIncMin","type":"uint256"},{"internalType":"uint256","name":"liqIncMax","type":"uint256"},{"internalType":"uint256","name":"closeFactorBase","type":"uint256"},{"internalType":"uint256","name":"closeFactorMin","type":"uint256"},{"internalType":"uint256","name":"closeFactorMax","type":"uint256"},{"internalType":"uint256","name":"collateralCap","type":"uint256"},{"internalType":"uint256","name":"debtCap","type":"uint256"}],"internalType":"struct MarketManagerIsolated.TokenConfig","name":"newConfig","type":"tuple"}],"name":"updateTokenConfig","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101606040526004805462ffffff191662010101179055348015610021575f5ffd5b50604051615115380380615115833981016040819052610040916101f4565b828282678ac7230489e80000821080610061575068056bc75e2d6310000082115b1561007f57604051632e7cf4cd60e11b815260040160405180910390fd5b610088836100e7565b6001600160a01b0383166101405261012082905280151560a052806100af576125e06100b3565b6126165b60c052806100c3576126de6100c7565b6127065b60e08190526100d8906126e8610243565b60805250610266945050505050565b6100f8816399011ef160e01b610118565b610115576040516369b5e45b60e11b815260040160405180910390fd5b50565b5f6101228361013c565b80156101335750610133838361016e565b90505b92915050565b5f61014e826301ffc9a760e01b61016e565b80156101365750610167826001600160e01b031961016e565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f5190508280156101de575060208210155b80156101e957505f81115b979650505050505050565b5f5f5f60608486031215610206575f5ffd5b83516001600160a01b038116811461021c575f5ffd5b6020850151604086015191945092508015158114610238575f5ffd5b809150509250925092565b808202811582820484141761013657634e487b7160e01b5f52601160045260245ffd5b60805160a05160c05160e051610100516101205161014051614dee6103275f395f81816106bb01528181610f1a01528181610fd801528181611532015281816125790152818161285e01528181612c8b01528181612ffd01528181613574015281816136b2015281816139920152613a7701525f8181610737015281816115ea01526138ca01525f61066e01525f81816106e20152613b2601525f81816104b90152610bf901525f6108c901525f81816104e00152610dc70152614dee5ff3fe608060405234801561000f575f5ffd5b5060043610610387575f3560e01c80638a05a2e6116101df578063c03c24bb11610109578063d99f05e1116100a9578063ecdb97a011610079578063ecdb97a01461093f578063f794062e146109f4578063f96492c914610a1f578063fb2cb34e14610a32575f5ffd5b8063d99f05e1146108c4578063da11ee23146108eb578063e2f0ab011461090c578063e8bbf5d71461091f575f5ffd5b8063c8b5277e116100e4578063c8b5277e14610889578063ccb99c261461089c578063d53dc739146108af578063d78db3f1146108bc575f5ffd5b8063c03c24bb14610844578063c2ba474414610863578063c80fa87214610876575f5ffd5b8063a2675bcd1161017f578063afbe407a1161014f578063afbe407a146107f2578063b235d468146107fa578063b6606d1c1461081e578063b7b7f26014610831575f5ffd5b8063a2675bcd1461076c578063a2f88e49146107b6578063abf883cb146107bf578063af79b3ca146107e9575f5ffd5b8063901941f9116101ba578063901941f9146106dd57806397a5d5b5146107045780639b4e3822146107325780639d488a0c14610759575f5ffd5b80638a05a2e6146106905780638c75d4fe146106a35780638f73dcfa146106b6575f5ffd5b80633fd596ce116102c0578063699ba8b3116102605780637551cd48116102305780637551cd4814610644578063757942ea146106575780637beec6af1461066057806380a00b7414610669575f5ffd5b8063699ba8b31461059c5780636c3b426f146106095780636dac9023146106125780637148fa5414610631575f5ffd5b80634b3d3b581161029b5780634b3d3b58146105435780634b7e1ff114610556578063504d6b181461056957806363e12aa314610571575f5ffd5b80633fd596ce1461051e57806345a9bbde146105275780634b03195214610530575f5ffd5b80631e9fb63a1161032b5780632f7a4c65116103065780632f7a4c65146104b457806337142666146104db57806339a8bf38146105025780633e0cdfd31461050b575f5ffd5b80631e9fb63a146104785780632076d8e7146104815780632c62fa1014610494575f5ffd5b80630358e376116103665780630358e376146103e957806308799c63146103fe5780630a73e3911461041157806317c221c614610433575f5ffd5b80623c8bd41461038b57806301ffc9a7146103a7578063032886d9146103ca575b5f5ffd5b6103946104b081565b6040519081526020015b60405180910390f35b6103ba6103b53660046140c9565b610a45565b604051901515815260200161039e565b6103946103d8366004614114565b60056020525f908152604090205481565b6103fc6103f736600461412f565b610a7b565b005b6103fc61040c366004614240565b610be4565b6103ba61041f366004614114565b60076020525f908152604090205460ff1681565b5f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c16604080516001600160a01b03909416845260208401929092529082015260600161039e565b6103946126de81565b61039461048f3660046142f9565b611352565b6104a76104a2366004614114565b6113a2565b60405161039e919061435c565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b61039461270681565b6103fc6105193660046143a7565b611418565b6103946126e881565b6103946125e081565b6103fc61053e3660046143de565b6114d1565b6103fc610551366004614439565b611649565b6103fc61056436600461447e565b61165b565b6103fc611836565b61058461057f3660046144b0565b611850565b6040516001600160a01b03909116815260200161039e565b6105ea6105aa366004614114565b6001600160a01b03165f90815260208190526040902054600260ff6101008304811682149362010000840482168314936301000000900490911690911490565b604080519315158452911515602084015215159082015260600161039e565b61039461261681565b610394610620366004614114565b60026020525f908152604090205481565b6103fc61063f3660046144c7565b611878565b6103fc6106523660046144c7565b611c73565b61039461138881565b6103946103e881565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103fc61069e366004614114565b611d79565b6103fc6106b13660046144c7565b611e0a565b6105847f000000000000000000000000000000000000000000000000000000000000000081565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b610717610712366004614114565b611e38565b6040805193845260208401929092529082015260600161039e565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103fc6107673660046144f3565b611e52565b61071761077a366004614114565b6001600160a01b03165f9081526020819052604090205462ffffff600160201b8204811692600160381b8304821692600160501b900490911690565b610394615b6881565b6103946107cd3660046144c7565b600160209081525f928352604080842090915290825290205481565b610394610bb881565b6104a7611ede565b60045461080c90610100900460ff1681565b60405160ff909116815260200161039e565b6103fc61082c3660046143a7565b611f3e565b61039461083f3660046142f9565b611ff5565b610394610852366004614114565b60066020525f908152604090205481565b6103fc610871366004614114565b61203a565b6103fc6108843660046143a7565b612086565b6103fc6108973660046144f3565b61214b565b6103fc6108aa3660046144f3565b6121d3565b60045461080c9060ff1681565b610394606481565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b6108fe6108f93660046145ed565b61225d565b60405161039e92919061470f565b6103fc61091a366004614114565b6124c4565b61093261092d366004614752565b612575565b60405161039e91906147be565b6109b961094d366004614114565b6001600160a01b03165f9081526020819052604090205461ffff600160681b8204811692600160781b8304821692600160881b8104831692600160981b8204811692600160a81b8304821692600160b81b8104831692600160c81b8204811692600160d81b9092041690565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201526101000161039e565b6103ba610a02366004614114565b6001600160a01b03165f9081526020819052604090205460ff1690565b6103fc610a2d366004614439565b6127d7565b60045461080c9062010000900460ff1681565b5f6001600160e01b03198216634d6978eb60e11b1480610a7557506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a84836127fd565b80610a9657635518d5cb5f526004601cfd5b6001600160a01b0383165f9081526020819052604090205462010000900460ff16600203610ad757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0383165f90815260056020526040902054811115610b0f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038083165f81815260026020818152604080842042905594881683526001815284832093835292909252919091205414610bdf576001600160a01b038381165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e5906060015b60405180910390a15b505050565b8051610bef90612811565b610bf7612849565b7f000000000000000000000000000000000000000000000000000000000000000081602001511180610c2e5750615b688160400151115b80610c4157508060400151816060015110155b15610c5357610c536365513fc16128e3565b8060a001518160800151101580610c7157508060e001518160800151115b80610c8357508060c001518160800151105b80610c9657508060e001518160c0015110155b80610ca65750610bb88160e00151115b80610cb3575060c0810151155b80610cc35750610bb88160a00151115b15610cd557610cd56365513fc16128e3565b806060015160648260a00151610ceb9190614835565b1180610d0a5750806060015160648260e00151610d089190614835565b115b15610d1c57610d1c6365513fc16128e3565b6113888161010001511180610d3757506103e8816101000151105b15610d4957610d496365513fc16128e3565b8061014001518161010001511180610d6a5750806101200151816101000151105b80610d7f575080610140015181610120015110155b80610d8d5750610120810151155b80610d9e5750612710816101400151115b15610db057610db06365513fc16128e3565b6040810151610dc190612710614835565b610deb907f0000000000000000000000000000000000000000000000000000000000000000614848565b81602001511115610e0357610e036365513fc16128e3565b6020810151158015610e1957505f816101600151115b15610e2b57610e2b6365513fc16128e3565b61018081015115610ecc5761018081015170ffffffffffffffffffffffffffffffffff1080610eba5750805f01516001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e94573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eb89190614867565b155b15610ecc57610ecc6365513fc16128e3565b80516001600160a01b03165f9081526020819052604090208054600160201b900462ffffff1615801590610f0257506020820151155b15610f1457610f146365513fc16128e3565b5f610f3e7f00000000000000000000000000000000000000000000000000000000000000006128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae6916391610f71916001908190600401614882565b6040805180830381865afa158015610f8b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faf91906148a5565b91505060028103610fd35760405163583c953760e01b815260040160405180910390fd5b610ffc7f00000000000000000000000000000000000000000000000000000000000000006128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae691639161102f916001905f90600401614882565b6040805180830381865afa158015611049573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061106d91906148a5565b91505060011981016110925760405163583c953760e01b815260040160405180910390fd5b6020830151825462ffffff909116600160201b0266ffffff000000001990911617825560408301516110c79061271090614835565b825462ffffff91909116600160381b0269ffffff000000000000001990911617825560608301516110fb9061271090614835565b825462ffffff91909116600160501b0262ffffff60501b19909116178255608083015161112a90612710614835565b825461ffff91909116600160681b0261ffff60681b1990911617825560c083015161115790612710614835565b825461ffff91909116600160881b0261ffff60881b1990911617825560e083015161118490612710614835565b825461ffff91909116600160981b0261ffff60981b19909116178255608083015160a08401516111b491906148c7565b825461010085015167ffff00000000ffff60781b19909116600160781b61ffff9384160261ffff60a81b191617600160a81b928216929092029190911783556111ff906127106148c7565b825461012085015161014086015163ffffffff60b81b19909216600160b81b61ffff9485160261ffff60c81b191617600160c81b918416919091021761ffff60d81b1916600160d81b929091169190910217825561016083015183516001600160a01b039081165f90815260056020908152604080832094909455610180870151875190931682526006905282902055517f7118653a594971f43f27090077f0b05efeaf77dd61915894fa826f79ca0ab5b890610bd690859081516001600160a01b031681526101a081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010083015161010083015261012083015161012083015261014083015161014083015261016083015161016083015261018083015161018083015292915050565b5f61135c876127fd565b600454610100900460ff1660020361138757604051633d1cc8fd60e21b815260040160405180910390fd5b611397878787878760018861294d565b979650505050505050565b6001600160a01b0381165f9081526002602090815260409182902060010180548351818402810184019094528084526060939283018282801561140c57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116113ee575b50505050509050919050565b611420612849565b61142982612811565b80611435576001611438565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff959095166101000261ff00199095169490941790935580519182526060928201839052600b928201929092526a135a5b9d0814185d5cd95960aa1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0015b60405180910390a15050565b6114da856127fd565b6114e385612811565b6114ec81612a55565b6001600160a01b038086165f90815260016020908152604080832093851683529290522054600214611525576115256365513fc16128e3565b8315611642575f5f6115567f00000000000000000000000000000000000000000000000000000000000000006128ec565b6001600160a01b0316635ae69163866001806040518463ffffffff1660e01b815260040161158693929190614882565b6040805180830381865afa1580156115a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c491906148a5565b915091505f81146115e85760405163583c953760e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000611620878461161988600a6149bd565b6001612a9b565b101561163f57604051632e7cf4cd60e11b815260040160405180910390fd5b50505b5050505050565b61165584848484612aca565b50505050565b611663612c76565b61166c83612811565b6001600160a01b0383165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c08301529091036117935760405163fac97a2b60e01b815260040160405180910390fd5b82158015906117bc575080610120015161ffff168310806117bc575080610140015161ffff1683115b156117ce576117ce6365513fc16128e3565b81158015906117f75750806101a0015161ffff168210806117f75750806101c0015161ffff1682115b15611809576118096365513fc16128e3565b60a083901b60b083901b176001600160a01b03851617805f516020614d995f395f51905f525d5050505050565b61183e612c76565b5f5f516020614d995f395f51905f525d565b6003818154811061185f575f80fd5b5f918252602090912001546001600160a01b0316905081565b611880612849565b806001600160a01b0316826001600160a01b0316036118a6576118a66365513fc16128e3565b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190691906149c8565b6001600160a01b0316826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561194b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196f91906149c8565b6001600160a01b03160361198a5761198a6365513fc16128e3565b6003541561199f5761199f6365513fc16128e3565b816001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ff9190614867565b158015611a695750806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a43573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a679190614867565b155b15611a7b57611a7b6365513fc16128e3565b6001600160a01b038281165f818152602081905260408082208054600160ff19918216811790925594861683529181902080549094169091179092559051637ada7a0960e01b8152336004820152637ada7a09906024016020604051808303815f875af1158015611aee573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b129190614867565b611b2357611b23635518d5cb6128e3565b604051637ada7a0960e01b81523360048201526001600160a01b03821690637ada7a09906024016020604051808303815f875af1158015611b66573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8a9190614867565b611b9b57611b9b635518d5cb6128e3565b60038054600180820183555f8390527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b91820180546001600160a01b03199081166001600160a01b0388811691821790935585549384019095559190920180549091169184169190911790556040519081527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a99060200160405180910390a16040516001600160a01b03821681527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a9906020016114c5565b611c7c82612811565b611c8581612811565b806001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ce591906149c8565b6001600160a01b0316826001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d4e91906149c8565b6001600160a01b031614611d7557604051631284375160e11b815260040160405180910390fd5b5050565b611d81612849565b6001600160a01b0381165f9081526007602052604090205460ff16611dad57611dad6365513fc16128e3565b6001600160a01b0381165f818152600760209081526040808320805460ff191690558051938452908301919091527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a1691015b60405180910390a150565b611e13826127fd565b611e1c82612811565b6001600160a01b03165f90815260026020526040902042905550565b5f5f5f611e4484612cc2565b9250925092505b9193909250565b611e5a612849565b80611e66576001611e69565b60025b600460026101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600f908201526e151c985b9cd9995c8814185d5cd959608a1b6060820152901515602082015260800190565b60606003805480602002602001604051908101604052809291908181526020018280548015611f3457602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611f16575b5050505050905090565b611f46612849565b611f4f82612811565b80611f5b576001611f5e565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff9590951663010000000263ff000000199095169490941790935580519182526060928201839052600d928201929092526c109bdc9c9bddc814185d5cd959609a1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b5f611fff876127fd565b60045462010000900460ff1660020361202b57604051633d1cc8fd60e21b815260040160405180910390fd5b6113978787878787875f61294d565b6001600160a01b0381165f90815260208190526040902054610100900460ff1660020361207a57604051633d1cc8fd60e21b815260040160405180910390fd5b61208381612811565b50565b61208e612849565b61209782612811565b806120a35760016120a6565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff95909516620100000262ff00001990951694909417909355805191825260609282018390526018928201929092527f436f6c6c61746572616c697a6174696f6e2050617573656400000000000000006080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b612153612849565b8061215f576001612162565b60025b6004805460ff191660ff929092169190911790556040805181815260129181019190915271131a5c5d5a59185d1a5bdb8814185d5cd95960721b606082015281151560208201527fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de090608001611dff565b6121db612849565b806121e75760016121ea565b60025b600460016101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600d908201526c14995919595b4814185d5cd959609a1b6060820152901515602082015260800190565b61227f6040518060600160405280606081526020015f81526020015f81525090565b60045460609060ff166002036122a857604051633d1cc8fd60e21b815260040160405180910390fd5b6122b583602001516127fd565b82516122c090612811565b6122cd8360200151612811565b5f5f6122e0855f01518660200151612e2c565b9150915084604001516001600160401b038111156123005761230061416d565b604051908082528060200260200182016040528015612329578160200160208202803683370190505b5084525f80805b87604001518110156124915789898281811061234e5761234e6149e3565b90506020020160208101906123639190614114565b9250826001600160a01b03168b6001600160a01b03160361238b5761238b6337cf6ad56128e3565b826001600160a01b0316826001600160a01b0316106123b1576123b16337cf6ad56128e3565b6123db8c82815181106123c6576123c66149e3565b60200260200101518487878c60600151613216565b60c08b015260a08a0181905260808a0191909152602088018051612400908390614835565b9052506080880151875180518390811061241c5761241c6149e3565b602090810291909101015260c088015115612464578760c00151876040018181516124479190614835565b90525060c088015160a089018051612460908390614835565b9052505b8760a001518c828151811061247b5761247b6149e3565b6020908102919091010152829150600101612330565b5085602001515f036124b6576040516311d1870d60e11b815260040160405180910390fd5b509399975050505050505050565b6124cc612849565b6124dd816316bb16f160e11b61346a565b6124ee576124ee6365513fc16128e3565b6001600160a01b0381165f9081526007602052604090205460ff161561251b5761251b6365513fc16128e3565b6001600160a01b0381165f81815260076020908152604091829020805460ff191660019081179091558251938452908301527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a169101611dff565b60607f000000000000000000000000000000000000000000000000000000000000000082806001600160401b038111156125b1576125b161416d565b6040519080825280602002602001820160405280156125e457816020015b60608152602001906001900390816125cf5790505b5060408051606080820183525f80835260208301819052928201529194505b828110156127cd5786868281811061261d5761261d6149e3565b905060200281019061262f91906149f7565b61263890614a15565b915081602001511561276f57815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa15801561268c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126b091906149c8565b90506001600160a01b0381166126d957604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d79261270e9233929190600401614ad6565b5f604051808303815f87803b158015612725575f5ffd5b505af1158015612737573d5f5f3e3d5ffd5b5050505061274c835f0151846040015161348c565b86838151811061275e5761275e6149e3565b6020026020010181905250506127c5565b81516001600160a01b0316301461279957604051637720ccd960e01b815260040160405180910390fd5b6127a7308360400151613501565b8582815181106127b9576127b96149e3565b60200260200101819052505b600101612603565b5050505092915050565b6001600160a01b0382165f90815260026020526040902042905561165584848484612aca565b803314612083576337cf6ad55f526004601cfd5b6001600160a01b0381165f9081526020819052604090205460ff1661208357604051634f3013c560e01b815260040160405180910390fd5b604051630225e24360e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630225e243906024015b602060405180830381865afa1580156128ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128d09190614867565b6128e1576128e16337cf6ad56128e3565b565b805f526004601cfd5b5f816001600160a01b031663565d878c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612929573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7591906149c8565b5f61295788612811565b61296086613555565b82156129bc578115612994578387111561298d576040516378a198b960e11b815260040160405180910390fd5b50856129bc565b8461299f8886614835565b106129bc57846129af8886614835565b6129b991906148c7565b90505b8015806129ee57506001600160a01b038089165f908152600160209081526040808320938a1683529290522054600214155b611397575f612a278760405180608001604052808c6001600160a01b031681526020018581526020015f815260200160018152506135f8565b9150508015612a49576040516378a198b960e11b815260040160405180910390fd5b50979650505050505050565b6001600160a01b0381165f908152600260205260409020544290612a7c906104b090614835565b11156120835760405163792f8c5960e11b815260040160405180910390fd5b5f8115612ab457612aad858585613951565b9050612ac2565b612abf85858561395d565b90505b949350505050565b612ad3846127fd565b80612ae557635518d5cb5f526004601cfd5b6001600160a01b0384165f908152602081905260409020546301000000900460ff16600203612b2757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0384165f90815260066020526040902054811115612b5f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038085165f90815260016020908152604080832093861683529290522054600214612c1f576001600160a01b038481165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e59060600160405180910390a15b5f612c54836040518060800160405280886001600160a01b031681526020015f815260200187815260200160018152506135f8565b9150508015611642576040516378a198b960e11b815260040160405180910390fd5b60405163287530f760e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063287530f790602401612891565b5f5f5f5f5f5f612cd3876002613989565b925092509250612d106040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5b82811015612e2057848181518110612d2c57612d2c6149e3565b60200260200101519150816060015115612dc8575f612d748360800151868481518110612d5b57612d5b6149e3565b60200260200101518560400151600a6116199190614b01565b9050612d80818a614835565b83516001600160a01b03165f90815260208190526040902054909950612db6908290600160201b900462ffffff16612710613951565b612dc09089614835565b975050612e18565b60a082015115612e1857612e0b8260a00151858381518110612dec57612dec6149e3565b60200260200101518460400151600a612e059190614b01565b5f612a9b565b612e159087614835565b95505b600101612d12565b50505050509193909250565b612e846040518061012001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b612ec46040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b6001600160a01b0384165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c0830152909103612fdf57612fdf6365513fc16128e3565b612fe885613a48565b60a085015260408401526101008401526130217f00000000000000000000000000000000000000000000000000000000000000006128ec565b60405163035e6c1960e01b81526001600160a01b038781166004830152868116602483015260026044830152919091169063035e6c199060640160408051808303815f875af1158015613076573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061309a91906148a5565b60e085015260608401526001600160a01b03851680845260a082015162ffffff90811660208087019190915260c0840151909116604080870191909152805163313ce56760e01b8152905163313ce567926004808401939192918290030181865afa15801561310b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061312f9190614b1f565b61313a90600a614b01565b60808401526001600160a01b03841660a084018190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015613189573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131ad9190614b1f565b6131b890600a614b01565b60c084015260a08201515f036131e65761016081015161ffff90811660c08401526101808201511660e08301525b81604001515f0361320e5760e081015161ffff90811660608401526101008201511660808301525b509250929050565b5f5f5f6132238787613b7f565b60208701528086525f0361323e57505f91508190508061345f565b60e085015115613277576132628560e00151865f0151670de0b6b3a7640000613951565b8560c001516132719190614835565b60a08601525b6080850151156132b05761329b8560800151865f0151670de0b6b3a7640000613951565b85606001516132aa9190614835565b60408601525b5f6132f36132e48860e0015188604001516132cb9190614b38565b6d04ee2d6d415b85acef81000000008a60600151613e5a565b88608001518960c00151613e5a565b90505f61271087602001518860a0015161330d9190614b38565b6133179190614848565b905085613322578099505b61333c8a836ec097ce7bc90715b34b9f1000000000613e5a565b885160405163e28d591d60e01b81526001600160a01b038c811660048301529297505f929091169063e28d591d90602401602060405180830381865afa158015613388573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ac9190614b4f565b905086156133d857818b11806133c157508086115b156133d3576133d36365513fc16128e3565b6133f1565b808611156133f1576133eb8b8288613ef6565b9a508095505b5f6134108960200151856ec097ce7bc90715b34b9f1000000000613ef6565b905081811115613457576134258c8284613ef6565b9450886020015185111561344a578b896020015161344391906148c7565b9450613457565b6134548c866148c7565b94505b508a94505050505b955095509592505050565b5f61347483613f22565b801561348557506134858383613f54565b9392505050565b60605f5f846001600160a01b03165f856040516134a99190614b66565b5f6040518083038185875af1925050503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b606091505b50915091506134f8858383613fd7565b95945050505050565b60605f5f846001600160a01b03168460405161351d9190614b66565b5f60405180830381855af49150503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b6040516373578c6760e01b81526001600160a01b0382811660048301527f000000000000000000000000000000000000000000000000000000000000000016906373578c6790602401602060405180830381865afa1580156135b9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135dd9190614867565b156135ef576135ef6337cf6ad56128e3565b61208381612a55565b5f5f5f5f5f61360b878760600151613989565b9250925092506136486040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5f5f5b8481101561391157868181518110613666576136666149e3565b60200260200101519350835f01516001600160a01b03168a5f01516001600160a01b0316148015613698575083606001515b80156136a757505f8a60400151115b15613796575f6136d67f00000000000000000000000000000000000000000000000000000000000000006128ec565b6001600160a01b0316635ae69163866020015160015f6040518463ffffffff1660e01b815260040161370a93929190614882565b6040805180830381865afa158015613724573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061374891906148a5565b88848151811061375a5761375a6149e3565b602002602001018193508281525050508a60600151811061378e57604051631db384db60e11b815260040160405180910390fd5b505f60608501525b83606001511561384f5783518a516001600160a01b039182169116036137d0578960200151846080018181516137cc91906148c7565b9052505b60808401511561384a5761383d61381085608001518884815181106137f7576137f76149e3565b60200260200101518760400151600a6116199190614b01565b85516001600160a01b03165f90815260208190526040902054600160201b900462ffffff16612710613951565b6138479084614835565b92505b613909565b83518a516001600160a01b0391821691160361387f5789604001518460a00181815161387b9190614835565b9052505b60a084015115613909576138bc8460a001518783815181106138a3576138a36149e3565b60200260200101518660400151600a612e059190614b01565b6138c69083614835565b91507f000000000000000000000000000000000000000000000000000000000000000082101561390957604051632e7cf4cd60e11b815260040160405180910390fd5b60010161364c565b50808211156139345761392481836148c7565b5f9750975050505050505061394a565b5f61393f83836148c7565b975097505050505050505b9250929050565b5f612ac284848461401f565b5f825f19048411830215820261397a5763ad251c275f526004601cfd5b50910281810615159190040190565b6060805f6139b67f00000000000000000000000000000000000000000000000000000000000000006128ec565b6001600160a01b038681165f9081526002602052604090819020905162020bc560e21b8152929091169162082f14916139f9918991600101908990600401614b7c565b5f604051808303815f875af1158015613a14573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613a3b9190810190614c4a565b9250925092509250925092565b5f80808080805f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c169250925092505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663572e2fa26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ad1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613af59190614867565b90506001600160a01b03848116908916148180613b0f5750805b15613b6d57818015613b1e5750805b15613b5457507f000000000000000000000000000000000000000000000000000000000000000096509194509250611e4b915050565b60405163fac97a2b60e01b815260040160405180910390fd5b505f9889985088975095505050505050565b5f5f613ba260405180606001604052805f81526020015f81526020015f81525090565b6001600160a01b0385165f90815260026020908152604080832060010180548251818502810185019093528083529192909190830182828015613c0c57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613bee575b505050505090505f5f825190505f5b81811015613da5578381613c2e81614d80565b925081518110613c4057613c406149e3565b60200260200101519250875f01516001600160a01b0316836001600160a01b031603613d0157608088015160208901516040808b015160608c01518c51925163e28d591d60e01b81526001600160a01b038f81166004830152613cf5969594169063e28d591d90602401602060405180830381865afa158015613cc5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ce99190614b4f565b8a5160208c0151614043565b60208701528552613c1b565b60a08801516040516311005b0760e01b81526001600160a01b038b81166004830152909116906311005b0790602401602060405180830381865afa158015613d4b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d6f9190614b4f565b95508515613da057613d8b868960e001518a60c001515f612a9b565b85604001818151613d9c9190614835565b9052505b613c1b565b5061010087015115613de657613dc6845f0151886101000151612710613951565b84526020840151610100880151613de09190612710613951565b60208501525b6040840151845110613dfa575f9550613e4f565b836020015184604001511015613e425783516040850151613e3d91613e1e916148c7565b85516020870151670de0b6b3a764000091613e38916148c7565b61395d565b613e4c565b670de0b6b3a76400005b95505b505050509250929050565b8282025f198385098181108201900380613e895782613e805763ae47f7025f526004601cfd5b50819004613485565b808311613e9d5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f613f02848484613e5a565b9050818385091561348557600101806134855763ae47f7025f526004601cfd5b5f613f34826301ffc9a760e01b613f54565b8015610a755750613f4d826001600160e01b0319613f54565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015613fc4575060208210155b8015611397575015159695505050505050565b6060613fe3838361409b565b8151158015613ffa57506001600160a01b0384163b155b15614018576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b5f825f19048411830215820261403c5763ad251c275f526004601cfd5b5091020490565b5f5f5f61271061405687898d6001612a9b565b6140609190614b38565b905061406c8982614848565b6140769086614835565b92506140828882614848565b61408c9085614835565b91505097509795505050505050565b81611d755780515f036140c1576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f602082840312156140d9575f5ffd5b81356001600160e01b031981168114613485575f5ffd5b6001600160a01b0381168114612083575f5ffd5b803561410f816140f0565b919050565b5f60208284031215614124575f5ffd5b8135613485816140f0565b5f5f5f60608486031215614141575f5ffd5b833561414c816140f0565b9250602084013561415c816140f0565b929592945050506040919091013590565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156141a4576141a461416d565b60405290565b60405160e081016001600160401b03811182821017156141a4576141a461416d565b604051606081016001600160401b03811182821017156141a4576141a461416d565b60405160c081016001600160401b03811182821017156141a4576141a461416d565b604051601f8201601f191681016001600160401b03811182821017156142385761423861416d565b604052919050565b5f6101a0828403128015614252575f5ffd5b5061425b614181565b61426483614104565b81526020838101359082015260408084013590820152606080840135908201526080808401359082015260a0808401359082015260c0808401359082015260e080840135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013590820152610180928301359281019290925250919050565b8015158114612083575f5ffd5b5f5f5f5f5f5f60c0878903121561430e575f5ffd5b8635614319816140f0565b9550602087013594506040870135614330816140f0565b9350606087013592506080870135915060a087013561434e816142ec565b809150509295509295509295565b602080825282518282018190525f918401906040840190835b8181101561439c5783516001600160a01b0316835260209384019390920191600101614375565b509095945050505050565b5f5f604083850312156143b8575f5ffd5b82356143c3816140f0565b915060208301356143d3816142ec565b809150509250929050565b5f5f5f5f5f60a086880312156143f2575f5ffd5b85356143fd816140f0565b9450602086013593506040860135614414816140f0565b925060608601359150608086013561442b816140f0565b809150509295509295909350565b5f5f5f5f6080858703121561444c575f5ffd5b8435614457816140f0565b935060208501359250604085013561446e816140f0565b9396929550929360600135925050565b5f5f5f60608486031215614490575f5ffd5b833561449b816140f0565b95602085013595506040909401359392505050565b5f602082840312156144c0575f5ffd5b5035919050565b5f5f604083850312156144d8575f5ffd5b82356144e3816140f0565b915060208301356143d3816140f0565b5f60208284031215614503575f5ffd5b8135613485816142ec565b5f6001600160401b038211156145265761452661416d565b5060051b60200190565b5f5f83601f840112614540575f5ffd5b5081356001600160401b03811115614556575f5ffd5b6020830191508360208260051b850101111561394a575f5ffd5b5f60e08284031215614580575f5ffd5b6145886141aa565b90508135614595816140f0565b815260208201356145a5816140f0565b60208201526040828101359082015260608201356145c2816142ec565b60608201526080828101359082015260a0808301359082015260c09182013591810191909152919050565b5f5f5f5f5f6101408688031215614602575f5ffd5b85356001600160401b03811115614617575f5ffd5b8601601f81018813614627575f5ffd5b803561463a6146358261450e565b614210565b8082825260208201915060208360051b85010192508a83111561465b575f5ffd5b6020840193505b8284101561467d578335825260209384019390910190614662565b975061468f9250505060208701614104565b935060408601356001600160401b038111156146a9575f5ffd5b6146b588828901614530565b90945092506146c990508760608801614570565b90509295509295909350565b5f8151808452602084019350602083015f5b828110156147055781518652602095860195909101906001016146e7565b5093949350505050565b604081525f83516060604084015261472a60a08401826146d5565b9050602085015160608401526040850151608084015282810360208401526134f881856146d5565b5f5f60208385031215614763575f5ffd5b82356001600160401b03811115614778575f5ffd5b61478485828601614530565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561481557603f19878603018452614800858351614790565b945060209384019391909101906001016147e4565b50929695505050505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610a7557610a75614821565b5f8261486257634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215614877575f5ffd5b8151613485816142ec565b6001600160a01b0393909316835290151560208301521515604082015260600190565b5f5f604083850312156148b6575f5ffd5b505080516020909101519092909150565b81810381811115610a7557610a75614821565b6001815b6001841115614915578085048111156148f9576148f9614821565b600184161561490757908102905b60019390931c9280026148de565b935093915050565b5f8261492b57506001610a75565b8161493757505f610a75565b816001811461494d576002811461495757614973565b6001915050610a75565b60ff84111561496857614968614821565b50506001821b610a75565b5060208310610133831016604e8410600b8410161715614996575081810a610a75565b6149a25f1984846148da565b805f19048211156149b5576149b5614821565b029392505050565b5f613485838361491d565b5f602082840312156149d8575f5ffd5b8151613485816140f0565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112614a0b575f5ffd5b9190910192915050565b5f60608236031215614a25575f5ffd5b614a2d6141cc565b8235614a38816140f0565b81526020830135614a48816142ec565b602082015260408301356001600160401b03811115614a65575f5ffd5b830136601f820112614a75575f5ffd5b80356001600160401b03811115614a8e57614a8e61416d565b614aa1601f8201601f1916602001614210565b818152366020838501011115614ab5575f5ffd5b816020840160208301375f9181016020019190915260408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f90612abf90830184614790565b5f61348560ff84168361491d565b805160ff8116811461410f575f5ffd5b5f60208284031215614b2f575f5ffd5b61348582614b0f565b8082028115828204841417610a7557610a75614821565b5f60208284031215614b5f575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b6001600160a01b03841681526060602080830182905284549183018290525f85815290812090916080840190835b81811015614bd15783546001600160a01b0316835260019384019360209093019201614baa565b505060409390930193909352509392505050565b5f82601f830112614bf4575f5ffd5b8151614c026146358261450e565b8082825260208201915060208360051b860101925085831115614c23575f5ffd5b602085015b83811015614c40578051835260209283019201614c28565b5095945050505050565b5f5f5f60608486031215614c5c575f5ffd5b83516001600160401b03811115614c71575f5ffd5b8401601f81018613614c81575f5ffd5b8051614c8f6146358261450e565b80828252602082019150602060c08402850101925088831115614cb0575f5ffd5b6020840193505b82841015614d415760c0848a031215614cce575f5ffd5b614cd66141ee565b8451614ce1816140f0565b81526020850151614cf1816140f0565b6020820152614d0260408601614b0f565b60408201526060850151614d15816142ec565b60608201526080858101519082015260a08086015190820152825260c090930192602090910190614cb7565b8096505050505060208401516001600160401b03811115614d60575f5ffd5b614d6c86828701614be5565b604095909501519396949550929392505050565b5f60018201614d9157614d91614821565b506001019056fe1966ec4daf81281b2aba49348128e9b155301b8486bde131e0db16a52b730b82a26469706673582212203480a9d34d0738f022270141175efb5c96b0766841cbae8de67341217ab4a49d64736f6c634300081c00330000000000000000000000001310f352f1389969ece6741671c4b919523912ff0000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000000000000000000001

Deployed Bytecode

0x608060405234801561000f575f5ffd5b5060043610610387575f3560e01c80638a05a2e6116101df578063c03c24bb11610109578063d99f05e1116100a9578063ecdb97a011610079578063ecdb97a01461093f578063f794062e146109f4578063f96492c914610a1f578063fb2cb34e14610a32575f5ffd5b8063d99f05e1146108c4578063da11ee23146108eb578063e2f0ab011461090c578063e8bbf5d71461091f575f5ffd5b8063c8b5277e116100e4578063c8b5277e14610889578063ccb99c261461089c578063d53dc739146108af578063d78db3f1146108bc575f5ffd5b8063c03c24bb14610844578063c2ba474414610863578063c80fa87214610876575f5ffd5b8063a2675bcd1161017f578063afbe407a1161014f578063afbe407a146107f2578063b235d468146107fa578063b6606d1c1461081e578063b7b7f26014610831575f5ffd5b8063a2675bcd1461076c578063a2f88e49146107b6578063abf883cb146107bf578063af79b3ca146107e9575f5ffd5b8063901941f9116101ba578063901941f9146106dd57806397a5d5b5146107045780639b4e3822146107325780639d488a0c14610759575f5ffd5b80638a05a2e6146106905780638c75d4fe146106a35780638f73dcfa146106b6575f5ffd5b80633fd596ce116102c0578063699ba8b3116102605780637551cd48116102305780637551cd4814610644578063757942ea146106575780637beec6af1461066057806380a00b7414610669575f5ffd5b8063699ba8b31461059c5780636c3b426f146106095780636dac9023146106125780637148fa5414610631575f5ffd5b80634b3d3b581161029b5780634b3d3b58146105435780634b7e1ff114610556578063504d6b181461056957806363e12aa314610571575f5ffd5b80633fd596ce1461051e57806345a9bbde146105275780634b03195214610530575f5ffd5b80631e9fb63a1161032b5780632f7a4c65116103065780632f7a4c65146104b457806337142666146104db57806339a8bf38146105025780633e0cdfd31461050b575f5ffd5b80631e9fb63a146104785780632076d8e7146104815780632c62fa1014610494575f5ffd5b80630358e376116103665780630358e376146103e957806308799c63146103fe5780630a73e3911461041157806317c221c614610433575f5ffd5b80623c8bd41461038b57806301ffc9a7146103a7578063032886d9146103ca575b5f5ffd5b6103946104b081565b6040519081526020015b60405180910390f35b6103ba6103b53660046140c9565b610a45565b604051901515815260200161039e565b6103946103d8366004614114565b60056020525f908152604090205481565b6103fc6103f736600461412f565b610a7b565b005b6103fc61040c366004614240565b610be4565b6103ba61041f366004614114565b60076020525f908152604090205460ff1681565b5f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c16604080516001600160a01b03909416845260208401929092529082015260600161039e565b6103946126de81565b61039461048f3660046142f9565b611352565b6104a76104a2366004614114565b6113a2565b60405161039e919061435c565b6103947f000000000000000000000000000000000000000000000000000000000000261681565b6103947f0000000000000000000000000000000000000000000000000000000005ee417081565b61039461270681565b6103fc6105193660046143a7565b611418565b6103946126e881565b6103946125e081565b6103fc61053e3660046143de565b6114d1565b6103fc610551366004614439565b611649565b6103fc61056436600461447e565b61165b565b6103fc611836565b61058461057f3660046144b0565b611850565b6040516001600160a01b03909116815260200161039e565b6105ea6105aa366004614114565b6001600160a01b03165f90815260208190526040902054600260ff6101008304811682149362010000840482168314936301000000900490911690911490565b604080519315158452911515602084015215159082015260600161039e565b61039461261681565b610394610620366004614114565b60026020525f908152604090205481565b6103fc61063f3660046144c7565b611878565b6103fc6106523660046144c7565b611c73565b61039461138881565b6103946103e881565b6103947f000000000000000000000000000000000000000000000000000000000000000081565b6103fc61069e366004614114565b611d79565b6103fc6106b13660046144c7565b611e0a565b6105847f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff81565b6103947f000000000000000000000000000000000000000000000000000000000000270681565b610717610712366004614114565b611e38565b6040805193845260208401929092529082015260600161039e565b6103947f0000000000000000000000000000000000000000000000008ac7230489e8000081565b6103fc6107673660046144f3565b611e52565b61071761077a366004614114565b6001600160a01b03165f9081526020819052604090205462ffffff600160201b8204811692600160381b8304821692600160501b900490911690565b610394615b6881565b6103946107cd3660046144c7565b600160209081525f928352604080842090915290825290205481565b610394610bb881565b6104a7611ede565b60045461080c90610100900460ff1681565b60405160ff909116815260200161039e565b6103fc61082c3660046143a7565b611f3e565b61039461083f3660046142f9565b611ff5565b610394610852366004614114565b60066020525f908152604090205481565b6103fc610871366004614114565b61203a565b6103fc6108843660046143a7565b612086565b6103fc6108973660046144f3565b61214b565b6103fc6108aa3660046144f3565b6121d3565b60045461080c9060ff1681565b610394606481565b6103ba7f000000000000000000000000000000000000000000000000000000000000000181565b6108fe6108f93660046145ed565b61225d565b60405161039e92919061470f565b6103fc61091a366004614114565b6124c4565b61093261092d366004614752565b612575565b60405161039e91906147be565b6109b961094d366004614114565b6001600160a01b03165f9081526020819052604090205461ffff600160681b8204811692600160781b8304821692600160881b8104831692600160981b8204811692600160a81b8304821692600160b81b8104831692600160c81b8204811692600160d81b9092041690565b604080519889526020890197909752958701949094526060860192909252608085015260a084015260c083015260e08201526101000161039e565b6103ba610a02366004614114565b6001600160a01b03165f9081526020819052604090205460ff1690565b6103fc610a2d366004614439565b6127d7565b60045461080c9062010000900460ff1681565b5f6001600160e01b03198216634d6978eb60e11b1480610a7557506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a84836127fd565b80610a9657635518d5cb5f526004601cfd5b6001600160a01b0383165f9081526020819052604090205462010000900460ff16600203610ad757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0383165f90815260056020526040902054811115610b0f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038083165f81815260026020818152604080842042905594881683526001815284832093835292909252919091205414610bdf576001600160a01b038381165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e5906060015b60405180910390a15b505050565b8051610bef90612811565b610bf7612849565b7f000000000000000000000000000000000000000000000000000000000000261681602001511180610c2e5750615b688160400151115b80610c4157508060400151816060015110155b15610c5357610c536365513fc16128e3565b8060a001518160800151101580610c7157508060e001518160800151115b80610c8357508060c001518160800151105b80610c9657508060e001518160c0015110155b80610ca65750610bb88160e00151115b80610cb3575060c0810151155b80610cc35750610bb88160a00151115b15610cd557610cd56365513fc16128e3565b806060015160648260a00151610ceb9190614835565b1180610d0a5750806060015160648260e00151610d089190614835565b115b15610d1c57610d1c6365513fc16128e3565b6113888161010001511180610d3757506103e8816101000151105b15610d4957610d496365513fc16128e3565b8061014001518161010001511180610d6a5750806101200151816101000151105b80610d7f575080610140015181610120015110155b80610d8d5750610120810151155b80610d9e5750612710816101400151115b15610db057610db06365513fc16128e3565b6040810151610dc190612710614835565b610deb907f0000000000000000000000000000000000000000000000000000000005ee4170614848565b81602001511115610e0357610e036365513fc16128e3565b6020810151158015610e1957505f816101600151115b15610e2b57610e2b6365513fc16128e3565b61018081015115610ecc5761018081015170ffffffffffffffffffffffffffffffffff1080610eba5750805f01516001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e94573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eb89190614867565b155b15610ecc57610ecc6365513fc16128e3565b80516001600160a01b03165f9081526020819052604090208054600160201b900462ffffff1615801590610f0257506020820151155b15610f1457610f146365513fc16128e3565b5f610f3e7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae6916391610f71916001908190600401614882565b6040805180830381865afa158015610f8b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faf91906148a5565b91505060028103610fd35760405163583c953760e01b815260040160405180910390fd5b610ffc7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b8351604051635ae6916360e01b81526001600160a01b039290921691635ae691639161102f916001905f90600401614882565b6040805180830381865afa158015611049573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061106d91906148a5565b91505060011981016110925760405163583c953760e01b815260040160405180910390fd5b6020830151825462ffffff909116600160201b0266ffffff000000001990911617825560408301516110c79061271090614835565b825462ffffff91909116600160381b0269ffffff000000000000001990911617825560608301516110fb9061271090614835565b825462ffffff91909116600160501b0262ffffff60501b19909116178255608083015161112a90612710614835565b825461ffff91909116600160681b0261ffff60681b1990911617825560c083015161115790612710614835565b825461ffff91909116600160881b0261ffff60881b1990911617825560e083015161118490612710614835565b825461ffff91909116600160981b0261ffff60981b19909116178255608083015160a08401516111b491906148c7565b825461010085015167ffff00000000ffff60781b19909116600160781b61ffff9384160261ffff60a81b191617600160a81b928216929092029190911783556111ff906127106148c7565b825461012085015161014086015163ffffffff60b81b19909216600160b81b61ffff9485160261ffff60c81b191617600160c81b918416919091021761ffff60d81b1916600160d81b929091169190910217825561016083015183516001600160a01b039081165f90815260056020908152604080832094909455610180870151875190931682526006905282902055517f7118653a594971f43f27090077f0b05efeaf77dd61915894fa826f79ca0ab5b890610bd690859081516001600160a01b031681526101a081016020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010083015161010083015261012083015161012083015261014083015161014083015261016083015161016083015261018083015161018083015292915050565b5f61135c876127fd565b600454610100900460ff1660020361138757604051633d1cc8fd60e21b815260040160405180910390fd5b611397878787878760018861294d565b979650505050505050565b6001600160a01b0381165f9081526002602090815260409182902060010180548351818402810184019094528084526060939283018282801561140c57602002820191905f5260205f20905b81546001600160a01b031681526001909101906020018083116113ee575b50505050509050919050565b611420612849565b61142982612811565b80611435576001611438565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff959095166101000261ff00199095169490941790935580519182526060928201839052600b928201929092526a135a5b9d0814185d5cd95960aa1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0015b60405180910390a15050565b6114da856127fd565b6114e385612811565b6114ec81612a55565b6001600160a01b038086165f90815260016020908152604080832093851683529290522054600214611525576115256365513fc16128e3565b8315611642575f5f6115567f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b6001600160a01b0316635ae69163866001806040518463ffffffff1660e01b815260040161158693929190614882565b6040805180830381865afa1580156115a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c491906148a5565b915091505f81146115e85760405163583c953760e01b815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000008ac7230489e80000611620878461161988600a6149bd565b6001612a9b565b101561163f57604051632e7cf4cd60e11b815260040160405180910390fd5b50505b5050505050565b61165584848484612aca565b50505050565b611663612c76565b61166c83612811565b6001600160a01b0383165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c08301529091036117935760405163fac97a2b60e01b815260040160405180910390fd5b82158015906117bc575080610120015161ffff168310806117bc575080610140015161ffff1683115b156117ce576117ce6365513fc16128e3565b81158015906117f75750806101a0015161ffff168210806117f75750806101c0015161ffff1682115b15611809576118096365513fc16128e3565b60a083901b60b083901b176001600160a01b03851617805f516020614d995f395f51905f525d5050505050565b61183e612c76565b5f5f516020614d995f395f51905f525d565b6003818154811061185f575f80fd5b5f918252602090912001546001600160a01b0316905081565b611880612849565b806001600160a01b0316826001600160a01b0316036118a6576118a66365513fc16128e3565b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118e2573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190691906149c8565b6001600160a01b0316826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561194b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196f91906149c8565b6001600160a01b03160361198a5761198a6365513fc16128e3565b6003541561199f5761199f6365513fc16128e3565b816001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119ff9190614867565b158015611a695750806001600160a01b03166345d7b97a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a43573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a679190614867565b155b15611a7b57611a7b6365513fc16128e3565b6001600160a01b038281165f818152602081905260408082208054600160ff19918216811790925594861683529181902080549094169091179092559051637ada7a0960e01b8152336004820152637ada7a09906024016020604051808303815f875af1158015611aee573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b129190614867565b611b2357611b23635518d5cb6128e3565b604051637ada7a0960e01b81523360048201526001600160a01b03821690637ada7a09906024016020604051808303815f875af1158015611b66573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b8a9190614867565b611b9b57611b9b635518d5cb6128e3565b60038054600180820183555f8390527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b91820180546001600160a01b03199081166001600160a01b0388811691821790935585549384019095559190920180549091169184169190911790556040519081527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a99060200160405180910390a16040516001600160a01b03821681527f017664858438d89f547fee46da0bcfc5396ea13a9fb1490b8fdd76cfa979f1a9906020016114c5565b611c7c82612811565b611c8581612811565b806001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cc1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ce591906149c8565b6001600160a01b0316826001600160a01b03166341ed2c126040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d2a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d4e91906149c8565b6001600160a01b031614611d7557604051631284375160e11b815260040160405180910390fd5b5050565b611d81612849565b6001600160a01b0381165f9081526007602052604090205460ff16611dad57611dad6365513fc16128e3565b6001600160a01b0381165f818152600760209081526040808320805460ff191690558051938452908301919091527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a1691015b60405180910390a150565b611e13826127fd565b611e1c82612811565b6001600160a01b03165f90815260026020526040902042905550565b5f5f5f611e4484612cc2565b9250925092505b9193909250565b611e5a612849565b80611e66576001611e69565b60025b600460026101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600f908201526e151c985b9cd9995c8814185d5cd959608a1b6060820152901515602082015260800190565b60606003805480602002602001604051908101604052809291908181526020018280548015611f3457602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611f16575b5050505050905090565b611f46612849565b611f4f82612811565b80611f5b576001611f5e565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff9590951663010000000263ff000000199095169490941790935580519182526060928201839052600d928201929092526c109bdc9c9bddc814185d5cd959609a1b6080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b5f611fff876127fd565b60045462010000900460ff1660020361202b57604051633d1cc8fd60e21b815260040160405180910390fd5b6113978787878787875f61294d565b6001600160a01b0381165f90815260208190526040902054610100900460ff1660020361207a57604051633d1cc8fd60e21b815260040160405180910390fd5b61208381612811565b50565b61208e612849565b61209782612811565b806120a35760016120a6565b60025b6001600160a01b0383165f8181526020818152604091829020805460ff95909516620100000262ff00001990951694909417909355805191825260609282018390526018928201929092527f436f6c6c61746572616c697a6174696f6e2050617573656400000000000000006080820152821515918101919091527f359e41b7f6189b08ab0ad7b56dfc630860095deba215f7d1e24f126d048ac6219060a0016114c5565b612153612849565b8061215f576001612162565b60025b6004805460ff191660ff929092169190911790556040805181815260129181019190915271131a5c5d5a59185d1a5bdb8814185d5cd95960721b606082015281151560208201527fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de090608001611dff565b6121db612849565b806121e75760016121ea565b60025b600460016101000a81548160ff021916908360ff1602179055507fef159d9a32b2472e32b098f954f3ce62d232939f1c207070b584df1814de2de081604051611dff91906040808252600d908201526c14995919595b4814185d5cd959609a1b6060820152901515602082015260800190565b61227f6040518060600160405280606081526020015f81526020015f81525090565b60045460609060ff166002036122a857604051633d1cc8fd60e21b815260040160405180910390fd5b6122b583602001516127fd565b82516122c090612811565b6122cd8360200151612811565b5f5f6122e0855f01518660200151612e2c565b9150915084604001516001600160401b038111156123005761230061416d565b604051908082528060200260200182016040528015612329578160200160208202803683370190505b5084525f80805b87604001518110156124915789898281811061234e5761234e6149e3565b90506020020160208101906123639190614114565b9250826001600160a01b03168b6001600160a01b03160361238b5761238b6337cf6ad56128e3565b826001600160a01b0316826001600160a01b0316106123b1576123b16337cf6ad56128e3565b6123db8c82815181106123c6576123c66149e3565b60200260200101518487878c60600151613216565b60c08b015260a08a0181905260808a0191909152602088018051612400908390614835565b9052506080880151875180518390811061241c5761241c6149e3565b602090810291909101015260c088015115612464578760c00151876040018181516124479190614835565b90525060c088015160a089018051612460908390614835565b9052505b8760a001518c828151811061247b5761247b6149e3565b6020908102919091010152829150600101612330565b5085602001515f036124b6576040516311d1870d60e11b815260040160405180910390fd5b509399975050505050505050565b6124cc612849565b6124dd816316bb16f160e11b61346a565b6124ee576124ee6365513fc16128e3565b6001600160a01b0381165f9081526007602052604090205460ff161561251b5761251b6365513fc16128e3565b6001600160a01b0381165f81815260076020908152604091829020805460ff191660019081179091558251938452908301527f95f28d5f3b25ba2ec0ace967a30ee05f0ff47e77f8c63e8fe5fc009f95894a169101611dff565b60607f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff82806001600160401b038111156125b1576125b161416d565b6040519080825280602002602001820160405280156125e457816020015b60608152602001906001900390816125cf5790505b5060408051606080820183525f80835260208301819052928201529194505b828110156127cd5786868281811061261d5761261d6149e3565b905060200281019061262f91906149f7565b61263890614a15565b915081602001511561276f57815160405163191d0cc560e11b81526001600160a01b0391821660048201525f9186169063323a198a90602401602060405180830381865afa15801561268c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126b091906149c8565b90506001600160a01b0381166126d957604051632f3285fb60e21b815260040160405180910390fd5b8251604080850151905163bd0226d760e01b81526001600160a01b0384169263bd0226d79261270e9233929190600401614ad6565b5f604051808303815f87803b158015612725575f5ffd5b505af1158015612737573d5f5f3e3d5ffd5b5050505061274c835f0151846040015161348c565b86838151811061275e5761275e6149e3565b6020026020010181905250506127c5565b81516001600160a01b0316301461279957604051637720ccd960e01b815260040160405180910390fd5b6127a7308360400151613501565b8582815181106127b9576127b96149e3565b60200260200101819052505b600101612603565b5050505092915050565b6001600160a01b0382165f90815260026020526040902042905561165584848484612aca565b803314612083576337cf6ad55f526004601cfd5b6001600160a01b0381165f9081526020819052604090205460ff1661208357604051634f3013c560e01b815260040160405180910390fd5b604051630225e24360e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031690630225e243906024015b602060405180830381865afa1580156128ac573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128d09190614867565b6128e1576128e16337cf6ad56128e3565b565b805f526004601cfd5b5f816001600160a01b031663565d878c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612929573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7591906149c8565b5f61295788612811565b61296086613555565b82156129bc578115612994578387111561298d576040516378a198b960e11b815260040160405180910390fd5b50856129bc565b8461299f8886614835565b106129bc57846129af8886614835565b6129b991906148c7565b90505b8015806129ee57506001600160a01b038089165f908152600160209081526040808320938a1683529290522054600214155b611397575f612a278760405180608001604052808c6001600160a01b031681526020018581526020015f815260200160018152506135f8565b9150508015612a49576040516378a198b960e11b815260040160405180910390fd5b50979650505050505050565b6001600160a01b0381165f908152600260205260409020544290612a7c906104b090614835565b11156120835760405163792f8c5960e11b815260040160405180910390fd5b5f8115612ab457612aad858585613951565b9050612ac2565b612abf85858561395d565b90505b949350505050565b612ad3846127fd565b80612ae557635518d5cb5f526004601cfd5b6001600160a01b0384165f908152602081905260409020546301000000900460ff16600203612b2757604051633d1cc8fd60e21b815260040160405180910390fd5b6001600160a01b0384165f90815260066020526040902054811115612b5f57604051633448aa9d60e01b815260040160405180910390fd5b6001600160a01b038085165f90815260016020908152604080832093861683529290522054600214612c1f576001600160a01b038481165f81815260016020818152604080842095881680855295825280842060029081905582528084208301805480850182559085529382902090930180546001600160a01b0319168517905582519384528301939093528101919091527f5cbb919307f3804aff990e94bdc923c0878589779d539552a35353302b8ed8e59060600160405180910390a15b5f612c54836040518060800160405280886001600160a01b031681526020015f815260200187815260200160018152506135f8565b9150508015611642576040516378a198b960e11b815260040160405180910390fd5b60405163287530f760e01b81523360048201527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b03169063287530f790602401612891565b5f5f5f5f5f5f612cd3876002613989565b925092509250612d106040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5b82811015612e2057848181518110612d2c57612d2c6149e3565b60200260200101519150816060015115612dc8575f612d748360800151868481518110612d5b57612d5b6149e3565b60200260200101518560400151600a6116199190614b01565b9050612d80818a614835565b83516001600160a01b03165f90815260208190526040902054909950612db6908290600160201b900462ffffff16612710613951565b612dc09089614835565b975050612e18565b60a082015115612e1857612e0b8260a00151858381518110612dec57612dec6149e3565b60200260200101518460400151600a612e059190614b01565b5f612a9b565b612e159087614835565b95505b600101612d12565b50505050509193909250565b612e846040518061012001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f81526020015f81526020015f81525090565b612ec46040518061010001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b6001600160a01b0384165f9081526020818152604080832081516101e081018352905460ff8082161515835261010080830482169584019590955262010000820481169383019390935263010000008104909216606082015262ffffff600160201b8304811660808301819052600160381b8404821660a0840152600160501b840490911660c083015261ffff600160681b8404811660e0840152600160781b8404811694830194909452600160881b83048416610120830152600160981b83048416610140830152600160a81b83048416610160830152600160b81b83048416610180830152600160c81b830484166101a0830152600160d81b9092049092166101c0830152909103612fdf57612fdf6365513fc16128e3565b612fe885613a48565b60a085015260408401526101008401526130217f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b60405163035e6c1960e01b81526001600160a01b038781166004830152868116602483015260026044830152919091169063035e6c199060640160408051808303815f875af1158015613076573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061309a91906148a5565b60e085015260608401526001600160a01b03851680845260a082015162ffffff90811660208087019190915260c0840151909116604080870191909152805163313ce56760e01b8152905163313ce567926004808401939192918290030181865afa15801561310b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061312f9190614b1f565b61313a90600a614b01565b60808401526001600160a01b03841660a084018190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015613189573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131ad9190614b1f565b6131b890600a614b01565b60c084015260a08201515f036131e65761016081015161ffff90811660c08401526101808201511660e08301525b81604001515f0361320e5760e081015161ffff90811660608401526101008201511660808301525b509250929050565b5f5f5f6132238787613b7f565b60208701528086525f0361323e57505f91508190508061345f565b60e085015115613277576132628560e00151865f0151670de0b6b3a7640000613951565b8560c001516132719190614835565b60a08601525b6080850151156132b05761329b8560800151865f0151670de0b6b3a7640000613951565b85606001516132aa9190614835565b60408601525b5f6132f36132e48860e0015188604001516132cb9190614b38565b6d04ee2d6d415b85acef81000000008a60600151613e5a565b88608001518960c00151613e5a565b90505f61271087602001518860a0015161330d9190614b38565b6133179190614848565b905085613322578099505b61333c8a836ec097ce7bc90715b34b9f1000000000613e5a565b885160405163e28d591d60e01b81526001600160a01b038c811660048301529297505f929091169063e28d591d90602401602060405180830381865afa158015613388573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133ac9190614b4f565b905086156133d857818b11806133c157508086115b156133d3576133d36365513fc16128e3565b6133f1565b808611156133f1576133eb8b8288613ef6565b9a508095505b5f6134108960200151856ec097ce7bc90715b34b9f1000000000613ef6565b905081811115613457576134258c8284613ef6565b9450886020015185111561344a578b896020015161344391906148c7565b9450613457565b6134548c866148c7565b94505b508a94505050505b955095509592505050565b5f61347483613f22565b801561348557506134858383613f54565b9392505050565b60605f5f846001600160a01b03165f856040516134a99190614b66565b5f6040518083038185875af1925050503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b606091505b50915091506134f8858383613fd7565b95945050505050565b60605f5f846001600160a01b03168460405161351d9190614b66565b5f60405180830381855af49150503d805f81146134e3576040519150601f19603f3d011682016040523d82523d5f602084013e6134e8565b6040516373578c6760e01b81526001600160a01b0382811660048301527f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff16906373578c6790602401602060405180830381865afa1580156135b9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135dd9190614867565b156135ef576135ef6337cf6ad56128e3565b61208381612a55565b5f5f5f5f5f61360b878760600151613989565b9250925092506136486040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a081019190915290565b5f5f5f5b8481101561391157868181518110613666576136666149e3565b60200260200101519350835f01516001600160a01b03168a5f01516001600160a01b0316148015613698575083606001515b80156136a757505f8a60400151115b15613796575f6136d67f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b6001600160a01b0316635ae69163866020015160015f6040518463ffffffff1660e01b815260040161370a93929190614882565b6040805180830381865afa158015613724573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061374891906148a5565b88848151811061375a5761375a6149e3565b602002602001018193508281525050508a60600151811061378e57604051631db384db60e11b815260040160405180910390fd5b505f60608501525b83606001511561384f5783518a516001600160a01b039182169116036137d0578960200151846080018181516137cc91906148c7565b9052505b60808401511561384a5761383d61381085608001518884815181106137f7576137f76149e3565b60200260200101518760400151600a6116199190614b01565b85516001600160a01b03165f90815260208190526040902054600160201b900462ffffff16612710613951565b6138479084614835565b92505b613909565b83518a516001600160a01b0391821691160361387f5789604001518460a00181815161387b9190614835565b9052505b60a084015115613909576138bc8460a001518783815181106138a3576138a36149e3565b60200260200101518660400151600a612e059190614b01565b6138c69083614835565b91507f0000000000000000000000000000000000000000000000008ac7230489e8000082101561390957604051632e7cf4cd60e11b815260040160405180910390fd5b60010161364c565b50808211156139345761392481836148c7565b5f9750975050505050505061394a565b5f61393f83836148c7565b975097505050505050505b9250929050565b5f612ac284848461401f565b5f825f19048411830215820261397a5763ad251c275f526004601cfd5b50910281810615159190040190565b6060805f6139b67f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6128ec565b6001600160a01b038681165f9081526002602052604090819020905162020bc560e21b8152929091169162082f14916139f9918991600101908990600401614b7c565b5f604051808303815f875af1158015613a14573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613a3b9190810190614c4a565b9250925092509250925092565b5f80808080805f516020614d995f395f51905f525c61ffff60a082901c81169060b083901c169250925092505f7f0000000000000000000000001310f352f1389969ece6741671c4b919523912ff6001600160a01b031663572e2fa26040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ad1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613af59190614867565b90506001600160a01b03848116908916148180613b0f5750805b15613b6d57818015613b1e5750805b15613b5457507f000000000000000000000000000000000000000000000000000000000000270696509194509250611e4b915050565b60405163fac97a2b60e01b815260040160405180910390fd5b505f9889985088975095505050505050565b5f5f613ba260405180606001604052805f81526020015f81526020015f81525090565b6001600160a01b0385165f90815260026020908152604080832060010180548251818502810185019093528083529192909190830182828015613c0c57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613bee575b505050505090505f5f825190505f5b81811015613da5578381613c2e81614d80565b925081518110613c4057613c406149e3565b60200260200101519250875f01516001600160a01b0316836001600160a01b031603613d0157608088015160208901516040808b015160608c01518c51925163e28d591d60e01b81526001600160a01b038f81166004830152613cf5969594169063e28d591d90602401602060405180830381865afa158015613cc5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ce99190614b4f565b8a5160208c0151614043565b60208701528552613c1b565b60a08801516040516311005b0760e01b81526001600160a01b038b81166004830152909116906311005b0790602401602060405180830381865afa158015613d4b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d6f9190614b4f565b95508515613da057613d8b868960e001518a60c001515f612a9b565b85604001818151613d9c9190614835565b9052505b613c1b565b5061010087015115613de657613dc6845f0151886101000151612710613951565b84526020840151610100880151613de09190612710613951565b60208501525b6040840151845110613dfa575f9550613e4f565b836020015184604001511015613e425783516040850151613e3d91613e1e916148c7565b85516020870151670de0b6b3a764000091613e38916148c7565b61395d565b613e4c565b670de0b6b3a76400005b95505b505050509250929050565b8282025f198385098181108201900380613e895782613e805763ae47f7025f526004601cfd5b50819004613485565b808311613e9d5763ae47f7025f526004601cfd5b828486095f84810385169485900494848311909303908390038390046001010292030417600260038302811880840282030280840282030280840282030280840282030280840282030280840290910302029392505050565b5f613f02848484613e5a565b9050818385091561348557600101806134855763ae47f7025f526004601cfd5b5f613f34826301ffc9a760e01b613f54565b8015610a755750613f4d826001600160e01b0319613f54565b1592915050565b6040516001600160e01b0319821660248201525f90819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b17815282519293505f9283928392909183918a617530fa92503d91505f519050828015613fc4575060208210155b8015611397575015159695505050505050565b6060613fe3838361409b565b8151158015613ffa57506001600160a01b0384163b155b15614018576040516314859aeb60e21b815260040160405180910390fd5b5092915050565b5f825f19048411830215820261403c5763ad251c275f526004601cfd5b5091020490565b5f5f5f61271061405687898d6001612a9b565b6140609190614b38565b905061406c8982614848565b6140769086614835565b92506140828882614848565b61408c9085614835565b91505097509795505050505050565b81611d755780515f036140c1576040516314859aeb60e21b815260040160405180910390fd5b805181602001fd5b5f602082840312156140d9575f5ffd5b81356001600160e01b031981168114613485575f5ffd5b6001600160a01b0381168114612083575f5ffd5b803561410f816140f0565b919050565b5f60208284031215614124575f5ffd5b8135613485816140f0565b5f5f5f60608486031215614141575f5ffd5b833561414c816140f0565b9250602084013561415c816140f0565b929592945050506040919091013590565b634e487b7160e01b5f52604160045260245ffd5b6040516101a081016001600160401b03811182821017156141a4576141a461416d565b60405290565b60405160e081016001600160401b03811182821017156141a4576141a461416d565b604051606081016001600160401b03811182821017156141a4576141a461416d565b60405160c081016001600160401b03811182821017156141a4576141a461416d565b604051601f8201601f191681016001600160401b03811182821017156142385761423861416d565b604052919050565b5f6101a0828403128015614252575f5ffd5b5061425b614181565b61426483614104565b81526020838101359082015260408084013590820152606080840135908201526080808401359082015260a0808401359082015260c0808401359082015260e080840135908201526101008084013590820152610120808401359082015261014080840135908201526101608084013590820152610180928301359281019290925250919050565b8015158114612083575f5ffd5b5f5f5f5f5f5f60c0878903121561430e575f5ffd5b8635614319816140f0565b9550602087013594506040870135614330816140f0565b9350606087013592506080870135915060a087013561434e816142ec565b809150509295509295509295565b602080825282518282018190525f918401906040840190835b8181101561439c5783516001600160a01b0316835260209384019390920191600101614375565b509095945050505050565b5f5f604083850312156143b8575f5ffd5b82356143c3816140f0565b915060208301356143d3816142ec565b809150509250929050565b5f5f5f5f5f60a086880312156143f2575f5ffd5b85356143fd816140f0565b9450602086013593506040860135614414816140f0565b925060608601359150608086013561442b816140f0565b809150509295509295909350565b5f5f5f5f6080858703121561444c575f5ffd5b8435614457816140f0565b935060208501359250604085013561446e816140f0565b9396929550929360600135925050565b5f5f5f60608486031215614490575f5ffd5b833561449b816140f0565b95602085013595506040909401359392505050565b5f602082840312156144c0575f5ffd5b5035919050565b5f5f604083850312156144d8575f5ffd5b82356144e3816140f0565b915060208301356143d3816140f0565b5f60208284031215614503575f5ffd5b8135613485816142ec565b5f6001600160401b038211156145265761452661416d565b5060051b60200190565b5f5f83601f840112614540575f5ffd5b5081356001600160401b03811115614556575f5ffd5b6020830191508360208260051b850101111561394a575f5ffd5b5f60e08284031215614580575f5ffd5b6145886141aa565b90508135614595816140f0565b815260208201356145a5816140f0565b60208201526040828101359082015260608201356145c2816142ec565b60608201526080828101359082015260a0808301359082015260c09182013591810191909152919050565b5f5f5f5f5f6101408688031215614602575f5ffd5b85356001600160401b03811115614617575f5ffd5b8601601f81018813614627575f5ffd5b803561463a6146358261450e565b614210565b8082825260208201915060208360051b85010192508a83111561465b575f5ffd5b6020840193505b8284101561467d578335825260209384019390910190614662565b975061468f9250505060208701614104565b935060408601356001600160401b038111156146a9575f5ffd5b6146b588828901614530565b90945092506146c990508760608801614570565b90509295509295909350565b5f8151808452602084019350602083015f5b828110156147055781518652602095860195909101906001016146e7565b5093949350505050565b604081525f83516060604084015261472a60a08401826146d5565b9050602085015160608401526040850151608084015282810360208401526134f881856146d5565b5f5f60208385031215614763575f5ffd5b82356001600160401b03811115614778575f5ffd5b61478485828601614530565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b8281101561481557603f19878603018452614800858351614790565b945060209384019391909101906001016147e4565b50929695505050505050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610a7557610a75614821565b5f8261486257634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215614877575f5ffd5b8151613485816142ec565b6001600160a01b0393909316835290151560208301521515604082015260600190565b5f5f604083850312156148b6575f5ffd5b505080516020909101519092909150565b81810381811115610a7557610a75614821565b6001815b6001841115614915578085048111156148f9576148f9614821565b600184161561490757908102905b60019390931c9280026148de565b935093915050565b5f8261492b57506001610a75565b8161493757505f610a75565b816001811461494d576002811461495757614973565b6001915050610a75565b60ff84111561496857614968614821565b50506001821b610a75565b5060208310610133831016604e8410600b8410161715614996575081810a610a75565b6149a25f1984846148da565b805f19048211156149b5576149b5614821565b029392505050565b5f613485838361491d565b5f602082840312156149d8575f5ffd5b8151613485816140f0565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112614a0b575f5ffd5b9190910192915050565b5f60608236031215614a25575f5ffd5b614a2d6141cc565b8235614a38816140f0565b81526020830135614a48816142ec565b602082015260408301356001600160401b03811115614a65575f5ffd5b830136601f820112614a75575f5ffd5b80356001600160401b03811115614a8e57614a8e61416d565b614aa1601f8201601f1916602001614210565b818152366020838501011115614ab5575f5ffd5b816020840160208301375f9181016020019190915260408301525092915050565b6001600160a01b038481168252831660208201526060604082018190525f90612abf90830184614790565b5f61348560ff84168361491d565b805160ff8116811461410f575f5ffd5b5f60208284031215614b2f575f5ffd5b61348582614b0f565b8082028115828204841417610a7557610a75614821565b5f60208284031215614b5f575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b6001600160a01b03841681526060602080830182905284549183018290525f85815290812090916080840190835b81811015614bd15783546001600160a01b0316835260019384019360209093019201614baa565b505060409390930193909352509392505050565b5f82601f830112614bf4575f5ffd5b8151614c026146358261450e565b8082825260208201915060208360051b860101925085831115614c23575f5ffd5b602085015b83811015614c40578051835260209283019201614c28565b5095945050505050565b5f5f5f60608486031215614c5c575f5ffd5b83516001600160401b03811115614c71575f5ffd5b8401601f81018613614c81575f5ffd5b8051614c8f6146358261450e565b80828252602082019150602060c08402850101925088831115614cb0575f5ffd5b6020840193505b82841015614d415760c0848a031215614cce575f5ffd5b614cd66141ee565b8451614ce1816140f0565b81526020850151614cf1816140f0565b6020820152614d0260408601614b0f565b60408201526060850151614d15816142ec565b60608201526080858101519082015260a08086015190820152825260c090930192602090910190614cb7565b8096505050505060208401516001600160401b03811115614d60575f5ffd5b614d6c86828701614be5565b604095909501519396949550929392505050565b5f60018201614d9157614d91614821565b506001019056fe1966ec4daf81281b2aba49348128e9b155301b8486bde131e0db16a52b730b82a26469706673582212203480a9d34d0738f022270141175efb5c96b0766841cbae8de67341217ab4a49d64736f6c634300081c0033

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

0000000000000000000000001310f352f1389969ece6741671c4b919523912ff0000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000000000000000000001

-----Decoded View---------------
Arg [0] : cr (address): 0x1310f352f1389969Ece6741671c4B919523912fF
Arg [1] : minLoanSize (uint256): 10000000000000000000
Arg [2] : isCorrelatedMarket (bool): True

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000001310f352f1389969ece6741671c4b919523912ff
Arg [1] : 0000000000000000000000000000000000000000000000008ac7230489e80000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001


Deployed Bytecode Sourcemap

162397:77036:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;164452:52;;164494:10;164452:52;;;;;160:25:1;;;148:2;133:18;164452:52:0;;;;;;;;213149:234;;;;;;:::i;:::-;;:::i;:::-;;;652:14:1;;645:22;627:41;;615:2;600:18;213149:234:0;487:187:1;166863:49:0;;;;;;:::i;:::-;;;;;;;;;;;;;;175241:1760;;;;;;:::i;:::-;;:::i;:::-;;195619:7649;;;;;;:::i;:::-;;:::i;167290:49::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;212375:526;-1:-1:-1;;;;;;;;;;;212655:40:0;212773:54;165894:3;212792:34;;;212773:54;;;166056:3;212859:33;;;212838:55;212375:526;;;-1:-1:-1;;;;;5253:32:1;;;5235:51;;5317:2;5302:18;;5295:34;;;;5345:18;;;5338:34;5223:2;5208:18;212375:526:0;5033:345:1;138808:58:0;;138862:4;138808:58;;177858:628;;;;;;:::i;:::-;;:::i;173580:156::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;140186:39::-;;;;;139658:47;;;;;138405:56;;138457:4;138405:56;;205098:265;;;;;;:::i;:::-;;:::i;139308:62::-;;139366:4;139308:62;;138004:58;;138058:4;138004:58;;181211:1469;;;;;;:::i;:::-;;:::i;179058:206::-;;;;;;:::i;:::-;;:::i;208939:2121::-;;;;;;:::i;:::-;;:::i;211591:232::-;;;:::i;166192:29::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;9723:32:1;;;9705:51;;9693:2;9678:18;166192:29:0;9559:203:1;169953:380:0;;;;;;:::i;:::-;-1:-1:-1;;;;;170152:20:0;170025:15;170152:20;;;;;;;;;;170196:12;170212:1;170196:12;;;;;;:17;;;170250:25;;;;;:30;;;170306:14;;;;;;:19;;;;169953:380;;;;;9976:14:1;;9969:22;9951:41;;10035:14;;10028:22;10023:2;10008:18;;10001:50;10094:14;10087:22;10067:18;;;10060:50;9939:2;9924:18;169953:380:0;9767:349:1;137772:56:0;;137824:4;137772:56;;142093:52;;;;;;:::i;:::-;;;;;;;;;;;;;;191203:1783;;;;;;:::i;:::-;;:::i;188778:402::-;;;;;;:::i;:::-;;:::i;163910:47::-;;163953:4;163910:47;;164043;;164086:4;164043:47;;140818:56;;;;;207939:409;;;;;;:::i;:::-;;:::i;180467:213::-;;;;;;:::i;:::-;;:::i;141244:49::-;;;;;140538:39;;;;;174176:140;;;;;;:::i;:::-;;:::i;:::-;;;;10948:25:1;;;11004:2;10989:18;;10982:34;;;;11032:18;;;11025:34;10936:2;10921:18;174176:140:0;10746:319:1;141164:38:0;;;;;204518:189;;;;;;:::i;:::-;;:::i;170939:229::-;;;;;;:::i;:::-;-1:-1:-1;;;;;171079:20:0;171009:7;171079:20;;;;;;;;;;171118:11;;-1:-1:-1;;;171118:11:0;;;;;-1:-1:-1;;;171131:13:0;;;;;-1:-1:-1;;;171146:13:0;;;;;;170939:229;163186:58;;163239:5;163186:58;;141901:71;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;163659:56;;163711:4;163659:56;;173174:107;;;:::i;166504:29::-;;;;;;;;;;;;;;;11488:4:1;11476:17;;;11458:36;;11446:2;11431:18;166504:29:0;11316:184:1;206485:271:0;;;;;;:::i;:::-;;:::i;190009:594::-;;;;;;:::i;:::-;;:::i;167090:43::-;;;;;;:::i;:::-;;;;;;;;;;;;;;174502:212;;;;;;:::i;:::-;;:::i;205784:304::-;;;;;;:::i;:::-;;:::i;203561:198::-;;;;;;:::i;:::-;;:::i;204049:183::-;;;;;;:::i;:::-;;:::i;166356:34::-;;;;;;;;;163393:54;;163444:3;163393:54;;139901:48;;;;;185301:3058;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;207036:612::-;;;;;;:::i;:::-;;:::i;77742:1590::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;172451:482::-;;;;;;:::i;:::-;-1:-1:-1;;;;;172642:20:0;172527:7;172642:20;;;;;;;;;;172695:12;;-1:-1:-1;;;172695:12:0;;;;;-1:-1:-1;;;172722:13:0;;;;;-1:-1:-1;;;172750:11:0;;;;;-1:-1:-1;;;172776:11:0;;;;;-1:-1:-1;;;172802:17:0;;;;;-1:-1:-1;;;172834:18:0;;;;;-1:-1:-1;;;172867:16:0;;;;;-1:-1:-1;;;172898:16:0;;;;;172451:482;;;;;17599:25:1;;;17655:2;17640:18;;17633:34;;;;17683:18;;;17676:34;;;;17741:2;17726:18;;17719:34;;;;17784:3;17769:19;;17762:35;17828:3;17813:19;;17806:35;17872:3;17857:19;;17850:35;17916:3;17901:19;;17894:35;17586:3;17571:19;172451:482:0;17256:679:1;169314:127:0;;;;;;:::i;:::-;-1:-1:-1;;;;;169404:20:0;169371:11;169404:20;;;;;;;;;;:29;;;;169314:127;179842:285;;;;;;:::i;:::-;;:::i;166645:31::-;;;;;;;;;;;;213149:234;213242:11;-1:-1:-1;;;;;;213275:47:0;;-1:-1:-1;;;213275:47:0;;:100;;-1:-1:-1;;;;;;;;;;72453:40:0;;;213339:36;213266:109;213149:234;-1:-1:-1;;213149:234:0:o;175241:1760::-;175389:30;175403:15;175389:13;:30::i;:::-;175795:16;175785:194;;175845:25;175839:4;175832:39;175959:4;175953;175946:18;175785:194;-1:-1:-1;;;;;176006:29:0;;:12;:29;;;;;;;;;;:53;;;;;;;:58;176002:121;;176088:23;;-1:-1:-1;;;176088:23:0;;;;;;;;;;;176002:121;-1:-1:-1;;;;;176351:31:0;;;;;;:14;:31;;;;;;176332:50;;176328:117;;;176406:27;;-1:-1:-1;;;176406:27:0;;;;;;;;;;;176328:117;-1:-1:-1;;;;;176570:22:0;;;;;;;:13;:22;;;;;;;;176613:15;176570:58;;176737:33;;;;;:16;:33;;;;;:42;;;;;;;;;;;;:47;176733:261;;-1:-1:-1;;;;;176801:33:0;;;;;;;:16;:33;;;;;;;;:42;;;;;;;;;;;;176846:1;176801:46;;;;176862:22;;;;;:29;;:51;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;176862:51:0;;;;;176935:47;;18136:51:1;;;18203:18;;18196:60;;;;18272:18;;18265:50;;;;176935:47:0;;18124:2:1;18109:18;176935:47:0;;;;;;;;176733:261;175241:1760;;;:::o;195619:7649::-;195716:16;;195696:37;;:19;:37::i;:::-;195744:25;:23;:25::i;:::-;196158:14;196136:9;:19;;;:36;:103;;;;163239:5;196189:9;:21;;;:50;196136:103;:166;;;;196281:9;:21;;;196256:9;:21;;;:46;;196136:166;196118:259;;;196329:36;164857:10;196329:7;:36::i;:::-;197239:9;:20;;;197215:9;:20;;;:44;;:103;;;;197299:9;:19;;;197276:9;:20;;;:42;197215:103;:162;;;;197358:9;:19;;;197335:9;:20;;;:42;197215:162;:221;;;;197417:9;:19;;;197394:9;:19;;;:42;;197215:221;:285;;;;163711:4;197453:9;:19;;;:47;197215:285;:326;;;-1:-1:-1;197517:19:0;;;;:24;197215:326;:391;;;;163711:4;197558:9;:20;;;:48;197215:391;197197:484;;;197633:36;164857:10;197633:7;:36::i;:::-;198055:9;:21;;;163444:3;198005:9;:20;;;:47;;;;:::i;:::-;:71;:158;;;;198142:9;:21;;;163444:3;198093:9;:19;;;:46;;;;:::i;:::-;:70;198005:158;197987:251;;;198190:36;164857:10;198190:7;:36::i;:::-;163953:4;198340:9;:25;;;:44;:105;;;;164086:4;198401:9;:25;;;:44;198340:105;198322:198;;;198472:36;164857:10;198472:7;:36::i;:::-;198805:9;:24;;;198777:9;:25;;;:52;:121;;;;198874:9;:24;;;198846:9;:25;;;:52;198777:121;:190;;;;198943:9;:24;;;198915:9;:24;;;:52;;198777:190;:236;;;-1:-1:-1;198984:24:0;;;;:29;198777:236;:283;;;;745:3;199030:9;:24;;;:30;198777:283;198759:376;;;199087:36;164857:10;199087:7;:36::i;:::-;199409:21;;;;199403:27;;745:3;199403:27;:::i;:::-;199377:54;;:22;:54;:::i;:::-;199341:9;:19;;;:91;199323:184;;;199459:36;164857:10;199459:7;:36::i;:::-;199645:19;;;;:24;:55;;;;;199699:1;199673:9;:23;;;:27;199645:55;199641:124;;;199717:36;164857:10;199717:7;:36::i;:::-;199857:17;;;;:21;199853:257;;199917:17;;;;164699;-1:-1:-1;199917:33:0;:95;;;199980:9;:16;;;-1:-1:-1;;;;;199972:38:0;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;199971:41;199917:95;199895:204;;;200047:36;164857:10;200047:7;:36::i;:::-;200172:16;;-1:-1:-1;;;;;200159:30:0;200122:34;200159:30;;;;;;;;;;200394:22;;-1:-1:-1;;;200394:22:0;;;;:27;;;;:55;;-1:-1:-1;200425:19:0;;;;:24;200394:55;200390:124;;;200466:36;164857:10;200466:7;:36::i;:::-;200675:17;200696:41;200721:15;200696:24;:41::i;:::-;200761:16;;200696:94;;-1:-1:-1;;;200696:94:0;;-1:-1:-1;;;;;200696:64:0;;;;;;;:94;;200779:4;;;;200696:94;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;200672:118;;;843:1;200886:9;:23;200882:90;;200933:27;;-1:-1:-1;;;200933:27:0;;;;;;;;;;;200882:90;201000:41;201025:15;201000:24;:41::i;:::-;201065:16;;201000:95;;-1:-1:-1;;;201000:95:0;;-1:-1:-1;;;;;201000:64:0;;;;;;;:95;;201083:4;;201065:16;;201000:95;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;200984:111;-1:-1:-1;;;;201191:23:0;;201187:90;;201238:27;;-1:-1:-1;;;201238:27:0;;;;;;;;;;;201187:90;201480:19;;;;201448:52;;;;;;-1:-1:-1;;;201448:52:0;-1:-1:-1;;201448:52:0;;;;;;201727:21;;;;:27;;745:3;;201727:27;:::i;:::-;201693:62;;;;;;;-1:-1:-1;;;201693:62:0;-1:-1:-1;;201693:62:0;;;;;;201800:21;;;;:27;;745:3;;201800:27;:::i;:::-;201766:62;;;;;;;-1:-1:-1;;;201766:62:0;-1:-1:-1;;;;201766:62:0;;;;;;202010:20;;;;202004:26;;745:3;202004:26;:::i;:::-;201971:60;;;;;;;-1:-1:-1;;;201971:60:0;-1:-1:-1;;;;201971:60:0;;;;;;202080:19;;;;202074:25;;745:3;202074:25;:::i;:::-;202042:58;;;;;;;-1:-1:-1;;;202042:58:0;-1:-1:-1;;;;202042:58:0;;;;;;202149:19;;;;202143:25;;745:3;202143:25;:::i;:::-;202111:58;;;;;;;-1:-1:-1;;;202111:58:0;-1:-1:-1;;;;202111:58:0;;;;;;202382:20;;;;202359;;;;:43;;202382:20;202359:43;:::i;:::-;202325:78;;;202491:25;;;-1:-1:-1;;;;202453:64:0;;;-1:-1:-1;;;202325:78:0;;;;;-1:-1:-1;;;;202453:64:0;;-1:-1:-1;;;202453:64:0;;;;;;;;;;;;;202710:31;;745:3;202710:31;:::i;:::-;202671:71;;202850:24;;;;202923;;;;-1:-1:-1;;;;202813:62:0;;;-1:-1:-1;;;202671:71:0;;;;;-1:-1:-1;;;;202813:62:0;;-1:-1:-1;;;202813:62:0;;;;;;;;-1:-1:-1;;;;202886:62:0;-1:-1:-1;;;202886:62:0;;;;;;;;;;;203064:23;;;;203044:16;;-1:-1:-1;;;;;203029:32:0;;;-1:-1:-1;203029:32:0;;;:14;:32;;;;;;;;:58;;;;203196:17;;;;203176:16;;203167:26;;;;;:8;:26;;;;;:46;203231:29;;;;;202850:24;;20135:13:1;;-1:-1:-1;;;;;4990:31:1;4978:44;;20103:3;20088:19;;20216:4;20208:6;20204:17;20198:24;20191:4;20180:9;20176:20;20169:54;20279:4;20271:6;20267:17;20261:24;20254:4;20243:9;20239:20;20232:54;20342:4;20334:6;20330:17;20324:24;20317:4;20306:9;20302:20;20295:54;20405:4;20397:6;20393:17;20387:24;20380:4;20369:9;20365:20;20358:54;20468:4;20460:6;20456:17;20450:24;20443:4;20432:9;20428:20;20421:54;20531:4;20523:6;20519:17;20513:24;20506:4;20495:9;20491:20;20484:54;20594:4;20586:6;20582:17;20576:24;20569:4;20558:9;20554:20;20547:54;20659:6;20651;20647:19;20641:26;20632:6;20621:9;20617:22;20610:58;20726:6;20718;20714:19;20708:26;20699:6;20688:9;20684:22;20677:58;20793:6;20785;20781:19;20775:26;20766:6;20755:9;20751:22;20744:58;20860:6;20852;20848:19;20842:26;20833:6;20822:9;20818:22;20811:58;20927:6;20919;20915:19;20909:26;20900:6;20889:9;20885:22;20878:58;19911:1031;;;;;177858:628:0;178099:26;178138:21;178152:6;178138:13;:21::i;:::-;178174:12;;;;;;;178190:1;178174:17;178170:80;;178215:23;;-1:-1:-1;;;178215:23:0;;;;;;;;;;;178170:80;178283:195;178308:6;178329;178350:7;178372:9;178396:16;178427:4;178446:21;178283:10;:195::i;:::-;178262:216;177858:628;-1:-1:-1;;;;;;;177858:628:0:o;173580:156::-;-1:-1:-1;;;;;173699:22:0;;;;;;:13;:22;;;;;;;;;:29;;173690:38;;;;;;;;;;;;;;;;;173654:23;;173690:38;;;173699:29;173690:38;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;173690:38:0;;;;;;;;;;;;;;;;;;;;;;;173580:156;;;:::o;205098:265::-;205169:25;:23;:25::i;:::-;205205:27;205225:6;205205:19;:27::i;:::-;205279:5;:13;;205291:1;205279:13;;;205287:1;205279:13;-1:-1:-1;;;;;205245:20:0;;:12;:20;;;;;;;;;;;;:47;;;;;;;;;-1:-1:-1;;205245:47:0;;;;;;;;;;205308;;21181:51:1;;;21268:2;21248:18;;;21241:30;;;21307:2;21287:18;;;21280:30;;;;-1:-1:-1;;;21341:3:1;21326:19;;21319:42;21440:14;;21433:22;21413:18;;;21406:50;;;;205308:47:0;;21219:3:1;21378:19;205308:47:0;;;;;;;;205098:265;;:::o;181211:1469::-;181401:21;181415:6;181401:13;:21::i;:::-;181433:27;181453:6;181433:19;:27::i;:::-;181471:25;181488:7;181471:16;:25::i;:::-;-1:-1:-1;;;;;181586:24:0;;;;;;;:16;:24;;;;;;;;:33;;;;;;;;;;181623:1;181586:38;181582:107;;181641:36;164857:10;181641:7;:36::i;:::-;181797:54;;181833:7;181797:54;181976:13;181991:17;182025:41;182050:15;182025:24;:41::i;:::-;-1:-1:-1;;;;;182025:68:0;;182094:9;182105:4;182111;182025:91;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;181975:141;;;;1036:1;182252:9;:21;182248:88;;182297:27;;-1:-1:-1;;;182297:27:0;;;;;;;;;;;182248:88;182574:13;182506:52;182518:10;182530:5;182537:14;182543:8;182537:2;:14;:::i;:::-;182553:4;182506:11;:52::i;:::-;:81;182488:185;;;182621:40;;-1:-1:-1;;;182621:40:0;;;;;;;;;;;182488:185;181390:1290;;181211:1469;;;;;;:::o;179058:206::-;179209:47;179220:6;179228;179236:7;179245:10;179209;:47::i;:::-;179058:206;;;;:::o;208939:2121::-;209088:26;:24;:26::i;:::-;209125:27;209145:6;209125:19;:27::i;:::-;-1:-1:-1;;;;;209191:20:0;;209166:22;209191:20;;;;;;;;;;;209166:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;-1:-1:-1;;;209166:45:0;;;;;;;;;;;;209347:16;209343:96;;209387:40;;-1:-1:-1;;;209387:40:0;;;;;;;;;;;209343:96;209709:14;;;;;:83;;;209753:1;:11;;;209741:23;;:9;:23;:50;;;;209780:1;:11;;;209768:23;;:9;:23;209741:50;209691:176;;;209819:36;164857:10;209819:7;:36::i;:::-;210163:16;;;;;:99;;;210211:1;:16;;;210197:30;;:11;:30;:64;;;;210245:1;:16;;;210231:30;;:11;:30;210197:64;210145:192;;;210289:36;164857:10;210289:7;:36::i;:::-;210844:21;210840:37;;;210904:20;210900:38;;;210815:142;-1:-1:-1;;;;;210369:24:0;;210766:208;;-1:-1:-1;;;;;;;;;;;210990:52:0;210413:640;;208939:2121;;;:::o;211591:232::-;211654:26;:24;:26::i;:::-;211803:1;-1:-1:-1;;;;;;;;;;;211761:44:0;211591:232::o;166192:29::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;166192:29:0;;-1:-1:-1;166192:29:0;:::o;191203:1783::-;191275:25;:23;:25::i;:::-;191390:6;-1:-1:-1;;;;;191380:16:0;:6;-1:-1:-1;;;;;191380:16:0;;191376:85;;191413:36;164857:10;191413:7;:36::i;:::-;191586:6;-1:-1:-1;;;;;191578:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;191551:50:0;191559:6;-1:-1:-1;;;;;191551:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;191551:50:0;;191547:119;;191618:36;164857:10;191618:7;:36::i;:::-;191758:12;:19;:24;191754:93;;191799:36;164857:10;191799:7;:36::i;:::-;191997:6;-1:-1:-1;;;;;191989:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;191988:31;:66;;;;;192032:6;-1:-1:-1;;;;;192024:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;192023:31;191988:66;191984:135;;;192071:36;164857:10;192071:7;:36::i;:::-;-1:-1:-1;;;;;192243:20:0;;;:12;:20;;;;;;;;;;;:36;;192275:4;-1:-1:-1;;192243:36:0;;;;;;;;192290:20;;;;;;;;;:36;;;;;;;;;;;192469:46;;-1:-1:-1;;;192469:46:0;;192504:10;192469:46;;;9705:51:1;192469:34:0;;9678:18:1;;192469:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;192464:114;;192532:34;165146:10;192532:7;:34::i;:::-;192603:46;;-1:-1:-1;;;192603:46:0;;192638:10;192603:46;;;9705:51:1;-1:-1:-1;;;;;192603:34:0;;;;;9678:18:1;;192603:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;192598:114;;192666:34;165146:10;192666:7;:34::i;:::-;192837:12;:25;;;;;;;;-1:-1:-1;192837:25:0;;;;;;;;;-1:-1:-1;;;;;;192837:25:0;;;-1:-1:-1;;;;;192837:25:0;;;;;;;;;192873;;;;;;;;;;;;;;;;;;;;;;;;;;192924:19;;9705:51:1;;;192924:19:0;;9693:2:1;9678:18;192924:19:0;;;;;;;192959;;-1:-1:-1;;;;;9723:32:1;;9705:51;;192959:19:0;;9693:2:1;9678:18;192959:19:0;9559:203:1;188778:402:0;188890:36;188910:15;188890:19;:36::i;:::-;188937:30;188957:9;188937:19;:30::i;:::-;189063:9;-1:-1:-1;;;;;189055:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;188998:91:0;189006:15;-1:-1:-1;;;;;188998:38:0;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;188998:91:0;;188980:193;;189123:38;;-1:-1:-1;;;189123:38:0;;;;;;;;;;;188980:193;188778:402;;:::o;207939:409::-;208005:25;:23;:25::i;:::-;-1:-1:-1;;;;;208102:24:0;;;;;;:17;:24;;;;;;;;208097:94;;208143:36;164857:10;208143:7;:36::i;:::-;-1:-1:-1;;;;;208262:24:0;;;;;;:17;:24;;;;;;;;208255:31;;-1:-1:-1;;208255:31:0;;;208304:36;;23592:51:1;;;23659:18;;;23652:50;;;;208304:36:0;;23565:18:1;208304:36:0;;;;;;;;207939:409;:::o;180467:213::-;180542:21;180556:6;180542:13;:21::i;:::-;180574:27;180594:6;180574:19;:27::i;:::-;-1:-1:-1;;;;;180614:22:0;;;;;:13;:22;;;;;180657:15;180614:58;;-1:-1:-1;180467:213:0:o;174176:140::-;174245:7;174254;174263;174290:18;174300:7;174290:9;:18::i;:::-;174283:25;;;;;;174176:140;;;;;;:::o;204518:189::-;204577:25;:23;:25::i;:::-;204632:5;:13;;204644:1;204632:13;;;204640:1;204632:13;204615:14;;:30;;;;;;;;;;;;;;;;;;204661:38;204693:5;204661:38;;;;;23937:2:1;23919:21;;;23976:2;23956:18;;;23949:30;-1:-1:-1;;;24010:2:1;23995:18;;23988:45;24114:14;;24107:22;24100:4;24085:20;;24078:52;24065:3;24050:19;;23713:423;173174:107:0;173226:18;173261:12;173257:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;173257:16:0;;;;;;;;;;;;;;;;;;;;;;;173174:107;:::o;206485:271::-;206558:25;:23;:25::i;:::-;206594:27;206614:6;206594:19;:27::i;:::-;206670:5;:13;;206682:1;206670:13;;;206678:1;206670:13;-1:-1:-1;;;;;206634:20:0;;:12;:20;;;;;;;;;;;;:49;;;;;;;;;-1:-1:-1;;206634:49:0;;;;;;;;;;206699;;24375:51:1;;;24462:2;24442:18;;;24435:30;;;24501:2;24481:18;;;24474:30;;;;-1:-1:-1;;;24535:3:1;24520:19;;24513:44;24636:14;;24629:22;24609:18;;;24602:50;;;;206699:49:0;;24413:3:1;24574:19;206699:49:0;24141:517:1;190009:594:0;190222:26;190261:21;190275:6;190261:13;:21::i;:::-;190297:14;;;;;;;;:19;190293:82;;190340:23;;-1:-1:-1;;;190340:23:0;;;;;;;;;;;190293:82;190408:187;190433:6;190454;190475:7;190497:9;190521:16;190552:12;190579:5;190408:10;:187::i;174502:212::-;-1:-1:-1;;;;;174572:20:0;;:12;:20;;;;;;;;;;:31;;;;;;174607:1;174572:36;174568:99;;174632:23;;-1:-1:-1;;;174632:23:0;;;;;;;;;;;174568:99;174679:27;174699:6;174679:19;:27::i;:::-;174502:212;:::o;205784:304::-;205868:25;:23;:25::i;:::-;205904:27;205924:6;205904:19;:27::i;:::-;205991:5;:13;;206003:1;205991:13;;;205999:1;205991:13;-1:-1:-1;;;;;205944:20:0;;:12;:20;;;;;;;;;;;;:60;;;;;;;;;-1:-1:-1;;205944:60:0;;;;;;;;;;206020;;24897:51:1;;;24984:2;24964:18;;;24957:30;;;25023:2;25003:18;;;24996:30;;;;25063:26;25057:3;25042:19;;25035:55;25169:14;;25162:22;25142:18;;;25135:50;;;;206020:60:0;;24935:3:1;25107:19;206020:60:0;24663:528:1;203561:198:0;203623:25;:23;:25::i;:::-;203681:5;:13;;203693:1;203681:13;;;203689:1;203681:13;203661:17;:33;;-1:-1:-1;;203661:33:0;;;;;;;;;;;;203710:41;;;25402:21:1;;;25459:2;25439:18;;;25432:30;;;;-1:-1:-1;;;25493:2:1;25478:18;;25471:48;25600:14;;25593:22;25586:4;25571:20;;25564:52;203710:41:0;;25551:3:1;25536:19;203710:41:0;25196:426:1;204049:183:0;204106:25;:23;:25::i;:::-;204159:5;:13;;204171:1;204159:13;;;204167:1;204159:13;204144:12;;:28;;;;;;;;;;;;;;;;;;204188:36;204218:5;204188:36;;;;;25851:2:1;25833:21;;;25890:2;25870:18;;;25863:30;-1:-1:-1;;;25924:2:1;25909:18;;25902:43;26026:14;;26019:22;26012:4;25997:20;;25990:52;25977:3;25962:19;;25627:421;185301:3058:0;185513:38;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;185513:38:0;185601:17;;185562:16;;185601:17;;185622:1;185601:22;185597:85;;185647:23;;-1:-1:-1;;;185647:23:0;;;;;;;;;;;185597:85;185694:31;185708:6;:16;;;185694:13;:31::i;:::-;185756:22;;185736:43;;:19;:43::i;:::-;185790:37;185810:6;:16;;;185790:19;:37::i;:::-;185841:25;185868:27;185912:63;185934:6;:22;;;185958:6;:16;;;185912:21;:63::i;:::-;185840:135;;;;186125:6;:18;;;-1:-1:-1;;;;;186111:33:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;186111:33:0;-1:-1:-1;186085:59:0;;:23;;;186218:1908;186238:6;:18;;;186234:1;:22;186218:1908;;;186294:8;;186303:1;186294:11;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;186278:27;;186412:13;-1:-1:-1;;;;;186398:27:0;:10;-1:-1:-1;;;;;186398:27:0;;186394:99;;186446:31;164999:10;186446:7;:31::i;:::-;186702:13;-1:-1:-1;;;;;186686:29:0;:12;-1:-1:-1;;;;;186686:29:0;;186682:101;;186736:31;164999:10;186736:7;:31::i;:::-;186928:181;186960:11;186972:1;186960:14;;;;;;;;:::i;:::-;;;;;;;186993:13;187025:5;187049;187073:6;:21;;;186928:13;:181::i;:::-;186896:14;;;186799:310;186860:17;;;186799:310;;;186818:23;;;186799:310;;;;-1:-1:-1;187343:17:0;;:38;;;;186799:310;;187343:38;:::i;:::-;;;-1:-1:-1;187425:23:0;;;;187396;;:26;;187420:1;;187396:26;;;;;;:::i;:::-;;;;;;;;;;:52;187469:14;;;;:18;187465:257;;187534:6;:14;;;187508:6;:22;;:40;;;;;;;:::i;:::-;;;-1:-1:-1;187692:14:0;;;;187671:17;;;:35;;;;187692:14;;187671:35;:::i;:::-;;;-1:-1:-1;187465:257:0;187995:6;:17;;;187978:11;187990:1;187978:14;;;;;;;;:::i;:::-;;;;;;;;;;:34;188101:13;;-1:-1:-1;186258:3:0;;186218:1908;;;;188214:6;:17;;;188235:1;188214:22;188210:101;;188260:39;;-1:-1:-1;;;188260:39:0;;;;;;;;;;;188210:101;-1:-1:-1;185301:3058:0;;;-1:-1:-1;;;;;;;;185301:3058:0:o;207036:612::-;207099:25;:23;:25::i;:::-;207156:92;207206:5;-1:-1:-1;;;207156:49:0;:92::i;:::-;207137:186;;207275:36;164857:10;207275:7;:36::i;:::-;-1:-1:-1;;;;;207395:24:0;;;;;;:17;:24;;;;;;;;207391:93;;;207436:36;164857:10;207436:7;:36::i;:::-;-1:-1:-1;;;;;207556:24:0;;;;;;:17;:24;;;;;;;;;:31;;-1:-1:-1;;207556:31:0;207583:4;207556:31;;;;;;207605:35;;23592:51:1;;;23659:18;;;23652:50;207605:35:0;;23565:18:1;207605:35:0;23424:284:1;77742:1590:0;77829:22;239407:15;77937:5;;-1:-1:-1;;;;;77970:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;77960:31:0;;-1:-1:-1;78048:1277:0;78068:8;78064:1;:12;78048:1277;;;78111:5;;78117:1;78111:8;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;78098:21;;;:::i;:::-;;;78152:10;:24;;;78148:810;;;78380:17;;78360:38;;-1:-1:-1;;;78360:38:0;;-1:-1:-1;;;;;9723:32:1;;;78360:38:0;;;9705:51:1;78342:15:0;;78360:19;;;;;9678:18:1;;78360:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78342:56;-1:-1:-1;;;;;;78489:21:0;;78485:105;;78542:28;;-1:-1:-1;;;78542:28:0;;;;;;;;;;;78485:105;78706:17;;78746:15;;;;;78610:170;;-1:-1:-1;;;78610:170:0;;-1:-1:-1;;;;;78610:40:0;;;;;:170;;78673:10;;78706:17;78746:15;78610:170;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;78814:83;78862:10;:17;;;78881:10;:15;;;78814:47;:83::i;:::-;78801:7;78809:1;78801:10;;;;;;;;:::i;:::-;;;;;;:96;;;;78934:8;;;78148:810;79114:17;;-1:-1:-1;;;;;79097:34:0;79105:4;79097:34;79093:108;;79159:26;;-1:-1:-1;;;79159:26:0;;;;;;;;;;;79093:108;79230:83;79290:4;79297:10;:15;;;79230:51;:83::i;:::-;79217:7;79225:1;79217:10;;;;;;;;:::i;:::-;;;;;;:96;;;;78048:1277;78078:3;;78048:1277;;;;77853:1479;;;77742:1590;;;;:::o;179842:285::-;-1:-1:-1;;;;;180003:22:0;;;;;;:13;:22;;;;;180046:15;180003:58;;180072:47;180083:6;180091;180017:7;180108:10;180072;:47::i;236219:393::-;236423:5;236413:8;236410:19;236400:194;;236463:22;236457:4;236450:36;236574:4;236568;236561:18;235983:176;-1:-1:-1;;;;;236057:19:0;;:12;:19;;;;;;;;;;:28;;;236052:100;;236109:31;;-1:-1:-1;;;236109:31:0;;;;;;;;;;;238717:188;238790:48;;-1:-1:-1;;;238790:48:0;;238827:10;238790:48;;;9705:51:1;238790:15:0;-1:-1:-1;;;;;238790:36:0;;;;9678:18:1;;238790:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;238785:113;;238855:31;164999:10;238855:7;:31::i;:::-;238717:188::o;159439:186::-;159573:1;159567:4;159560:15;159602:4;159596;159589:18;81461:183;81545:28;81617:2;-1:-1:-1;;;;;81617:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;217629:2478::-;217876:26;217915:27;217935:6;217915:19;:27::i;:::-;217953:31;217976:7;217953:22;:31::i;:::-;218001:12;217997:1153;;;218168:21;218164:975;;;218352:16;218343:6;:25;218339:120;;;218400:39;;-1:-1:-1;;;218400:39:0;;;;;;;;;;;218339:120;-1:-1:-1;218500:6:0;218164:975;;;219016:7;218987:25;219006:6;218987:16;:25;:::i;:::-;:36;218983:141;;219097:7;219069:25;219088:6;219069:16;:25;:::i;:::-;:35;;;;:::i;:::-;219048:56;;218983:141;219315:23;;;:65;;-1:-1:-1;;;;;;219342:24:0;;;;;;;:16;:24;;;;;;;;:33;;;;;;;;;;219379:1;219342:38;;219315:65;219397:25;219311:123;219522:24;219550:316;219593:7;219619:232;;;;;;;;219677:6;-1:-1:-1;;;;;219619:232:0;;;;;219724:18;219619:232;;;;219779:1;219619:232;;;;952:1;219619:232;;;219550:24;:316::i;:::-;219519:347;-1:-1:-1;;220005:20:0;;220001:99;;220049:39;;-1:-1:-1;;;220049:39:0;;;;;;;;;;;220001:99;217904:2203;217629:2478;;;;;;;;;:::o;235382:450::-;-1:-1:-1;;;;;235656:22:0;;;;;;:13;:22;;;;;:40;235730:15;;235656:58;;164494:10;;235656:58;:::i;:::-;:89;235638:187;;;235779:34;;-1:-1:-1;;;235779:34:0;;;;;;;;;;;157308:351;157470:7;157494:19;157490:91;;;157537:32;157545:6;157553:5;157560:8;157537:7;:32::i;:::-;157530:39;;;;157490:91;157600:51;157627:6;157635:5;157642:8;157600:26;:51::i;:::-;157593:58;;157308:351;;;;;;;:::o;214075:2536::-;214230:24;214244:9;214230:13;:24::i;:::-;214612:10;214602:188;;214656:25;214650:4;214643:39;214770:4;214764;214757:18;214602:188;-1:-1:-1;;;;;214817:23:0;;:12;:23;;;;;;;;;;:36;;;;;;214857:1;214817:41;214813:104;;214882:23;;-1:-1:-1;;;214882:23:0;;;;;;;;;;;214813:104;-1:-1:-1;;;;;215306:19:0;;;;;;:8;:19;;;;;;215293:32;;215289:99;;;215349:27;;-1:-1:-1;;;215349:27:0;;;;;;;;;;;215289:99;-1:-1:-1;;;;;215503:27:0;;;;;;;:16;:27;;;;;;;;:36;;;;;;;;;;215543:1;215503:41;215499:409;;-1:-1:-1;;;;;215733:27:0;;;;;;;:16;:27;;;;;;;;:36;;;;;;;;;;;;215772:1;215733:40;;;;215788:22;;;;;:29;;:45;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;215788:45:0;;;;;215855:41;;18136:51:1;;;18203:18;;18196:60;;;;18272:18;;18265:50;;;;215855:41:0;;18124:2:1;18109:18;215855:41:0;;;;;;;215499:409;216035:24;216063:307;216106:7;216132:223;;;;;;;;216190:9;-1:-1:-1;;;;;216132:223:0;;;;;216240:1;216132:223;;;;216278:6;216132:223;;;;952:1;216132:223;;;216063:24;:307::i;:::-;216032:338;-1:-1:-1;;216509:20:0;;216505:99;;216553:39;;-1:-1:-1;;;216553:39:0;;;;;;;;;;;238983:182;239049:49;;-1:-1:-1;;;239049:49:0;;239087:10;239049:49;;;9705:51:1;239049:15:0;-1:-1:-1;;;;;239049:37:0;;;;9678:18:1;;239049:49:0;9559:203:1;144374:1335:0;144438:18;144467:15;144493:12;144539:34;144588:23;144626:17;144657:33;144670:7;843:1;144657:12;:33::i;:::-;144524:166;;;;;;144701:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;144701:27:0;144746:9;144741:961;144761:9;144757:1;:13;144741:961;;;144799:9;144809:1;144799:12;;;;;;;;:::i;:::-;;;;;;;144792:19;;144832:4;:17;;;144828:863;;;144870:23;144896:175;144930:4;:21;;;144974:6;144981:1;144974:9;;;;;;;;:::i;:::-;;;;;;;145012:4;:13;;;145006:2;:19;;;;:::i;144896:175::-;144870:201;-1:-1:-1;145090:29:0;144870:201;145090:29;;:::i;:::-;145230:10;;-1:-1:-1;;;;;145217:24:0;:12;:24;;;;;;;;;;:34;145090:29;;-1:-1:-1;145149:147:0;;145179:15;;-1:-1:-1;;;145217:34:0;;;;745:3;145149:7;:147::i;:::-;145138:158;;;;:::i;:::-;;;144851:461;144828:863;;;145412:16;;;;:20;145408:268;;145465:191;145503:4;:16;;;145546:6;145553:1;145546:9;;;;;;;;:::i;:::-;;;;;;;145588:4;:13;;;145582:2;:19;;;;:::i;:::-;145628:5;145465:11;:191::i;:::-;145457:199;;;;:::i;:::-;;;145408:268;144772:3;;144741:961;;;;144513:1196;;;;144374:1335;;;;;:::o;233302:1951::-;233430:25;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;233430:25:0;233466:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;233466:27:0;-1:-1:-1;;;;;233537:29:0;;233512:22;233537:29;;;;;;;;;;;233512:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;-1:-1:-1;;;233512:54:0;;;;;;;;;;;;233656:16;233652:85;;233689:36;164857:10;233689:7;:36::i;:::-;234035:40;234059:15;234035:23;:40::i;:::-;234001:17;;;233965:110;233987:12;;;233965:110;233966:19;;;233965:110;234263:41;234288:15;234263:24;:41::i;:::-;:120;;-1:-1:-1;;;234263:120:0;;-1:-1:-1;;;;;28488:32:1;;;234263:120:0;;;28470:51:1;28557:32;;;28537:18;;;28530:60;843:1:0;28606:18:1;;;28599:34;234263:80:0;;;;;;;28443:18:1;;234263:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;234221:25;;;234191:192;234192:27;;;234191:192;-1:-1:-1;;;;;234469:39:0;;;;;234545:13;;;;234519:39;;;;:23;;;;:39;;;;-1:-1:-1;234595:13:0;;;234569:39;;;-1:-1:-1;234569:23:0;;;:39;;;;234652:34;;-1:-1:-1;;;234652:34:0;;;;:32;;:34;;;;;234519:23;;234652:34;;;;;;234469:39;234652:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;234646:40;;:2;:40;:::i;:::-;234619:24;;;:67;-1:-1:-1;;;;;234697:27:0;;:15;;;:27;;;234762:28;;;-1:-1:-1;;;234762:28:0;;;;:26;;:28;;;;;;;;;;;;;;;234697:27;234762:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;234756:34;;:2;:34;:::i;:::-;234735:18;;;:55;234955:17;;;;234976:1;234955:22;234951:154;;235018:17;;;;234994:41;;;;:21;;;:41;235075:18;;;;235050:43;:22;;;:43;234951:154;235121:5;:12;;;235137:1;235121:17;235117:129;;235174:12;;;;235155:31;;;;:16;;;:31;235221:13;;;;235201:33;-1:-1:-1;235201:17:0;;:33;235117:129;233501:1752;233302:1951;;;;;:::o;224191:5585::-;224413:24;224448:7;224466:15;224623:36;224644:7;224653:5;224623:20;:36::i;:::-;224589:17;;;224573:86;;;;224574:13;224676:18;224672:67;;-1:-1:-1;224719:1:0;;-1:-1:-1;224719:1:0;;-1:-1:-1;224719:1:0;224711:16;;224672:67;225189:22;;;;:27;225185:172;;225294:51;225302:5;:22;;;225326:5;:13;;;636:4;225294:7;:51::i;:::-;225253:5;:21;;;:92;;;;:::i;:::-;225233:17;;;:112;225185:172;225373:17;;;;:22;225369:152;;225463:46;225471:5;:17;;;225490:5;:13;;;636:4;225463:7;:46::i;:::-;225427:5;:16;;;:82;;;;:::i;:::-;225412:12;;;:97;225369:152;225803:24;225830:315;225873:189;225935:5;:25;;;225920:5;:12;;;:40;;;;:::i;:::-;311:4;226020:5;:27;;;225873:28;:189::i;:::-;226077:5;:24;;;226116:5;:18;;;225830:28;:315::i;:::-;225803:342;;226156:15;745:3;226195:5;:17;;;226175:5;:17;;;:37;;;;:::i;:::-;226174:45;;;;:::i;:::-;226156:63;;226375:14;226370:68;;226419:7;226406:20;;226370:68;226537:121;226580:10;226605:16;182:4;226537:28;:121::i;:::-;226803:21;;226795:56;;-1:-1:-1;;;226795:56:0;;-1:-1:-1;;;;;9723:32:1;;;226795:56:0;;;9705:51:1;226518:140:0;;-1:-1:-1;226759:20:0;;226795:47;;;;;;9678:18:1;;226795:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;226759:92;;227052:14;227048:730;;;227100:7;227087:10;:20;:55;;;;227130:12;227111:16;:31;227087:55;227083:243;;;227274:36;164857:10;227274:7;:36::i;:::-;227048:730;;;227499:12;227480:16;:31;227476:291;;;227545:156;227598:10;227631:12;227666:16;227545:30;:156::i;:::-;227532:169;;227739:12;227720:31;;227476:291;228061:20;228084:130;228129:5;:17;;;228161:16;182:4;228084:30;:130::i;:::-;228061:153;;228244:12;228229;:27;228225:1313;;;228626:88;228675:10;228687:12;228701;228626:48;:88::i;:::-;228616:98;;229021:5;:17;;;229011:7;:27;229007:520;;;229242:10;229222:5;:17;;;:30;;;;:::i;:::-;229212:40;;229007:520;;;229491:20;229501:10;229491:7;:20;:::i;:::-;229481:30;;229007:520;-1:-1:-1;229748:10:0;;-1:-1:-1;;;;224191:5585:0;;;;;;;;;;:::o;73907:336::-;74019:4;74141:23;74156:7;74141:14;:23::i;:::-;:94;;;;;74181:54;74214:7;74223:11;74181:32;:54::i;:::-;74121:114;73907:336;-1:-1:-1;;;73907:336:0:o;49056:265::-;49149:12;49175;49189:23;49216:6;-1:-1:-1;;;;;49216:11:0;49235:1;49238:4;49216:27;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49174:69;;;;49271:42;49285:6;49293:7;49302:10;49271:13;:42::i;:::-;49264:49;49056:265;-1:-1:-1;;;;;49056:265:0:o;50936:263::-;51037:12;51063;51077:23;51104:6;-1:-1:-1;;;;;51104:19:0;51124:4;51104:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;236688:230;236766:47;;-1:-1:-1;;;236766:47:0;;-1:-1:-1;;;;;9723:32:1;;;236766:47:0;;;9705:51:1;236766:15:0;:38;;;;9678:18:1;;236766:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;236762:111;;;236830:31;164999:10;236830:7;:31::i;:::-;236885:25;236902:7;236885:16;:25::i;146751:4029::-;146879:7;146888;146923:34;146972:23;147010:17;147041:49;147054:7;147063:6;:26;;;147041:12;:49::i;:::-;146908:182;;;;;;147101:27;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;147101:27:0;147139:15;147165;147206:9;147201:3318;147221:9;147217:1;:13;147201:3318;;;147259:9;147269:1;147259:12;;;;;;;;:::i;:::-;;;;;;;147252:19;;147643:4;:10;;;-1:-1:-1;;;;;147618:35:0;:6;:21;;;-1:-1:-1;;;;;147618:35:0;;:56;;;;;147657:4;:17;;;147618:56;:100;;;;;147717:1;147695:6;:19;;;:23;147618:100;147596:676;;;147753:17;147835:41;147860:15;147835:24;:41::i;:::-;-1:-1:-1;;;;;147835:76:0;;147912:4;:15;;;147929:4;147935:5;147835:106;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;147790:6;147797:1;147790:9;;;;;;;;:::i;:::-;;;;;;147789:152;;;;;;;;;147979:6;:26;;;147966:9;:39;147962:125;;148037:30;;-1:-1:-1;;;148037:30:0;;;;;;;;;;;147962:125;-1:-1:-1;148232:24:0;148239:17;;;148232:24;147596:676;148292:4;:17;;;148288:2220;;;148468:10;;148443:21;;-1:-1:-1;;;;;148443:35:0;;;;;;148439:132;;148528:6;:23;;;148503:4;:21;;:48;;;;;;;:::i;:::-;;;-1:-1:-1;148439:132:0;148817:21;;;;:25;148813:590;;149020:363;149054:215;149096:4;:21;;;149148:6;149155:1;149148:9;;;;;;;;:::i;:::-;;;;;;;149194:4;:13;;;149188:2;:19;;;;:::i;149054:215::-;149309:10;;-1:-1:-1;;;;;149296:24:0;:12;:24;;;;;;;;;;:34;-1:-1:-1;;;149296:34:0;;;;745:3;149020:7;:363::i;:::-;149009:374;;;;:::i;:::-;;;148813:590;148288:2220;;;149472:10;;149447:21;;-1:-1:-1;;;;;149447:35:0;;;;;;149443:123;;149527:6;:19;;;149507:4;:16;;:39;;;;;;;:::i;:::-;;;-1:-1:-1;149443:123:0;149788:16;;;;:20;149784:709;;149984:191;150022:4;:16;;;150065:6;150072:1;150065:9;;;;;;;;:::i;:::-;;;;;;;150107:4;:13;;;150101:2;:19;;;;:::i;149984:191::-;149973:202;;;;:::i;:::-;;;150361:13;150351:7;:23;150347:127;;;150410:40;;-1:-1:-1;;;150410:40:0;;;;;;;;;;;150347:127;147232:3;;147201:3318;;;;150609:7;150599;:17;150595:79;;;150641:17;150651:7;150641;:17;:::i;:::-;150660:1;150633:29;;;;;;;;;;;;150595:79;150751:1;150754:17;150764:7;150754;:17;:::i;:::-;150743:29;;;;;;;;;;146751:4029;;;;;;:::o;159200:174::-;159307:9;159333:33;159358:1;159361;159364;159333:24;:33::i;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;156260:354::-;156364:24;156390:16;156408:7;156435:41;156460:15;156435:24;:41::i;:::-;-1:-1:-1;;;;;156532:22:0;;;;;;;:13;:22;;;;;;;156435:171;;-1:-1:-1;;;156435:171:0;;:60;;;;;;;:171;;156510:7;;156532:29;;;156576:19;;156435:171;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;156435:171:0;;;;;;;;;;;;:::i;:::-;156428:178;;;;;;156260:354;;;;;:::o;237284:1102::-;237372:7;;;;;;-1:-1:-1;;;;;;;;;;;212655:40:0;212773:54;165894:3;212792:34;;;212773:54;;;166056:3;212859:33;;;212838:55;237410:114;;;;;;237537:19;237559:15;-1:-1:-1;;;;;237559:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;237537:56;-1:-1:-1;;;;;;237630:24:0;;;;;;;237537:56;;237671:36;;;237689:18;237671:36;237667:533;;;237872:14;:36;;;;;237890:18;237872:36;237868:127;;;-1:-1:-1;237937:14:0;;-1:-1:-1;237953:12:0;;-1:-1:-1;237967:11:0;-1:-1:-1;237929:50:0;;-1:-1:-1;;237929:50:0;237868:127;238148:40;;-1:-1:-1;;;238148:40:0;;;;;;;;;;;237667:533;-1:-1:-1;238370:1:0;;;;-1:-1:-1;238370:1:0;;-1:-1:-1;237284:1102:0;-1:-1:-1;;;;;;237284:1102:0:o;153308:2495::-;153430:15;153447:12;153472:25;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;153472:25:0;-1:-1:-1;;;;;153534:22:0;;153508:23;153534:22;;;:13;:22;;;;;;;;:29;;153508:55;;;;;;;;;;;;;;;;;;;153534:29;;153508:55;;;153534:29;153508:55;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;153508:55:0;;;;;;;;;;;;;;;;;;;;;;;153576:13;153600:17;153620:6;:13;153600:33;;153649:9;153644:1260;153664:9;153660:1;:13;153644:1260;;;153700:6;153707:3;;;;:::i;:::-;;;153700:11;;;;;;;;:::i;:::-;;;;;;;153692:19;;153739:5;:21;;;-1:-1:-1;;;;;153730:30:0;:5;-1:-1:-1;;;;;153730:30:0;;153726:1167;;153846:24;;;;153893:23;;;;153939;;;;;153985:27;;;;154043:21;;154035:56;;-1:-1:-1;;;154035:56:0;;-1:-1:-1;;;;;9723:32:1;;;154035:56:0;;;9705:51:1;153802:368:0;;153846:24;153893:23;154035:47;;;;9678:18:1;;154035:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;154114:7;;154144;;;;153802:21;:368::i;:::-;153791:7;;;153781:389;;;153644:1260;;153726:1167;154445:15;;;;154427:55;;-1:-1:-1;;;154427:55:0;;-1:-1:-1;;;;;9723:32:1;;;154427:55:0;;;9705:51:1;154427:46:0;;;;;;9678:18:1;;154427:55:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;154399:83;-1:-1:-1;154621:8:0;;154617:261;;154664:194;154702:4;154733:5;:25;;;154785:5;:18;;;154830:5;154664:11;:194::i;:::-;154654:1;:6;;:204;;;;;;;:::i;:::-;;;-1:-1:-1;154617:261:0;153644:1260;;;-1:-1:-1;155082:19:0;;;;:24;155078:176;;155133:42;155141:1;:7;;;155150:5;:19;;;745:3;155133:7;:42::i;:::-;155123:52;;155208:7;;;;155217:19;;;;155200:42;;155208:7;745:3;155200:7;:42::i;:::-;155190:7;;;:52;155078:176;155316:6;;;;155305:7;;:17;155301:495;;155391:1;155381:11;;155301:495;;;155445:1;:7;;;155435:1;:6;;;:17;;:349;;155752:7;;155743:6;;;;155716:68;;155743:16;;;:::i;:::-;155776:7;;155766;;;;636:4;;155766:17;;;:::i;:::-;155716:26;:68::i;:::-;155435:349;;;636:4;155435:349;155425:359;;155301:495;153461:2342;;;;153308:2495;;;;;:::o;3388:3640::-;4011:9;;;-1:-1:-1;;4018:1:0;4015;4097:20;4227:14;;;4215:27;;4207:36;;;4331:285;;4378:1;4368:156;;4421:10;4415:4;4408:24;4496:4;4490;4483:18;4368:156;-1:-1:-1;4556:14:0;;;4592:5;;4331:285;4740:2;4737:1;4734:9;4724:152;;4781:10;4775:4;4768:24;4852:4;4846;4839:18;4724:152;5139:1;5136;5133;5126:15;5290:1;5286:9;;;5279:17;;5383:9;;;;;6724:13;;;6716:22;;;6748:9;;;;6744:17;;;6763:1;6740:25;6712:54;6801:14;;6797:22;6679:167;5764:1;5771;5767:9;;5760:17;;6050:11;;;6043:19;;6034:29;6124:11;;;6117:19;;6108:29;6199:11;;;6192:19;;6183:29;6274:11;;;6267:19;;6258:29;6349:11;;;6342:19;;6333:29;6936:11;;;6929:19;;;6920:29;6433:539;3388:3640;;;;;:::o;7316:474::-;7394:14;7430:19;7441:1;7444;7447;7430:10;:19::i;:::-;7421:28;;7544:1;7541;7538;7531:15;7528:244;;;7588:1;7576:14;;7608:149;;7662:10;7656:4;7649:24;7733:4;7727;7720:18;73199:482;73263:4;73474:117;73525:7;-1:-1:-1;;;73474:32:0;:117::i;:::-;:199;;;;-1:-1:-1;73609:64:0;73642:7;-1:-1:-1;;;;;;73609:32:0;:64::i;:::-;73608:65;73454:219;73199:482;-1:-1:-1;;73199:482:0:o;75088:826::-;75286:93;;-1:-1:-1;;;;;;33693:33:1;;75286:93:0;;;33675:52:1;75215:4:0;;;;33648:18:1;;75286:93:0;;;-1:-1:-1;;75286:93:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;75286:93:0;-1:-1:-1;;;75286:93:0;;;75663:20;;75286:93;;-1:-1:-1;;;;;;;75286:93:0;;-1:-1:-1;;75594:7:0;75570:5;75541:203;75530:214;;75772:16;75758:30;;75823:4;75817:11;75802:26;;75858:7;:29;;;;;75883:4;75869:10;:18;;75858:29;:48;;;;-1:-1:-1;75891:15:0;;;75851:55;-1:-1:-1;;;;;;75088:826:0:o;51413:513::-;51548:12;51573:36;51589:7;51598:10;51573:15;:36::i;:::-;51771:17;;:22;:49;;;;-1:-1:-1;;;;;;51797:18:0;;;:23;51771:49;51767:122;;;51844:33;;-1:-1:-1;;;51844:33:0;;;;;;;;;;;51767:122;-1:-1:-1;51908:10:0;51413:513;-1:-1:-1;;51413:513:0: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;158505:590::-;158774:15;158791;158819:18;745:3;158840:115;158866:16;158897:5;158917:8;158940:4;158840:11;:115::i;:::-;:121;;;;:::i;:::-;158819:142;-1:-1:-1;159000:24:0;159013:11;158819:142;159000:24;:::i;:::-;158984:41;;:12;:41;:::i;:::-;158974:51;-1:-1:-1;159062:24:0;159075:11;159062:10;:24;:::i;:::-;159046:41;;:12;:41;:::i;:::-;159036:51;;158808:287;158505:590;;;;;;;;;;:::o;52102:425::-;52221:7;52216:304;;52249:10;:17;52270:1;52249:22;52245:103;;52299:33;;-1:-1:-1;;;52299:33:0;;;;;;;;;;;52245:103;52482:10;52476:17;52463:10;52459:2;52455:19;52448:46;196:286:1;254:6;307:2;295:9;286:7;282:23;278:32;275:52;;;323:1;320;313:12;275:52;349:23;;-1:-1:-1;;;;;;401:32:1;;391:43;;381:71;;448:1;445;438:12;679:131;-1:-1:-1;;;;;754:31:1;;744:42;;734:70;;800:1;797;790:12;815:134;883:20;;912:31;883:20;912:31;:::i;:::-;815:134;;;:::o;954:247::-;1013:6;1066:2;1054:9;1045:7;1041:23;1037:32;1034:52;;;1082:1;1079;1072:12;1034:52;1121:9;1108:23;1140:31;1165:5;1140:31;:::i;1206:508::-;1283:6;1291;1299;1352:2;1340:9;1331:7;1327:23;1323:32;1320:52;;;1368:1;1365;1358:12;1320:52;1407:9;1394:23;1426:31;1451:5;1426:31;:::i;:::-;1476:5;-1:-1:-1;1533:2:1;1518:18;;1505:32;1546:33;1505:32;1546:33;:::i;:::-;1206:508;;1598:7;;-1:-1:-1;;;1678:2:1;1663:18;;;;1650:32;;1206:508::o;1719:127::-;1780:10;1775:3;1771:20;1768:1;1761:31;1811:4;1808:1;1801:15;1835:4;1832:1;1825:15;1851:252;1923:2;1917:9;1965:3;1953:16;;-1:-1:-1;;;;;1984:34:1;;2020:22;;;1981:62;1978:88;;;2046:18;;:::i;:::-;2082:2;2075:22;1851:252;:::o;2108:253::-;2180:2;2174:9;2222:4;2210:17;;-1:-1:-1;;;;;2242:34:1;;2278:22;;;2239:62;2236:88;;;2304:18;;:::i;2366:253::-;2438:2;2432:9;2480:4;2468:17;;-1:-1:-1;;;;;2500:34:1;;2536:22;;;2497:62;2494:88;;;2562:18;;:::i;2624:253::-;2696:2;2690:9;2738:4;2726:17;;-1:-1:-1;;;;;2758:34:1;;2794:22;;;2755:62;2752:88;;;2820:18;;:::i;2882:275::-;2953:2;2947:9;3018:2;2999:13;;-1:-1:-1;;2995:27:1;2983:40;;-1:-1:-1;;;;;3038:34:1;;3074:22;;;3035:62;3032:88;;;3100:18;;:::i;:::-;3136:2;3129:22;2882:275;;-1:-1:-1;2882:275:1:o;3162:1757::-;3250:6;3310:3;3298:9;3289:7;3285:23;3281:33;3326:2;3323:22;;;3341:1;3338;3331:12;3323:22;-1:-1:-1;3383:22:1;;:::i;:::-;3428:29;3447:9;3428:29;:::i;:::-;3414:44;;3531:2;3516:18;;;3503:32;3551:14;;;3544:31;3648:2;3633:18;;;3620:32;3668:14;;;3661:31;3765:2;3750:18;;;3737:32;3785:14;;;3778:31;3882:3;3867:19;;;3854:33;3903:15;;;3896:32;4001:3;3986:19;;;3973:33;4022:15;;;4015:32;4120:3;4105:19;;;4092:33;4141:15;;;4134:32;4239:3;4224:19;;;4211:33;4260:15;;;4253:32;4358:3;4343:19;;;4330:33;4379:15;;;4372:32;4477:3;4462:19;;;4449:33;4498:15;;;4491:32;4598:3;4583:19;;;4570:33;4619:15;;;4612:33;4720:3;4705:19;;;4692:33;4741:15;;;4734:33;4842:3;4827:19;;;4814:33;4863:15;;;4856:33;;;;-1:-1:-1;3421:5:1;3162:1757;-1:-1:-1;3162:1757:1:o;5383:118::-;5469:5;5462:13;5455:21;5448:5;5445:32;5435:60;;5491:1;5488;5481:12;5506:886;5607:6;5615;5623;5631;5639;5647;5700:3;5688:9;5679:7;5675:23;5671:33;5668:53;;;5717:1;5714;5707:12;5668:53;5756:9;5743:23;5775:31;5800:5;5775:31;:::i;:::-;5825:5;-1:-1:-1;5903:2:1;5888:18;;5875:32;;-1:-1:-1;5985:2:1;5970:18;;5957:32;5998:33;5957:32;5998:33;:::i;:::-;6050:7;-1:-1:-1;6130:2:1;6115:18;;6102:32;;-1:-1:-1;6233:3:1;6218:19;;6205:33;;-1:-1:-1;6316:3:1;6301:19;;6288:33;6330:30;6288:33;6330:30;:::i;:::-;6379:7;6369:17;;;5506:886;;;;;;;;:::o;6397:637::-;6587:2;6599:21;;;6669:13;;6572:18;;;6691:22;;;6539:4;;6770:15;;;6744:2;6729:18;;;6539:4;6813:195;6827:6;6824:1;6821:13;6813:195;;;6892:13;;-1:-1:-1;;;;;6888:39:1;6876:52;;6957:2;6983:15;;;;6948:12;;;;6924:1;6842:9;6813:195;;;-1:-1:-1;7025:3:1;;6397:637;-1:-1:-1;;;;;6397:637:1:o;7039:382::-;7104:6;7112;7165:2;7153:9;7144:7;7140:23;7136:32;7133:52;;;7181:1;7178;7171:12;7133:52;7220:9;7207:23;7239:31;7264:5;7239:31;:::i;:::-;7289:5;-1:-1:-1;7346:2:1;7331:18;;7318:32;7359:30;7318:32;7359:30;:::i;:::-;7408:7;7398:17;;;7039:382;;;;;:::o;7426:771::-;7521:6;7529;7537;7545;7553;7606:3;7594:9;7585:7;7581:23;7577:33;7574:53;;;7623:1;7620;7613:12;7574:53;7662:9;7649:23;7681:31;7706:5;7681:31;:::i;:::-;7731:5;-1:-1:-1;7809:2:1;7794:18;;7781:32;;-1:-1:-1;7891:2:1;7876:18;;7863:32;7904:33;7863:32;7904:33;:::i;:::-;7956:7;-1:-1:-1;8036:2:1;8021:18;;8008:32;;-1:-1:-1;8118:3:1;8103:19;;8090:33;8132;8090;8132;:::i;:::-;8184:7;8174:17;;;7426:771;;;;;;;;:::o;8202:629::-;8288:6;8296;8304;8312;8365:3;8353:9;8344:7;8340:23;8336:33;8333:53;;;8382:1;8379;8372:12;8333:53;8421:9;8408:23;8440:31;8465:5;8440:31;:::i;:::-;8490:5;-1:-1:-1;8568:2:1;8553:18;;8540:32;;-1:-1:-1;8650:2:1;8635:18;;8622:32;8663:33;8622:32;8663:33;:::i;:::-;8202:629;;;;-1:-1:-1;8715:7:1;;8795:2;8780:18;8767:32;;-1:-1:-1;;8202:629:1:o;8836:487::-;8913:6;8921;8929;8982:2;8970:9;8961:7;8957:23;8953:32;8950:52;;;8998:1;8995;8988:12;8950:52;9037:9;9024:23;9056:31;9081:5;9056:31;:::i;:::-;9106:5;9184:2;9169:18;;9156:32;;-1:-1:-1;9287:2:1;9272:18;;;9259:32;;8836:487;-1:-1:-1;;;8836:487:1:o;9328:226::-;9387:6;9440:2;9428:9;9419:7;9415:23;9411:32;9408:52;;;9456:1;9453;9446:12;9408:52;-1:-1:-1;9501:23:1;;9328:226;-1:-1:-1;9328:226:1:o;10121:388::-;10189:6;10197;10250:2;10238:9;10229:7;10225:23;10221:32;10218:52;;;10266:1;10263;10256:12;10218:52;10305:9;10292:23;10324:31;10349:5;10324:31;:::i;:::-;10374:5;-1:-1:-1;10431:2:1;10416:18;;10403:32;10444:33;10403:32;10444:33;:::i;11070:241::-;11126:6;11179:2;11167:9;11158:7;11154:23;11150:32;11147:52;;;11195:1;11192;11185:12;11147:52;11234:9;11221:23;11253:28;11275:5;11253:28;:::i;11505:183::-;11565:4;-1:-1:-1;;;;;11590:6:1;11587:30;11584:56;;;11620:18;;:::i;:::-;-1:-1:-1;11665:1:1;11661:14;11677:4;11657:25;;11505:183::o;11693:367::-;11756:8;11766:6;11820:3;11813:4;11805:6;11801:17;11797:27;11787:55;;11838:1;11835;11828:12;11787:55;-1:-1:-1;11861:20:1;;-1:-1:-1;;;;;11893:30:1;;11890:50;;;11936:1;11933;11926:12;11890:50;11973:4;11965:6;11961:17;11949:29;;12033:3;12026:4;12016:6;12013:1;12009:14;12001:6;11997:27;11993:38;11990:47;11987:67;;;12050:1;12047;12040:12;12065:1039;12121:5;12169:4;12157:9;12152:3;12148:19;12144:30;12141:50;;;12187:1;12184;12177:12;12141:50;12209:22;;:::i;:::-;12200:31;;12268:9;12255:23;12287:33;12312:7;12287:33;:::i;:::-;12329:22;;12403:2;12388:18;;12375:32;12416:33;12375:32;12416:33;:::i;:::-;12476:2;12465:14;;12458:31;12562:2;12547:18;;;12534:32;12582:14;;;12575:31;12658:2;12643:18;;12630:32;12671:30;12630:32;12671:30;:::i;:::-;12728:2;12717:14;;12710:31;12814:3;12799:19;;;12786:33;12835:15;;;12828:32;12933:3;12918:19;;;12905:33;12954:15;;;12947:32;13052:3;13037:19;;;13024:33;13073:15;;;13066:32;;;;12721:5;12065:1039;-1:-1:-1;12065:1039:1:o;13109:1476::-;13273:6;13281;13289;13297;13305;13358:3;13346:9;13337:7;13333:23;13329:33;13326:53;;;13375:1;13372;13365:12;13326:53;13415:9;13402:23;-1:-1:-1;;;;;13440:6:1;13437:30;13434:50;;;13480:1;13477;13470:12;13434:50;13503:22;;13556:4;13548:13;;13544:27;-1:-1:-1;13534:55:1;;13585:1;13582;13575:12;13534:55;13625:2;13612:16;13648:64;13664:47;13704:6;13664:47;:::i;:::-;13648:64;:::i;:::-;13734:3;13758:6;13753:3;13746:19;13790:4;13785:3;13781:14;13774:21;;13847:4;13837:6;13834:1;13830:14;13826:2;13822:23;13818:34;13804:48;;13875:7;13867:6;13864:19;13861:39;;;13896:1;13893;13886:12;13861:39;13928:4;13924:2;13920:13;13909:24;;13942:200;13958:6;13953:3;13950:15;13942:200;;;14050:17;;14080:18;;14127:4;13975:14;;;;14118;;;;13942:200;;;14161:5;-1:-1:-1;14185:40:1;;-1:-1:-1;;;14219:4:1;14204:20;;14185:40;:::i;:::-;14175:50;;14278:2;14267:9;14263:18;14250:32;-1:-1:-1;;;;;14297:8:1;14294:32;14291:52;;;14339:1;14336;14329:12;14291:52;14378:72;14442:7;14431:8;14420:9;14416:24;14378:72;:::i;:::-;14469:8;;-1:-1:-1;14352:98:1;-1:-1:-1;14523:56:1;;-1:-1:-1;14571:7:1;14566:2;14551:18;;14523:56;:::i;:::-;14513:66;;13109:1476;;;;;;;;:::o;14590:420::-;14643:3;14681:5;14675:12;14708:6;14703:3;14696:19;14740:4;14735:3;14731:14;14724:21;;14779:4;14772:5;14768:16;14802:1;14812:173;14826:6;14823:1;14820:13;14812:173;;;14887:13;;14875:26;;14930:4;14921:14;;;;14958:17;;;;14848:1;14841:9;14812:173;;;-1:-1:-1;15001:3:1;;14590:420;-1:-1:-1;;;;14590:420:1:o;15015:682::-;15274:2;15263:9;15256:21;15237:4;15312:6;15306:13;15355:4;15350:2;15339:9;15335:18;15328:32;15383:63;15441:3;15430:9;15426:19;15412:12;15383:63;:::i;:::-;15369:77;;15502:4;15494:6;15490:17;15484:24;15477:4;15466:9;15462:20;15455:54;15564:2;15556:6;15552:15;15546:22;15540:3;15529:9;15525:19;15518:51;15619:9;15611:6;15607:22;15600:4;15589:9;15585:20;15578:52;15647:44;15684:6;15676;15647:44;:::i;15702:472::-;15823:6;15831;15884:2;15872:9;15863:7;15859:23;15855:32;15852:52;;;15900:1;15897;15890:12;15852:52;15940:9;15927:23;-1:-1:-1;;;;;15965:6:1;15962:30;15959:50;;;16005:1;16002;15995:12;15959:50;16044:70;16106:7;16097:6;16086:9;16082:22;16044:70;:::i;:::-;16133:8;;16018:96;;-1:-1:-1;15702:472:1;-1:-1:-1;;;;15702:472:1:o;16179:288::-;16220:3;16258:5;16252:12;16285:6;16280:3;16273:19;16341:6;16334:4;16327:5;16323:16;16316:4;16311:3;16307:14;16301:47;16393:1;16386:4;16377:6;16372:3;16368:16;16364:27;16357:38;16456:4;16449:2;16445:7;16440:2;16432:6;16428:15;16424:29;16419:3;16415:39;16411:50;16404:57;;;16179:288;;;;:::o;16472:779::-;16632:4;16680:2;16669:9;16665:18;16710:2;16699:9;16692:21;16733:6;16768;16762:13;16799:6;16791;16784:22;16837:2;16826:9;16822:18;16815:25;;16899:2;16889:6;16886:1;16882:14;16871:9;16867:30;16863:39;16849:53;;16937:2;16929:6;16925:15;16958:1;16968:254;16982:6;16979:1;16976:13;16968:254;;;17075:2;17071:7;17059:9;17051:6;17047:22;17043:36;17038:3;17031:49;17103:39;17135:6;17126;17120:13;17103:39;:::i;:::-;17093:49;-1:-1:-1;17177:2:1;17200:12;;;;17165:15;;;;;17004:1;16997:9;16968:254;;;-1:-1:-1;17239:6:1;;16472:779;-1:-1:-1;;;;;;16472:779:1:o;18326:127::-;18387:10;18382:3;18378:20;18375:1;18368:31;18418:4;18415:1;18408:15;18442:4;18439:1;18432:15;18458:125;18523:9;;;18544:10;;;18541:36;;;18557:18;;:::i;18588:217::-;18628:1;18654;18644:132;;18698:10;18693:3;18689:20;18686:1;18679:31;18733:4;18730:1;18723:15;18761:4;18758:1;18751:15;18644:132;-1:-1:-1;18790:9:1;;18588:217::o;18810:245::-;18877:6;18930:2;18918:9;18909:7;18905:23;18901:32;18898:52;;;18946:1;18943;18936:12;18898:52;18978:9;18972:16;18997:28;19019:5;18997:28;:::i;19060:365::-;-1:-1:-1;;;;;19268:32:1;;;;19250:51;;19344:14;;19337:22;19332:2;19317:18;;19310:50;19403:14;19396:22;19391:2;19376:18;;19369:50;19238:2;19223:18;;19060:365::o;19430:343::-;19509:6;19517;19570:2;19558:9;19549:7;19545:23;19541:32;19538:52;;;19586:1;19583;19576:12;19538:52;-1:-1:-1;;19631:16:1;;19737:2;19722:18;;;19716:25;19631:16;;19716:25;;-1:-1:-1;19430:343:1:o;19778:128::-;19845:9;;;19866:11;;;19863:37;;;19880:18;;:::i;21467:375::-;21555:1;21573:5;21587:249;21608:1;21598:8;21595:15;21587:249;;;21658:4;21653:3;21649:14;21643:4;21640:24;21637:50;;;21667:18;;:::i;:::-;21717:1;21707:8;21703:16;21700:49;;;21731:16;;;;21700:49;21814:1;21810:16;;;;;21770:15;;21587:249;;;21467:375;;;;;;:::o;21847:902::-;21896:5;21926:8;21916:80;;-1:-1:-1;21967:1:1;21981:5;;21916:80;22015:4;22005:76;;-1:-1:-1;22052:1:1;22066:5;;22005:76;22097:4;22115:1;22110:59;;;;22183:1;22178:174;;;;22090:262;;22110:59;22140:1;22131:10;;22154:5;;;22178:174;22215:3;22205:8;22202:17;22199:43;;;22222:18;;:::i;:::-;-1:-1:-1;;22278:1:1;22264:16;;22337:5;;22090:262;;22436:2;22426:8;22423:16;22417:3;22411:4;22408:13;22404:36;22398:2;22388:8;22385:16;22380:2;22374:4;22371:12;22367:35;22364:77;22361:203;;;-1:-1:-1;22473:19:1;;;22549:5;;22361:203;22596:42;-1:-1:-1;;22621:8:1;22615:4;22596:42;:::i;:::-;22674:6;22670:1;22666:6;22662:19;22653:7;22650:32;22647:58;;;22685:18;;:::i;:::-;22723:20;;21847:902;-1:-1:-1;;;21847:902:1:o;22754:131::-;22814:5;22843:36;22870:8;22864:4;22843:36;:::i;22890:251::-;22960:6;23013:2;23001:9;22992:7;22988:23;22984:32;22981:52;;;23029:1;23026;23019:12;22981:52;23061:9;23055:16;23080:31;23105:5;23080:31;:::i;26053:127::-;26114:10;26109:3;26105:20;26102:1;26095:31;26145:4;26142:1;26135:15;26169:4;26166:1;26159:15;26185:332;26286:4;26344:11;26331:25;26438:2;26434:7;26423:8;26407:14;26403:29;26399:43;26379:18;26375:68;26365:96;;26457:1;26454;26447:12;26365:96;26478:33;;;;;26185:332;-1:-1:-1;;26185:332:1:o;26522:1180::-;26640:9;26699:4;26691:5;26675:14;26671:26;26667:37;26664:57;;;26717:1;26714;26707:12;26664:57;26745:22;;:::i;:::-;26804:5;26791:19;26819:33;26844:7;26819:33;:::i;:::-;26861:24;;26933:2;26922:14;;26909:28;26946:30;26909:28;26946:30;:::i;:::-;27005:2;26992:16;;26985:33;27065:2;27054:14;;27041:28;-1:-1:-1;;;;;27081:30:1;;27078:50;;;27124:1;27121;27114:12;27078:50;27147:18;;27203:14;27196:4;27188:13;;27184:34;27174:62;;27232:1;27229;27222:12;27174:62;27272:2;27259:16;-1:-1:-1;;;;;27290:6:1;27287:30;27284:56;;;27320:18;;:::i;:::-;27362:57;27409:2;27386:17;;-1:-1:-1;;27382:31:1;27415:2;27378:40;27362:57;:::i;:::-;27442:6;27435:5;27428:21;27490:14;27485:2;27476:6;27472:2;27468:15;27464:24;27461:44;27458:64;;;27518:1;27515;27508:12;27458:64;27573:6;27568:2;27564;27560:11;27555:2;27548:5;27544:14;27531:49;27625:1;27600:18;;;27620:2;27596:27;27589:38;;;;27656:2;27643:16;;27636:31;-1:-1:-1;27647:7:1;26522:1180;-1:-1:-1;;26522:1180:1:o;27707:411::-;-1:-1:-1;;;;;27910:32:1;;;27892:51;;27979:32;;27974:2;27959:18;;27952:60;28048:2;28043;28028:18;;28021:30;;;-1:-1:-1;;28068:44:1;;28093:18;;28085:6;28068:44;:::i;28123:140::-;28181:5;28210:47;28251:4;28241:8;28237:19;28231:4;28210:47;:::i;28644:160::-;28721:13;;28774:4;28763:16;;28753:27;;28743:55;;28794:1;28791;28784:12;28809:204;28877:6;28930:2;28918:9;28909:7;28905:23;28901:32;28898:52;;;28946:1;28943;28936:12;28898:52;28969:38;28997:9;28969:38;:::i;29018:168::-;29091:9;;;29122;;29139:15;;;29133:22;;29119:37;29109:71;;29160:18;;:::i;29191:230::-;29261:6;29314:2;29302:9;29293:7;29289:23;29285:32;29282:52;;;29330:1;29327;29320:12;29282:52;-1:-1:-1;29375:16:1;;29191:230;-1:-1:-1;29191:230:1:o;29426:301::-;29555:3;29593:6;29587:13;29639:6;29632:4;29624:6;29620:17;29615:3;29609:37;29701:1;29665:16;;29690:13;;;-1:-1:-1;29665:16:1;29426:301;-1:-1:-1;29426:301:1:o;29732:829::-;-1:-1:-1;;;;;30005:32:1;;29987:51;;29975:2;30069;30054:18;;;30047:30;;;30126:13;;29960:18;;;30148:22;;;29927:4;30214:17;;;30254:16;;;29927:4;;30201:3;30186:19;;;29927:4;30298:194;30312:6;30309:1;30306:13;30298:194;;;30377:13;;-1:-1:-1;;;;;30373:39:1;30361:52;;30409:1;30468:14;;;;30442:2;30433:12;;;;30327:9;30298:194;;;-1:-1:-1;;30543:2:1;30528:18;;;;30521:34;;;;-1:-1:-1;30509:3:1;29732:829;-1:-1:-1;;;29732:829:1:o;30566:720::-;30631:5;30684:3;30677:4;30669:6;30665:17;30661:27;30651:55;;30702:1;30699;30692:12;30651:55;30735:6;30729:13;30762:64;30778:47;30818:6;30778:47;:::i;30762:64::-;30850:3;30874:6;30869:3;30862:19;30906:4;30901:3;30897:14;30890:21;;30967:4;30957:6;30954:1;30950:14;30942:6;30938:27;30934:38;30920:52;;30995:3;30987:6;30984:15;30981:35;;;31012:1;31009;31002:12;30981:35;31048:4;31040:6;31036:17;31062:193;31078:6;31073:3;31070:15;31062:193;;;31170:10;;31193:18;;31240:4;31231:14;;;;31095;31062:193;;;-1:-1:-1;31273:7:1;30566:720;-1:-1:-1;;;;;30566:720:1:o;31291:2095::-;31462:6;31470;31478;31531:2;31519:9;31510:7;31506:23;31502:32;31499:52;;;31547:1;31544;31537:12;31499:52;31580:9;31574:16;-1:-1:-1;;;;;31605:6:1;31602:30;31599:50;;;31645:1;31642;31635:12;31599:50;31668:22;;31721:4;31713:13;;31709:27;-1:-1:-1;31699:55:1;;31750:1;31747;31740:12;31699:55;31783:2;31777:9;31806:64;31822:47;31862:6;31822:47;:::i;31806:64::-;31892:3;31916:6;31911:3;31904:19;31948:4;31943:3;31939:14;31932:21;;32008:4;32000;31992:6;31988:17;31984:2;31980:26;31976:37;31962:51;;32036:7;32028:6;32025:19;32022:39;;;32057:1;32054;32047:12;32022:39;32089:4;32085:2;32081:13;32070:24;;32103:951;32119:6;32114:3;32111:15;32103:951;;;32201:4;32195:3;32186:7;32182:17;32178:28;32175:48;;;32219:1;32216;32209:12;32175:48;32249:22;;:::i;:::-;32305:3;32299:10;32322:33;32347:7;32322:33;:::i;:::-;32368:22;;32433:4;32424:14;;32418:21;32452:33;32418:21;32452:33;:::i;:::-;32516:4;32505:16;;32498:33;32567:41;32604:2;32595:12;;32567:41;:::i;:::-;32562:2;32555:5;32551:14;32544:65;32652:2;32647:3;32643:12;32637:19;32669:30;32691:7;32669:30;:::i;:::-;32730:2;32719:14;;32712:31;32811:3;32802:13;;;32796:20;32836:15;;;32829:32;32929:3;32920:13;;;32914:20;32954:15;;;32947:32;32992:18;;32145:4;32136:14;;;;33039:4;33030:14;;;;32103:951;;;33073:5;33063:15;;;;;;33124:4;33113:9;33109:20;33103:27;-1:-1:-1;;;;;33145:8:1;33142:32;33139:52;;;33187:1;33184;33177:12;33139:52;33210:74;33276:7;33265:8;33254:9;33250:24;33210:74;:::i;:::-;33350:2;33335:18;;;;33329:25;31291:2095;;33200:84;;-1:-1:-1;33329:25:1;;31291:2095;-1:-1:-1;;;31291:2095:1:o;33391:135::-;33430:3;33451:17;;;33448:43;;33471:18;;:::i;:::-;-1:-1:-1;33518:1:1;33507:13;;33391:135::o

Swarm Source

ipfs://3480a9d34d0738f022270141175efb5c96b0766841cbae8de67341217ab4a49d

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.