ETH Price: $1,843.80 (-14.00%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RiskManager

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion, BSL 1.1 license
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.0;

import "../BaseLogic.sol";
import "../IRiskManager.sol";
import "../vendor/TickMath.sol";
import "../vendor/FullMath.sol";



interface IUniswapV3Factory {
    function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool);
}

interface IUniswapV3Pool {
    function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked);
    function liquidity() external view returns (uint128);
    function observe(uint32[] calldata secondsAgos) external view returns (int56[] memory tickCumulatives, uint160[] memory liquidityCumulatives);
    function observations(uint256 index) external view returns (uint32 blockTimestamp, int56 tickCumulative, uint160 liquidityCumulative, bool initialized);
    function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}


contract RiskManager is IRiskManager, BaseLogic {
    // Construction

    address immutable referenceAsset; // Token must have 18 decimals
    address immutable uniswapFactory;
    bytes32 immutable uniswapPoolInitCodeHash;

    struct RiskManagerSettings {
        address referenceAsset;
        address uniswapFactory;
        bytes32 uniswapPoolInitCodeHash;
    }

    constructor(bytes32 moduleGitCommit_, RiskManagerSettings memory settings) BaseLogic(MODULEID__RISK_MANAGER, moduleGitCommit_) {
        referenceAsset = settings.referenceAsset;
        uniswapFactory = settings.uniswapFactory;
        uniswapPoolInitCodeHash = settings.uniswapPoolInitCodeHash;
    }


    // Default market parameters

    function getNewMarketParameters(address underlying) external override returns (NewMarketParameters memory p) {
        p.config.borrowIsolated = true;
        p.config.collateralFactor = uint32(0);
        p.config.borrowFactor = type(uint32).max;
        p.config.twapWindow = type(uint24).max;

        if (underlying == referenceAsset) {
            // 1:1 peg

            p.pricingType = PRICINGTYPE__PEGGED;
            p.pricingParameters = uint32(0);
        } else if (pTokenLookup[underlying] != address(0)) {
            p.pricingType = PRICINGTYPE__FORWARDED;
            p.pricingParameters = uint32(0);

            p.config.collateralFactor = underlyingLookup[pTokenLookup[underlying]].collateralFactor;
        } else {
            // Uniswap3 TWAP

            // The uniswap pool (fee-level) with the highest in-range liquidity is used by default.
            // This is a heuristic and can easily be manipulated by the activator, so users should
            // verify the selection is suitable before using the pool. Otherwise, governance will
            // need to change the pricing config for the market.

            address pool = address(0);
            uint24 fee = 0;

            {
                uint24[4] memory fees = [uint24(3000), 10000, 500, 100];
                uint128 bestLiquidity = 0;

                for (uint i = 0; i < fees.length; ++i) {
                    address candidatePool = IUniswapV3Factory(uniswapFactory).getPool(underlying, referenceAsset, fees[i]);
                    if (candidatePool == address(0)) continue;

                    uint128 liquidity = IUniswapV3Pool(candidatePool).liquidity();

                    if (pool == address(0) || liquidity > bestLiquidity) {
                        pool = candidatePool;
                        fee = fees[i];
                        bestLiquidity = liquidity;
                    }
                }
            }

            require(pool != address(0), "e/no-uniswap-pool-avail");
            require(computeUniswapPoolAddress(underlying, fee) == pool, "e/bad-uniswap-pool-addr");

            p.pricingType = PRICINGTYPE__UNISWAP3_TWAP;
            p.pricingParameters = uint32(fee);

            try IUniswapV3Pool(pool).increaseObservationCardinalityNext(MIN_UNISWAP3_OBSERVATION_CARDINALITY) {
                // Success
            } catch Error(string memory err) {
                if (keccak256(bytes(err)) == keccak256("LOK")) revert("e/risk/uniswap-pool-not-inited");
                revert(string(abi.encodePacked("e/risk/uniswap/", err)));
            } catch (bytes memory returnData) {
                revertBytes(returnData);
            }
        }
    }



    // Pricing

    function computeUniswapPoolAddress(address underlying, uint24 fee) private view returns (address) {
        address tokenA = underlying;
        address tokenB = referenceAsset;
        if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);

        return address(uint160(uint256(keccak256(abi.encodePacked(
                   hex'ff',
                   uniswapFactory,
                   keccak256(abi.encode(tokenA, tokenB, fee)),
                   uniswapPoolInitCodeHash
               )))));
    }


    function decodeSqrtPriceX96(AssetCache memory assetCache, uint sqrtPriceX96) private view returns (uint price) {
        if (uint160(assetCache.underlying) < uint160(referenceAsset)) {
            price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / 1e18) / assetCache.underlyingDecimalsScaler;
        } else {
            price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / (1e18 * assetCache.underlyingDecimalsScaler));
            if (price == 0) return 1e36;
            price = 1e36 / price;
        }

        if (price > 1e36) price = 1e36;
        else if (price == 0) price = 1;
    }

    function callUniswapObserve(AssetCache memory assetCache, address pool, uint ago) private view returns (uint, uint) {
        uint32[] memory secondsAgos = new uint32[](2);

        secondsAgos[0] = uint32(ago);
        secondsAgos[1] = 0;

        (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IUniswapV3Pool.observe.selector, secondsAgos));

        if (!success) {
            if (keccak256(data) != keccak256(abi.encodeWithSignature("Error(string)", "OLD"))) revertBytes(data);

            // The oldest available observation in the ring buffer is the index following the current (accounting for wrapping),
            // since this is the one that will be overwritten next.

            (,, uint16 index, uint16 cardinality,,,) = IUniswapV3Pool(pool).slot0();

            (uint32 oldestAvailableAge,,,bool initialized) = IUniswapV3Pool(pool).observations((index + 1) % cardinality);

            // If the following observation in a ring buffer of our current cardinality is uninitialized, then all the
            // observations at higher indices are also uninitialized, so we wrap back to index 0, which we now know
            // to be the oldest available observation.

            if (!initialized) (oldestAvailableAge,,,) = IUniswapV3Pool(pool).observations(0);

            // Call observe() again to get the oldest available

            ago = block.timestamp - oldestAvailableAge;
            secondsAgos[0] = uint32(ago);

            (success, data) = pool.staticcall(abi.encodeWithSelector(IUniswapV3Pool.observe.selector, secondsAgos));
            if (!success) revertBytes(data);
        }

        // If uniswap pool doesn't exist, then data will be empty and this decode will throw:

        int56[] memory tickCumulatives = abi.decode(data, (int56[])); // don't bother decoding the liquidityCumulatives array

        int24 tick = int24((tickCumulatives[1] - tickCumulatives[0]) / int56(int(ago)));

        uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(tick);

        return (decodeSqrtPriceX96(assetCache, sqrtPriceX96), ago);
    }

    function resolvePricingConfig(AssetCache memory assetCache, AssetConfig memory config) private view returns (address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow) {
        if (assetCache.pricingType == PRICINGTYPE__FORWARDED) {
            underlying = pTokenLookup[assetCache.underlying];

            AssetConfig memory newConfig = resolveAssetConfig(underlying);
            twapWindow = newConfig.twapWindow;

            AssetStorage storage newAssetStorage = eTokenLookup[newConfig.eTokenAddress];
            pricingType = newAssetStorage.pricingType;
            pricingParameters = newAssetStorage.pricingParameters;

            require(pricingType != PRICINGTYPE__FORWARDED, "e/nested-price-forwarding");
        } else {
            underlying = assetCache.underlying;
            pricingType = assetCache.pricingType;
            pricingParameters = assetCache.pricingParameters;
            twapWindow = config.twapWindow;
        }
    }

    function getPriceInternal(AssetCache memory assetCache, AssetConfig memory config) public view FREEMEM returns (uint twap, uint twapPeriod) {
        (address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow) = resolvePricingConfig(assetCache, config);

        if (pricingType == PRICINGTYPE__PEGGED) {
            twap = 1e18;
            twapPeriod = twapWindow;
        } else if (pricingType == PRICINGTYPE__UNISWAP3_TWAP) {
            address pool = computeUniswapPoolAddress(underlying, uint24(pricingParameters));
            (twap, twapPeriod) = callUniswapObserve(assetCache, pool, twapWindow);
        } else {
            revert("e/unknown-pricing-type");
        }
    }

    function getPrice(address underlying) external view override returns (uint twap, uint twapPeriod) {
        AssetConfig memory config = resolveAssetConfig(underlying);
        AssetStorage storage assetStorage = eTokenLookup[config.eTokenAddress];
        AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);

        (twap, twapPeriod) = getPriceInternal(assetCache, config);
    }

    // This function is only meant to be called from a view so it doesn't need to be optimised.
    // The Euler protocol itself doesn't ever use currPrice as returned by this function.

    function getPriceFull(address underlying) external view override returns (uint twap, uint twapPeriod, uint currPrice) {
        AssetConfig memory config = resolveAssetConfig(underlying);
        AssetStorage storage assetStorage = eTokenLookup[config.eTokenAddress];
        AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);

        (twap, twapPeriod) = getPriceInternal(assetCache, config);

        (address newUnderlying, uint16 pricingType, uint32 pricingParameters,) = resolvePricingConfig(assetCache, config);

        if (pricingType == PRICINGTYPE__PEGGED) {
            currPrice = 1e18;
        } else if (pricingType == PRICINGTYPE__UNISWAP3_TWAP || pricingType == PRICINGTYPE__FORWARDED) {
            AssetCache memory newAssetCache = loadAssetCacheRO(newUnderlying, assetStorage);
            address pool = computeUniswapPoolAddress(newUnderlying, uint24(pricingParameters));
            (uint160 sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0();
            currPrice = decodeSqrtPriceX96(newAssetCache, sqrtPriceX96);
        } else {
            revert("e/unknown-pricing-type");
        }
    }


    // Liquidity

    function computeLiquidityRaw(address account, address[] memory underlyings) private view returns (LiquidityStatus memory status) {
        status.collateralValue = 0;
        status.liabilityValue = 0;
        status.numBorrows = 0;
        status.borrowIsolated = false;

        AssetConfig memory config;
        AssetStorage storage assetStorage;
        AssetCache memory assetCache;

        for (uint i = 0; i < underlyings.length; ++i) {
            address underlying = underlyings[i];
            bool assetCacheAndPriceInited = false;
            uint price;

            config = resolveAssetConfig(underlying);
            assetStorage = eTokenLookup[config.eTokenAddress];

            uint balance = assetStorage.users[account].balance;
            uint owed = assetStorage.users[account].owed;

            if (balance != 0 && config.collateralFactor != 0) {
                initAssetCache(underlying, assetStorage, assetCache);
                (price,) = getPriceInternal(assetCache, config);
                assetCacheAndPriceInited = true;

                uint assetCollateral = balanceToUnderlyingAmount(assetCache, balance);
                assetCollateral = assetCollateral * price / 1e18;
                assetCollateral = assetCollateral * config.collateralFactor / CONFIG_FACTOR_SCALE;
                status.collateralValue += assetCollateral;
            }

            if (owed != 0) {
                if (!assetCacheAndPriceInited) {
                    initAssetCache(underlying, assetStorage, assetCache);
                    (price,) = getPriceInternal(assetCache, config);
                    assetCacheAndPriceInited = true;
                }

                status.numBorrows++;
                if (config.borrowIsolated) status.borrowIsolated = true;

                uint assetLiability = getCurrentOwed(assetStorage, assetCache, account);
                assetLiability = assetLiability * price / 1e18;
                assetLiability = config.borrowFactor != 0 ? assetLiability * CONFIG_FACTOR_SCALE / config.borrowFactor : MAX_SANE_DEBT_AMOUNT;
                status.liabilityValue += assetLiability;
            }
        }
    }

    function computeLiquidity(address account) public view override returns (LiquidityStatus memory) {
        return computeLiquidityRaw(account, getEnteredMarketsArray(account));
    }

    function computeAssetLiquidities(address account) external view override returns (AssetLiquidity[] memory) {
        address[] memory underlyings = getEnteredMarketsArray(account);

        AssetLiquidity[] memory output = new AssetLiquidity[](underlyings.length);

        address[] memory singleUnderlying = new address[](1);

        for (uint i = 0; i < underlyings.length; ++i) {
            output[i].underlying = singleUnderlying[0] = underlyings[i];
            output[i].status = computeLiquidityRaw(account, singleUnderlying);
        }

        return output;
    }

    function requireLiquidity(address account) external view override {
        LiquidityStatus memory status = computeLiquidity(account);

        require(!status.borrowIsolated || status.numBorrows == 1, "e/borrow-isolation-violation");
        require(status.collateralValue >= status.liabilityValue, "e/collateral-violation");
    }
}

File 2 of 15 : BaseLogic.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./BaseModule.sol";
import "./BaseIRM.sol";
import "./Interfaces.sol";
import "./Utils.sol";
import "./vendor/RPow.sol";
import "./IRiskManager.sol";


abstract contract BaseLogic is BaseModule {
    constructor(uint moduleId_, bytes32 moduleGitCommit_) BaseModule(moduleId_, moduleGitCommit_) {}


    // Account auth

    function getSubAccount(address primary, uint subAccountId) internal pure returns (address) {
        require(subAccountId < 256, "e/sub-account-id-too-big");
        return address(uint160(primary) ^ uint160(subAccountId));
    }

    function isSubAccountOf(address primary, address subAccount) internal pure returns (bool) {
        return (uint160(primary) | 0xFF) == (uint160(subAccount) | 0xFF);
    }



    // Entered markets array

    function getEnteredMarketsArray(address account) internal view returns (address[] memory) {
        uint32 numMarketsEntered = accountLookup[account].numMarketsEntered;
        address firstMarketEntered = accountLookup[account].firstMarketEntered;

        address[] memory output = new address[](numMarketsEntered);
        if (numMarketsEntered == 0) return output;

        address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];

        output[0] = firstMarketEntered;

        for (uint i = 1; i < numMarketsEntered; ++i) {
            output[i] = markets[i];
        }

        return output;
    }

    function isEnteredInMarket(address account, address underlying) internal view returns (bool) {
        uint32 numMarketsEntered = accountLookup[account].numMarketsEntered;
        address firstMarketEntered = accountLookup[account].firstMarketEntered;

        if (numMarketsEntered == 0) return false;
        if (firstMarketEntered == underlying) return true;

        address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];

        for (uint i = 1; i < numMarketsEntered; ++i) {
            if (markets[i] == underlying) return true;
        }

        return false;
    }

    function doEnterMarket(address account, address underlying) internal {
        AccountStorage storage accountStorage = accountLookup[account];

        uint32 numMarketsEntered = accountStorage.numMarketsEntered;
        address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];

        if (numMarketsEntered != 0) {
            if (accountStorage.firstMarketEntered == underlying) return; // already entered
            for (uint i = 1; i < numMarketsEntered; i++) {
                if (markets[i] == underlying) return; // already entered
            }
        }

        require(numMarketsEntered < MAX_ENTERED_MARKETS, "e/too-many-entered-markets");

        if (numMarketsEntered == 0) accountStorage.firstMarketEntered = underlying;
        else markets[numMarketsEntered] = underlying;

        accountStorage.numMarketsEntered = numMarketsEntered + 1;

        emit EnterMarket(underlying, account);
    }

    // Liquidity check must be done by caller after calling this

    function doExitMarket(address account, address underlying) internal {
        AccountStorage storage accountStorage = accountLookup[account];

        uint32 numMarketsEntered = accountStorage.numMarketsEntered;
        address[MAX_POSSIBLE_ENTERED_MARKETS] storage markets = marketsEntered[account];
        uint searchIndex = type(uint).max;

        if (numMarketsEntered == 0) return; // already exited

        if (accountStorage.firstMarketEntered == underlying) {
            searchIndex = 0;
        } else {
            for (uint i = 1; i < numMarketsEntered; i++) {
                if (markets[i] == underlying) {
                    searchIndex = i;
                    break;
                }
            }

            if (searchIndex == type(uint).max) return; // already exited
        }

        uint lastMarketIndex = numMarketsEntered - 1;

        if (searchIndex != lastMarketIndex) {
            if (searchIndex == 0) accountStorage.firstMarketEntered = markets[lastMarketIndex];
            else markets[searchIndex] = markets[lastMarketIndex];
        }

        accountStorage.numMarketsEntered = uint32(lastMarketIndex);

        if (lastMarketIndex != 0) markets[lastMarketIndex] = address(0); // zero out for storage refund

        emit ExitMarket(underlying, account);
    }



    // AssetConfig

    function resolveAssetConfig(address underlying) internal view returns (AssetConfig memory) {
        AssetConfig memory config = underlyingLookup[underlying];
        require(config.eTokenAddress != address(0), "e/market-not-activated");

        if (config.borrowFactor == type(uint32).max) config.borrowFactor = DEFAULT_BORROW_FACTOR;
        if (config.twapWindow == type(uint24).max) config.twapWindow = DEFAULT_TWAP_WINDOW_SECONDS;

        return config;
    }


    // AssetCache

    struct AssetCache {
        address underlying;

        uint112 totalBalances;
        uint144 totalBorrows;

        uint96 reserveBalance;

        uint interestAccumulator;

        uint40 lastInterestAccumulatorUpdate;
        uint8 underlyingDecimals;
        uint32 interestRateModel;
        int96 interestRate;
        uint32 reserveFee;
        uint16 pricingType;
        uint32 pricingParameters;

        uint poolSize; // result of calling balanceOf on underlying (in external units)

        uint underlyingDecimalsScaler;
        uint maxExternalAmount;
    }

    function initAssetCache(address underlying, AssetStorage storage assetStorage, AssetCache memory assetCache) internal view returns (bool dirty) {
        dirty = false;

        assetCache.underlying = underlying;

        // Storage loads

        assetCache.lastInterestAccumulatorUpdate = assetStorage.lastInterestAccumulatorUpdate;
        uint8 underlyingDecimals = assetCache.underlyingDecimals = assetStorage.underlyingDecimals;
        assetCache.interestRateModel = assetStorage.interestRateModel;
        assetCache.interestRate = assetStorage.interestRate;
        assetCache.reserveFee = assetStorage.reserveFee;
        assetCache.pricingType = assetStorage.pricingType;
        assetCache.pricingParameters = assetStorage.pricingParameters;

        assetCache.reserveBalance = assetStorage.reserveBalance;

        assetCache.totalBalances = assetStorage.totalBalances;
        assetCache.totalBorrows = assetStorage.totalBorrows;

        assetCache.interestAccumulator = assetStorage.interestAccumulator;

        // Derived state

        unchecked {
            assetCache.underlyingDecimalsScaler = 10**(18 - underlyingDecimals);
            assetCache.maxExternalAmount = MAX_SANE_AMOUNT / assetCache.underlyingDecimalsScaler;
        }

        uint poolSize = callBalanceOf(assetCache, address(this));
        if (poolSize <= assetCache.maxExternalAmount) {
            unchecked { assetCache.poolSize = poolSize * assetCache.underlyingDecimalsScaler; }
        } else {
            assetCache.poolSize = 0;
        }

        // Update interest accumulator and reserves

        if (block.timestamp != assetCache.lastInterestAccumulatorUpdate) {
            dirty = true;

            uint deltaT = block.timestamp - assetCache.lastInterestAccumulatorUpdate;

            // Compute new values

            uint newInterestAccumulator = (RPow.rpow(uint(int(assetCache.interestRate) + 1e27), deltaT, 1e27) * assetCache.interestAccumulator) / 1e27;

            uint newTotalBorrows = assetCache.totalBorrows * newInterestAccumulator / assetCache.interestAccumulator;

            uint newReserveBalance = assetCache.reserveBalance;
            uint newTotalBalances = assetCache.totalBalances;

            uint feeAmount = (newTotalBorrows - assetCache.totalBorrows)
                               * (assetCache.reserveFee == type(uint32).max ? DEFAULT_RESERVE_FEE : assetCache.reserveFee)
                               / (RESERVE_FEE_SCALE * INTERNAL_DEBT_PRECISION);

            if (feeAmount != 0) {
                uint poolAssets = assetCache.poolSize + (newTotalBorrows / INTERNAL_DEBT_PRECISION);
                newTotalBalances = poolAssets * newTotalBalances / (poolAssets - feeAmount);
                newReserveBalance += newTotalBalances - assetCache.totalBalances;
            }

            // Store new values in assetCache, only if no overflows will occur

            if (newTotalBalances <= MAX_SANE_AMOUNT && newTotalBorrows <= MAX_SANE_DEBT_AMOUNT) {
                assetCache.totalBorrows = encodeDebtAmount(newTotalBorrows);
                assetCache.interestAccumulator = newInterestAccumulator;
                assetCache.lastInterestAccumulatorUpdate = uint40(block.timestamp);

                if (newTotalBalances != assetCache.totalBalances) {
                    assetCache.reserveBalance = encodeSmallAmount(newReserveBalance);
                    assetCache.totalBalances = encodeAmount(newTotalBalances);
                }
            }
        }
    }

    function loadAssetCache(address underlying, AssetStorage storage assetStorage) internal returns (AssetCache memory assetCache) {
        if (initAssetCache(underlying, assetStorage, assetCache)) {
            assetStorage.lastInterestAccumulatorUpdate = assetCache.lastInterestAccumulatorUpdate;

            assetStorage.underlying = assetCache.underlying; // avoid an SLOAD of this slot
            assetStorage.reserveBalance = assetCache.reserveBalance;

            assetStorage.totalBalances = assetCache.totalBalances;
            assetStorage.totalBorrows = assetCache.totalBorrows;

            assetStorage.interestAccumulator = assetCache.interestAccumulator;
        }
    }

    function loadAssetCacheRO(address underlying, AssetStorage storage assetStorage) internal view returns (AssetCache memory assetCache) {
        initAssetCache(underlying, assetStorage, assetCache);
    }



    // Utils

    function decodeExternalAmount(AssetCache memory assetCache, uint externalAmount) internal pure returns (uint scaledAmount) {
        require(externalAmount <= assetCache.maxExternalAmount, "e/amount-too-large");
        unchecked { scaledAmount = externalAmount * assetCache.underlyingDecimalsScaler; }
    }

    function encodeAmount(uint amount) internal pure returns (uint112) {
        require(amount <= MAX_SANE_AMOUNT, "e/amount-too-large-to-encode");
        return uint112(amount);
    }

    function encodeSmallAmount(uint amount) internal pure returns (uint96) {
        require(amount <= MAX_SANE_SMALL_AMOUNT, "e/small-amount-too-large-to-encode");
        return uint96(amount);
    }

    function encodeDebtAmount(uint amount) internal pure returns (uint144) {
        require(amount <= MAX_SANE_DEBT_AMOUNT, "e/debt-amount-too-large-to-encode");
        return uint144(amount);
    }

    function computeExchangeRate(AssetCache memory assetCache) private pure returns (uint) {
        if (assetCache.totalBalances == 0) return 1e18;
        return (assetCache.poolSize + (assetCache.totalBorrows / INTERNAL_DEBT_PRECISION)) * 1e18 / assetCache.totalBalances;
    }

    function underlyingAmountToBalance(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
        uint exchangeRate = computeExchangeRate(assetCache);
        return amount * 1e18 / exchangeRate;
    }

    function underlyingAmountToBalanceRoundUp(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
        uint exchangeRate = computeExchangeRate(assetCache);
        return (amount * 1e18 + (exchangeRate - 1)) / exchangeRate;
    }

    function balanceToUnderlyingAmount(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
        uint exchangeRate = computeExchangeRate(assetCache);
        return amount * exchangeRate / 1e18;
    }

    function callBalanceOf(AssetCache memory assetCache, address account) internal view FREEMEM returns (uint) {
        // We set a gas limit so that a malicious token can't eat up all gas and cause a liquidity check to fail.

        (bool success, bytes memory data) = assetCache.underlying.staticcall{gas: 20000}(abi.encodeWithSelector(IERC20.balanceOf.selector, account));

        // If token's balanceOf() call fails for any reason, return 0. This prevents malicious tokens from causing liquidity checks to fail.
        // If the contract doesn't exist (maybe because selfdestructed), then data.length will be 0 and we will return 0.
        // Data length > 32 is allowed because some legitimate tokens append extra data that can be safely ignored.

        if (!success || data.length < 32) return 0;

        return abi.decode(data, (uint256));
    }

    function updateInterestRate(AssetStorage storage assetStorage, AssetCache memory assetCache) internal {
        uint32 utilisation;

        {
            uint totalBorrows = assetCache.totalBorrows / INTERNAL_DEBT_PRECISION;
            uint poolAssets = assetCache.poolSize + totalBorrows;
            if (poolAssets == 0) utilisation = 0; // empty pool arbitrarily given utilisation of 0
            else utilisation = uint32(totalBorrows * (uint(type(uint32).max) * 1e18) / poolAssets / 1e18);
        }

        bytes memory result = callInternalModule(assetCache.interestRateModel,
                                                 abi.encodeWithSelector(BaseIRM.computeInterestRate.selector, assetCache.underlying, utilisation));

        (int96 newInterestRate) = abi.decode(result, (int96));

        assetStorage.interestRate = assetCache.interestRate = newInterestRate;
    }

    function logAssetStatus(AssetCache memory a) internal {
        emit AssetStatus(a.underlying, a.totalBalances, a.totalBorrows / INTERNAL_DEBT_PRECISION, a.reserveBalance, a.poolSize, a.interestAccumulator, a.interestRate, block.timestamp);
    }



    // Balances

    function increaseBalance(AssetStorage storage assetStorage, AssetCache memory assetCache, address eTokenAddress, address account, uint amount) internal {
        assetStorage.users[account].balance = encodeAmount(assetStorage.users[account].balance + amount);

        assetStorage.totalBalances = assetCache.totalBalances = encodeAmount(uint(assetCache.totalBalances) + amount);

        updateInterestRate(assetStorage, assetCache);

        emit Deposit(assetCache.underlying, account, amount);
        emitViaProxy_Transfer(eTokenAddress, address(0), account, amount);
    }

    function decreaseBalance(AssetStorage storage assetStorage, AssetCache memory assetCache, address eTokenAddress, address account, uint amount) internal {
        uint origBalance = assetStorage.users[account].balance;
        require(origBalance >= amount, "e/insufficient-balance");
        assetStorage.users[account].balance = encodeAmount(origBalance - amount);

        assetStorage.totalBalances = assetCache.totalBalances = encodeAmount(assetCache.totalBalances - amount);

        updateInterestRate(assetStorage, assetCache);

        emit Withdraw(assetCache.underlying, account, amount);
        emitViaProxy_Transfer(eTokenAddress, account, address(0), amount);
    }

    function transferBalance(AssetStorage storage assetStorage, AssetCache memory assetCache, address eTokenAddress, address from, address to, uint amount) internal {
        uint origFromBalance = assetStorage.users[from].balance;
        require(origFromBalance >= amount, "e/insufficient-balance");
        uint newFromBalance;
        unchecked { newFromBalance = origFromBalance - amount; }

        assetStorage.users[from].balance = encodeAmount(newFromBalance);
        assetStorage.users[to].balance = encodeAmount(assetStorage.users[to].balance + amount);

        emit Withdraw(assetCache.underlying, from, amount);
        emit Deposit(assetCache.underlying, to, amount);
        emitViaProxy_Transfer(eTokenAddress, from, to, amount);
    }

    function withdrawAmounts(AssetStorage storage assetStorage, AssetCache memory assetCache, address account, uint amount) internal view returns (uint, uint) {
        uint amountInternal;
        if (amount == type(uint).max) {
            amountInternal = assetStorage.users[account].balance;
            amount = balanceToUnderlyingAmount(assetCache, amountInternal);
        } else {
            amount = decodeExternalAmount(assetCache, amount);
            amountInternal = underlyingAmountToBalanceRoundUp(assetCache, amount);
        }

        return (amount, amountInternal);
    }

    // Borrows

    // Returns internal precision

    function getCurrentOwedExact(AssetStorage storage assetStorage, AssetCache memory assetCache, address account, uint owed) internal view returns (uint) {
        // Don't bother loading the user's accumulator
        if (owed == 0) return 0;

        // Can't divide by 0 here: If owed is non-zero, we must've initialised the user's interestAccumulator
        return owed * assetCache.interestAccumulator / assetStorage.users[account].interestAccumulator;
    }

    // When non-zero, we round *up* to the smallest external unit so that outstanding dust in a loan can be repaid.
    // unchecked is OK here since owed is always loaded from storage, so we know it fits into a uint144 (pre-interest accural)
    // Takes and returns 27 decimals precision.

    function roundUpOwed(AssetCache memory assetCache, uint owed) private pure returns (uint) {
        if (owed == 0) return 0;

        unchecked {
            uint scale = INTERNAL_DEBT_PRECISION * assetCache.underlyingDecimalsScaler;
            return (owed + scale - 1) / scale * scale;
        }
    }

    // Returns 18-decimals precision (debt amount is rounded up)

    function getCurrentOwed(AssetStorage storage assetStorage, AssetCache memory assetCache, address account) internal view returns (uint) {
        return roundUpOwed(assetCache, getCurrentOwedExact(assetStorage, assetCache, account, assetStorage.users[account].owed)) / INTERNAL_DEBT_PRECISION;
    }

    function updateUserBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address account) private returns (uint newOwedExact, uint prevOwedExact) {
        prevOwedExact = assetStorage.users[account].owed;

        newOwedExact = getCurrentOwedExact(assetStorage, assetCache, account, prevOwedExact);

        assetStorage.users[account].owed = encodeDebtAmount(newOwedExact);
        assetStorage.users[account].interestAccumulator = assetCache.interestAccumulator;
    }

    function logBorrowChange(AssetCache memory assetCache, address dTokenAddress, address account, uint prevOwed, uint owed) private {
        prevOwed = roundUpOwed(assetCache, prevOwed) / INTERNAL_DEBT_PRECISION;
        owed = roundUpOwed(assetCache, owed) / INTERNAL_DEBT_PRECISION;

        if (owed > prevOwed) {
            uint change = owed - prevOwed;
            emit Borrow(assetCache.underlying, account, change);
            emitViaProxy_Transfer(dTokenAddress, address(0), account, change);
        } else if (prevOwed > owed) {
            uint change = prevOwed - owed;
            emit Repay(assetCache.underlying, account, change);
            emitViaProxy_Transfer(dTokenAddress, account, address(0), change);
        }
    }

    function increaseBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address account, uint amount) internal {
        amount *= INTERNAL_DEBT_PRECISION;

        require(assetCache.pricingType != PRICINGTYPE__FORWARDED || pTokenLookup[assetCache.underlying] == address(0), "e/borrow-not-supported");

        (uint owed, uint prevOwed) = updateUserBorrow(assetStorage, assetCache, account);

        if (owed == 0) doEnterMarket(account, assetCache.underlying);

        owed += amount;

        assetStorage.users[account].owed = encodeDebtAmount(owed);
        assetStorage.totalBorrows = assetCache.totalBorrows = encodeDebtAmount(assetCache.totalBorrows + amount);

        updateInterestRate(assetStorage, assetCache);

        logBorrowChange(assetCache, dTokenAddress, account, prevOwed, owed);
    }

    function decreaseBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address account, uint origAmount) internal {
        uint amount = origAmount * INTERNAL_DEBT_PRECISION;

        (uint owed, uint prevOwed) = updateUserBorrow(assetStorage, assetCache, account);
        uint owedRoundedUp = roundUpOwed(assetCache, owed);

        require(amount <= owedRoundedUp, "e/repay-too-much");
        uint owedRemaining;
        unchecked { owedRemaining = owedRoundedUp - amount; }

        if (owed > assetCache.totalBorrows) owed = assetCache.totalBorrows;

        assetStorage.users[account].owed = encodeDebtAmount(owedRemaining);
        assetStorage.totalBorrows = assetCache.totalBorrows = encodeDebtAmount(assetCache.totalBorrows - owed + owedRemaining);

        updateInterestRate(assetStorage, assetCache);

        logBorrowChange(assetCache, dTokenAddress, account, prevOwed, owedRemaining);
    }

    function transferBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address from, address to, uint origAmount) internal {
        uint amount = origAmount * INTERNAL_DEBT_PRECISION;

        (uint fromOwed, uint fromOwedPrev) = updateUserBorrow(assetStorage, assetCache, from);
        (uint toOwed, uint toOwedPrev) = updateUserBorrow(assetStorage, assetCache, to);

        if (toOwed == 0) doEnterMarket(to, assetCache.underlying);

        // If amount was rounded up, transfer exact amount owed
        if (amount > fromOwed && amount - fromOwed < INTERNAL_DEBT_PRECISION * assetCache.underlyingDecimalsScaler) amount = fromOwed;

        require(fromOwed >= amount, "e/insufficient-balance");
        unchecked { fromOwed -= amount; }

        // Transfer any residual dust
        if (fromOwed < INTERNAL_DEBT_PRECISION) {
            amount += fromOwed;
            fromOwed = 0;
        }

        toOwed += amount;

        assetStorage.users[from].owed = encodeDebtAmount(fromOwed);
        assetStorage.users[to].owed = encodeDebtAmount(toOwed);

        logBorrowChange(assetCache, dTokenAddress, from, fromOwedPrev, fromOwed);
        logBorrowChange(assetCache, dTokenAddress, to, toOwedPrev, toOwed);
    }



    // Reserves

    function increaseReserves(AssetStorage storage assetStorage, AssetCache memory assetCache, uint amount) internal {
        assetStorage.reserveBalance = assetCache.reserveBalance = encodeSmallAmount(assetCache.reserveBalance + amount);
        assetStorage.totalBalances = assetCache.totalBalances = encodeAmount(assetCache.totalBalances + amount);
    }



    // Token asset transfers

    // amounts are in underlying units

    function pullTokens(AssetCache memory assetCache, address from, uint amount) internal returns (uint amountTransferred) {
        uint poolSizeBefore = assetCache.poolSize;

        Utils.safeTransferFrom(assetCache.underlying, from, address(this), amount / assetCache.underlyingDecimalsScaler);
        uint poolSizeAfter = assetCache.poolSize = decodeExternalAmount(assetCache, callBalanceOf(assetCache, address(this)));

        require(poolSizeAfter >= poolSizeBefore, "e/negative-transfer-amount");
        unchecked { amountTransferred = poolSizeAfter - poolSizeBefore; }
    }

    function pushTokens(AssetCache memory assetCache, address to, uint amount) internal returns (uint amountTransferred) {
        uint poolSizeBefore = assetCache.poolSize;

        Utils.safeTransfer(assetCache.underlying, to, amount / assetCache.underlyingDecimalsScaler);
        uint poolSizeAfter = assetCache.poolSize = decodeExternalAmount(assetCache, callBalanceOf(assetCache, address(this)));

        require(poolSizeBefore >= poolSizeAfter, "e/negative-transfer-amount");
        unchecked { amountTransferred = poolSizeBefore - poolSizeAfter; }
    }




    // Liquidity

    function getAssetPrice(address asset) internal returns (uint) {
        bytes memory result = callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.getPrice.selector, asset));
        return abi.decode(result, (uint));
    }

    function getAccountLiquidity(address account) internal returns (uint collateralValue, uint liabilityValue) {
        bytes memory result = callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.computeLiquidity.selector, account));
        (IRiskManager.LiquidityStatus memory status) = abi.decode(result, (IRiskManager.LiquidityStatus));

        collateralValue = status.collateralValue;
        liabilityValue = status.liabilityValue;
    }

    function checkLiquidity(address account) internal {
        uint8 status = accountLookup[account].deferLiquidityStatus;

        if (status == DEFERLIQUIDITY__NONE) {
            callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.requireLiquidity.selector, account));
        } else if (status == DEFERLIQUIDITY__CLEAN) {
            accountLookup[account].deferLiquidityStatus = DEFERLIQUIDITY__DIRTY;
        }
    }



    // Optional average liquidity tracking

    function computeNewAverageLiquidity(address account, uint deltaT) private returns (uint) {
        uint currDuration = deltaT >= AVERAGE_LIQUIDITY_PERIOD ? AVERAGE_LIQUIDITY_PERIOD : deltaT;
        uint prevDuration = AVERAGE_LIQUIDITY_PERIOD - currDuration;

        uint currAverageLiquidity;

        {
            (uint collateralValue, uint liabilityValue) = getAccountLiquidity(account);
            currAverageLiquidity = collateralValue > liabilityValue ? collateralValue - liabilityValue : 0;
        }

        return (accountLookup[account].averageLiquidity * prevDuration / AVERAGE_LIQUIDITY_PERIOD) +
               (currAverageLiquidity * currDuration / AVERAGE_LIQUIDITY_PERIOD);
    }

    function getUpdatedAverageLiquidity(address account) internal returns (uint) {
        uint lastAverageLiquidityUpdate = accountLookup[account].lastAverageLiquidityUpdate;
        if (lastAverageLiquidityUpdate == 0) return 0;

        uint deltaT = block.timestamp - lastAverageLiquidityUpdate;
        if (deltaT == 0) return accountLookup[account].averageLiquidity;

        return computeNewAverageLiquidity(account, deltaT);
    }

    function getUpdatedAverageLiquidityWithDelegate(address account) internal returns (uint) {
        address delegate = accountLookup[account].averageLiquidityDelegate;

        return delegate != address(0) && accountLookup[delegate].averageLiquidityDelegate == account
            ? getUpdatedAverageLiquidity(delegate)
            : getUpdatedAverageLiquidity(account);
    }

    function updateAverageLiquidity(address account) internal {
        uint lastAverageLiquidityUpdate = accountLookup[account].lastAverageLiquidityUpdate;
        if (lastAverageLiquidityUpdate == 0) return;

        uint deltaT = block.timestamp - lastAverageLiquidityUpdate;
        if (deltaT == 0) return;

        accountLookup[account].lastAverageLiquidityUpdate = uint40(block.timestamp);
        accountLookup[account].averageLiquidity = computeNewAverageLiquidity(account, deltaT);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./Storage.sol";

// This interface is used to avoid a circular dependency between BaseLogic and RiskManager

interface IRiskManager {
    struct NewMarketParameters {
        uint16 pricingType;
        uint32 pricingParameters;

        Storage.AssetConfig config;
    }

    struct LiquidityStatus {
        uint collateralValue;
        uint liabilityValue;
        uint numBorrows;
        bool borrowIsolated;
    }

    struct AssetLiquidity {
        address underlying;
        LiquidityStatus status;
    }

    function getNewMarketParameters(address underlying) external returns (NewMarketParameters memory);

    function requireLiquidity(address account) external view;
    function computeLiquidity(address account) external view returns (LiquidityStatus memory status);
    function computeAssetLiquidities(address account) external view returns (AssetLiquidity[] memory assets);

    function getPrice(address underlying) external view returns (uint twap, uint twapPeriod);
    function getPriceFull(address underlying) external view returns (uint twap, uint twapPeriod, uint currPrice);
}

// SPDX-License-Identifier: GPL-2.0-or-later

// From Uniswap3 Core

// Updated to Solidity 0.8 by Euler:
//   * Cast MAX_TICK to int256 before casting to uint
//   * Wrapped function bodies with "unchecked {}" so as to not add any extra gas costs

pragma solidity ^0.8.0;

/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = -MIN_TICK;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
      unchecked {
        uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
        require(absTick <= uint256(int(MAX_TICK)), 'T');

        uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
        if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
        if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;

        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
      }
    }

    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
    /// ever return.
    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
      unchecked {
        // second inequality must be < because the price can never reach the price at the max tick
        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
        uint256 ratio = uint256(sqrtPriceX96) << 32;

        uint256 r = ratio;
        uint256 msb = 0;

        assembly {
            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(5, gt(r, 0xFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(4, gt(r, 0xFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(3, gt(r, 0xFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(2, gt(r, 0xF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(1, gt(r, 0x3))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := gt(r, 0x1)
            msb := or(msb, f)
        }

        if (msb >= 128) r = ratio >> (msb - 127);
        else r = ratio << (127 - msb);

        int256 log_2 = (int256(msb) - 128) << 64;

        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(63, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(62, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(61, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(60, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(59, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(58, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(57, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(56, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(55, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(54, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(53, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(52, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(51, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(50, f))
        }

        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

        int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
        int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);

        tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
      }
    }
}

// SPDX-License-Identifier: MIT

// From Uniswap3 Core

// Updated to Solidity 0.8 by Euler:
//   * Rewrite unary negation of denominator, which is a uint
//   * Wrapped function bodies with "unchecked {}" so as to not add any extra gas costs

pragma solidity ^0.8.0;

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
      unchecked {
        // 512-bit multiply [prod1 prod0] = a * b
        // 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 = prod1 * 2**256 + prod0
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product
        assembly {
            let mm := mulmod(a, b, not(0))
            prod0 := mul(a, b)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }

        // Handle non-overflow cases, 256 by 256 division
        if (prod1 == 0) {
            require(denominator > 0);
            assembly {
                result := div(prod0, denominator)
            }
            return result;
        }

        // Make sure the result is less than 2**256.
        // Also prevents denominator == 0
        require(denominator > prod1);

        ///////////////////////////////////////////////
        // 512 by 256 division.
        ///////////////////////////////////////////////

        // Make division exact by subtracting the remainder from [prod1 prod0]
        // Compute remainder using mulmod
        uint256 remainder;
        assembly {
            remainder := mulmod(a, b, denominator)
        }
        // Subtract 256 bit number from 512 bit number
        assembly {
            prod1 := sub(prod1, gt(remainder, prod0))
            prod0 := sub(prod0, remainder)
        }

        // Factor powers of two out of denominator
        // Compute largest power of two divisor of denominator.
        // Always >= 1.
        uint256 twos = denominator & (~denominator + 1);

        // Divide denominator by power of two
        assembly {
            denominator := div(denominator, twos)
        }

        // Divide [prod1 prod0] by the factors of two
        assembly {
            prod0 := div(prod0, twos)
        }
        // Shift in bits from prod1 into prod0. For this we need
        // to flip `twos` such that it is 2**256 / twos.
        // If twos is zero, then it becomes one
        assembly {
            twos := add(div(sub(0, twos), twos), 1)
        }
        prod0 |= prod1 * twos;

        // Invert denominator mod 2**256
        // Now that denominator is an odd number, it has an inverse
        // modulo 2**256 such that denominator * inv = 1 mod 2**256.
        // Compute the inverse by starting with a seed that is correct
        // correct for four bits. That is, denominator * inv = 1 mod 2**4
        uint256 inv = (3 * denominator) ^ 2;
        // 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 *= 2 - denominator * inv; // inverse mod 2**8
        inv *= 2 - denominator * inv; // inverse mod 2**16
        inv *= 2 - denominator * inv; // inverse mod 2**32
        inv *= 2 - denominator * inv; // inverse mod 2**64
        inv *= 2 - denominator * inv; // inverse mod 2**128
        inv *= 2 - denominator * inv; // inverse mod 2**256

        // Because the division is now exact we can divide by multiplying
        // with the modular inverse of denominator. This will give us the
        // correct result modulo 2**256. Since the precoditions guarantee
        // that the outcome is less than 2**256, this is the final result.
        // We don't need to compute the high bits of the result and prod1
        // is no longer required.
        result = prod0 * inv;
        return result;
      }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
      unchecked {
        result = mulDiv(a, b, denominator);
        if (mulmod(a, b, denominator) > 0) {
            require(result < type(uint256).max);
            result++;
        }
      }
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./Base.sol";


abstract contract BaseModule is Base {
    // Construction

    // public accessors common to all modules

    uint immutable public moduleId;
    bytes32 immutable public moduleGitCommit;

    constructor(uint moduleId_, bytes32 moduleGitCommit_) {
        moduleId = moduleId_;
        moduleGitCommit = moduleGitCommit_;
    }


    // Accessing parameters

    function unpackTrailingParamMsgSender() internal pure returns (address msgSender) {
        assembly {
            msgSender := shr(96, calldataload(sub(calldatasize(), 40)))
        }
    }

    function unpackTrailingParams() internal pure returns (address msgSender, address proxyAddr) {
        assembly {
            msgSender := shr(96, calldataload(sub(calldatasize(), 40)))
            proxyAddr := shr(96, calldataload(sub(calldatasize(), 20)))
        }
    }


    // Emit logs via proxies

    function emitViaProxy_Transfer(address proxyAddr, address from, address to, uint value) internal FREEMEM {
        (bool success,) = proxyAddr.call(abi.encodePacked(
                               uint8(3),
                               keccak256(bytes('Transfer(address,address,uint256)')),
                               bytes32(uint(uint160(from))),
                               bytes32(uint(uint160(to))),
                               value
                          ));
        require(success, "e/log-proxy-fail");
    }

    function emitViaProxy_Approval(address proxyAddr, address owner, address spender, uint value) internal FREEMEM {
        (bool success,) = proxyAddr.call(abi.encodePacked(
                               uint8(3),
                               keccak256(bytes('Approval(address,address,uint256)')),
                               bytes32(uint(uint160(owner))),
                               bytes32(uint(uint160(spender))),
                               value
                          ));
        require(success, "e/log-proxy-fail");
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./BaseModule.sol";

abstract contract BaseIRM is BaseModule {
    constructor(uint moduleId_, bytes32 moduleGitCommit_) BaseModule(moduleId_, moduleGitCommit_) {}

    int96 internal constant MAX_ALLOWED_INTEREST_RATE = int96(int(uint(5 * 1e27) / SECONDS_PER_YEAR)); // 500% APR
    int96 internal constant MIN_ALLOWED_INTEREST_RATE = 0;

    function computeInterestRateImpl(address, uint32) internal virtual returns (int96);

    function computeInterestRate(address underlying, uint32 utilisation) external returns (int96) {
        int96 rate = computeInterestRateImpl(underlying, utilisation);

        if (rate > MAX_ALLOWED_INTEREST_RATE) rate = MAX_ALLOWED_INTEREST_RATE;
        else if (rate < MIN_ALLOWED_INTEREST_RATE) rate = MIN_ALLOWED_INTEREST_RATE;

        return rate;
    }

    function reset(address underlying, bytes calldata resetParams) external virtual {}
}

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;


interface IERC20 {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);
}

interface IERC20Permit {
    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    function nonces(address owner) external view returns (uint);
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

interface IERC3156FlashBorrower {
    function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data) external returns (bytes32);
}

interface IERC3156FlashLender {
    function maxFlashLoan(address token) external view returns (uint256);
    function flashFee(address token, uint256 amount) external view returns (uint256);
    function flashLoan(IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data) external returns (bool);
}

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./Interfaces.sol";

library Utils {
    function safeTransferFrom(address token, address from, address to, uint value) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), string(data));
    }

    function safeTransfer(address token, address to, uint value) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), string(data));
    }

    function safeApprove(address token, address to, uint value) internal {
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), string(data));
    }
}

// SPDX-License-Identifier: AGPL-3.0-or-later

// From MakerDAO DSS

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

library RPow {
    function rpow(uint x, uint n, uint base) internal pure returns (uint z) {
        assembly {
            switch x case 0 {switch n case 0 {z := base} default {z := 0}}
            default {
                switch mod(n, 2) case 0 { z := base } default { z := x }
                let half := div(base, 2)  // for rounding.
                for { n := div(n, 2) } n { n := div(n,2) } {
                    let xx := mul(x, x)
                    if iszero(eq(div(xx, x), x)) { revert(0,0) }
                    let xxRound := add(xx, half)
                    if lt(xxRound, xx) { revert(0,0) }
                    x := div(xxRound, base)
                    if mod(n,2) {
                        let zx := mul(z, x)
                        if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) }
                        let zxRound := add(zx, half)
                        if lt(zxRound, zx) { revert(0,0) }
                        z := div(zxRound, base)
                    }
                }
            }
        }
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;
//import "hardhat/console.sol"; // DEV_MODE

import "./Storage.sol";
import "./Events.sol";
import "./Proxy.sol";

abstract contract Base is Storage, Events {
    // Modules

    function _createProxy(uint proxyModuleId) internal returns (address) {
        require(proxyModuleId != 0, "e/create-proxy/invalid-module");
        require(proxyModuleId <= MAX_EXTERNAL_MODULEID, "e/create-proxy/internal-module");

        // If we've already created a proxy for a single-proxy module, just return it:

        if (proxyLookup[proxyModuleId] != address(0)) return proxyLookup[proxyModuleId];

        // Otherwise create a proxy:

        address proxyAddr = address(new Proxy());

        if (proxyModuleId <= MAX_EXTERNAL_SINGLE_PROXY_MODULEID) proxyLookup[proxyModuleId] = proxyAddr;

        trustedSenders[proxyAddr] = TrustedSenderInfo({ moduleId: uint32(proxyModuleId), moduleImpl: address(0) });

        emit ProxyCreated(proxyAddr, proxyModuleId);

        return proxyAddr;
    }

    function callInternalModule(uint moduleId, bytes memory input) internal returns (bytes memory) {
        (bool success, bytes memory result) = moduleLookup[moduleId].delegatecall(input);
        if (!success) revertBytes(result);
        return result;
    }



    // Modifiers

    modifier nonReentrant() {
        require(reentrancyLock == REENTRANCYLOCK__UNLOCKED, "e/reentrancy");

        reentrancyLock = REENTRANCYLOCK__LOCKED;
        _;
        reentrancyLock = REENTRANCYLOCK__UNLOCKED;
    }

    modifier reentrantOK() { // documentation only
        _;
    }

    // WARNING: Must be very careful with this modifier. It resets the free memory pointer
    // to the value it was when the function started. This saves gas if more memory will
    // be allocated in the future. However, if the memory will be later referenced
    // (for example because the function has returned a pointer to it) then you cannot
    // use this modifier.

    modifier FREEMEM() {
        uint origFreeMemPtr;

        assembly {
            origFreeMemPtr := mload(0x40)
        }

        _;

        /*
        assembly { // DEV_MODE: overwrite the freed memory with garbage to detect bugs
            let garbage := 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
            for { let i := origFreeMemPtr } lt(i, mload(0x40)) { i := add(i, 32) } { mstore(i, garbage) }
        }
        */

        assembly {
            mstore(0x40, origFreeMemPtr)
        }
    }



    // Error handling

    function revertBytes(bytes memory errMsg) internal pure {
        if (errMsg.length > 0) {
            assembly {
                revert(add(32, errMsg), mload(errMsg))
            }
        }

        revert("e/empty-error");
    }
}

File 12 of 15 : Storage.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./Constants.sol";

abstract contract Storage is Constants {
    // Dispatcher and upgrades

    uint reentrancyLock;

    address upgradeAdmin;
    address governorAdmin;

    mapping(uint => address) moduleLookup; // moduleId => module implementation
    mapping(uint => address) proxyLookup; // moduleId => proxy address (only for single-proxy modules)

    struct TrustedSenderInfo {
        uint32 moduleId; // 0 = un-trusted
        address moduleImpl; // only non-zero for external single-proxy modules
    }

    mapping(address => TrustedSenderInfo) trustedSenders; // sender address => moduleId (0 = un-trusted)



    // Account-level state
    // Sub-accounts are considered distinct accounts

    struct AccountStorage {
        // Packed slot: 1 + 5 + 4 + 20 = 30
        uint8 deferLiquidityStatus;
        uint40 lastAverageLiquidityUpdate;
        uint32 numMarketsEntered;
        address firstMarketEntered;

        uint averageLiquidity;
        address averageLiquidityDelegate;
    }

    mapping(address => AccountStorage) accountLookup;
    mapping(address => address[MAX_POSSIBLE_ENTERED_MARKETS]) marketsEntered;



    // Markets and assets

    struct AssetConfig {
        // Packed slot: 20 + 1 + 4 + 4 + 3 = 32
        address eTokenAddress;
        bool borrowIsolated;
        uint32 collateralFactor;
        uint32 borrowFactor;
        uint24 twapWindow;
    }

    struct UserAsset {
        uint112 balance;
        uint144 owed;

        uint interestAccumulator;
    }

    struct AssetStorage {
        // Packed slot: 5 + 1 + 4 + 12 + 4 + 2 + 4 = 32
        uint40 lastInterestAccumulatorUpdate;
        uint8 underlyingDecimals; // Not dynamic, but put here to live in same storage slot
        uint32 interestRateModel;
        int96 interestRate;
        uint32 reserveFee;
        uint16 pricingType;
        uint32 pricingParameters;

        address underlying;
        uint96 reserveBalance;

        address dTokenAddress;

        uint112 totalBalances;
        uint144 totalBorrows;

        uint interestAccumulator;

        mapping(address => UserAsset) users;

        mapping(address => mapping(address => uint)) eTokenAllowance;
        mapping(address => mapping(address => uint)) dTokenAllowance;
    }

    mapping(address => AssetConfig) internal underlyingLookup; // underlying => AssetConfig
    mapping(address => AssetStorage) internal eTokenLookup; // EToken => AssetStorage
    mapping(address => address) internal dTokenLookup; // DToken => EToken
    mapping(address => address) internal pTokenLookup; // PToken => underlying
    mapping(address => address) internal reversePTokenLookup; // underlying => PToken
}

File 13 of 15 : Events.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import "./Storage.sol";

abstract contract Events {
    event Genesis();


    event ProxyCreated(address indexed proxy, uint moduleId);
    event MarketActivated(address indexed underlying, address indexed eToken, address indexed dToken);
    event PTokenActivated(address indexed underlying, address indexed pToken);

    event EnterMarket(address indexed underlying, address indexed account);
    event ExitMarket(address indexed underlying, address indexed account);

    event Deposit(address indexed underlying, address indexed account, uint amount);
    event Withdraw(address indexed underlying, address indexed account, uint amount);
    event Borrow(address indexed underlying, address indexed account, uint amount);
    event Repay(address indexed underlying, address indexed account, uint amount);

    event Liquidation(address indexed liquidator, address indexed violator, address indexed underlying, address collateral, uint repay, uint yield, uint healthScore, uint baseDiscount, uint discount);

    event TrackAverageLiquidity(address indexed account);
    event UnTrackAverageLiquidity(address indexed account);
    event DelegateAverageLiquidity(address indexed account, address indexed delegate);

    event PTokenWrap(address indexed underlying, address indexed account, uint amount);
    event PTokenUnWrap(address indexed underlying, address indexed account, uint amount);

    event AssetStatus(address indexed underlying, uint totalBalances, uint totalBorrows, uint96 reserveBalance, uint poolSize, uint interestAccumulator, int96 interestRate, uint timestamp);


    event RequestDeposit(address indexed account, uint amount);
    event RequestWithdraw(address indexed account, uint amount);
    event RequestMint(address indexed account, uint amount);
    event RequestBurn(address indexed account, uint amount);
    event RequestTransferEToken(address indexed from, address indexed to, uint amount);

    event RequestBorrow(address indexed account, uint amount);
    event RequestRepay(address indexed account, uint amount);
    event RequestTransferDToken(address indexed from, address indexed to, uint amount);

    event RequestLiquidate(address indexed liquidator, address indexed violator, address indexed underlying, address collateral, uint repay, uint minYield);


    event InstallerSetUpgradeAdmin(address indexed newUpgradeAdmin);
    event InstallerSetGovernorAdmin(address indexed newGovernorAdmin);
    event InstallerInstallModule(uint indexed moduleId, address indexed moduleImpl, bytes32 moduleGitCommit);


    event GovSetAssetConfig(address indexed underlying, Storage.AssetConfig newConfig);
    event GovSetIRM(address indexed underlying, uint interestRateModel, bytes resetParams);
    event GovSetPricingConfig(address indexed underlying, uint16 newPricingType, uint32 newPricingParameter);
    event GovSetReserveFee(address indexed underlying, uint32 newReserveFee);
    event GovConvertReserves(address indexed underlying, address indexed recipient, uint amount);

    event RequestSwap(address indexed accountIn, address indexed accountOut, address indexed underlyingIn, address underlyingOut, uint amount, uint swapType);
}

File 14 of 15 : Proxy.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

contract Proxy {
    address immutable creator;

    constructor() {
        creator = msg.sender;
    }

    // External interface

    fallback() external {
        address creator_ = creator;

        if (msg.sender == creator_) {
            assembly {
                mstore(0, 0)
                calldatacopy(31, 0, calldatasize())

                switch mload(0) // numTopics
                    case 0 { log0(32,  sub(calldatasize(), 1)) }
                    case 1 { log1(64,  sub(calldatasize(), 33),  mload(32)) }
                    case 2 { log2(96,  sub(calldatasize(), 65),  mload(32), mload(64)) }
                    case 3 { log3(128, sub(calldatasize(), 97),  mload(32), mload(64), mload(96)) }
                    case 4 { log4(160, sub(calldatasize(), 129), mload(32), mload(64), mload(96), mload(128)) }
                    default { revert(0, 0) }

                return(0, 0)
            }
        } else {
            assembly {
                mstore(0, 0xe9c4a3ac00000000000000000000000000000000000000000000000000000000) // dispatch() selector
                calldatacopy(4, 0, calldatasize())
                mstore(add(4, calldatasize()), shl(96, caller()))

                let result := call(gas(), creator_, 0, 0, add(24, calldatasize()), 0, 0)
                returndatacopy(0, 0, returndatasize())

                switch result
                    case 0 { revert(0, returndatasize()) }
                    default { return(0, returndatasize()) }
            }
        }
    }
}

File 15 of 15 : Constants.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

abstract contract Constants {
    // Universal

    uint internal constant SECONDS_PER_YEAR = 365.2425 * 86400; // Gregorian calendar


    // Protocol parameters

    uint internal constant MAX_SANE_AMOUNT = type(uint112).max;
    uint internal constant MAX_SANE_SMALL_AMOUNT = type(uint96).max;
    uint internal constant MAX_SANE_DEBT_AMOUNT = type(uint144).max;
    uint internal constant INTERNAL_DEBT_PRECISION = 1e9;
    uint internal constant MAX_ENTERED_MARKETS = 10; // per sub-account
    uint internal constant MAX_POSSIBLE_ENTERED_MARKETS = 2**32; // limited by size of AccountStorage.numMarketsEntered
    uint internal constant CONFIG_FACTOR_SCALE = 4_000_000_000; // must fit into a uint32
    uint internal constant RESERVE_FEE_SCALE = 4_000_000_000; // must fit into a uint32
    uint32 internal constant DEFAULT_RESERVE_FEE = uint32(0.23 * 4_000_000_000);
    uint internal constant INITIAL_INTEREST_ACCUMULATOR = 1e27;
    uint internal constant AVERAGE_LIQUIDITY_PERIOD = 24 * 60 * 60;
    uint16 internal constant MIN_UNISWAP3_OBSERVATION_CARDINALITY = 144;
    uint24 internal constant DEFAULT_TWAP_WINDOW_SECONDS = 30 * 60;
    uint32 internal constant DEFAULT_BORROW_FACTOR = uint32(0.28 * 4_000_000_000);


    // Implementation internals

    uint internal constant REENTRANCYLOCK__UNLOCKED = 1;
    uint internal constant REENTRANCYLOCK__LOCKED = 2;

    uint8 internal constant DEFERLIQUIDITY__NONE = 0;
    uint8 internal constant DEFERLIQUIDITY__CLEAN = 1;
    uint8 internal constant DEFERLIQUIDITY__DIRTY = 2;


    // Pricing types

    uint16 internal constant PRICINGTYPE__PEGGED = 1;
    uint16 internal constant PRICINGTYPE__UNISWAP3_TWAP = 2;
    uint16 internal constant PRICINGTYPE__FORWARDED = 3;


    // Modules

    // Public single-proxy modules
    uint internal constant MODULEID__INSTALLER = 1;
    uint internal constant MODULEID__MARKETS = 2;
    uint internal constant MODULEID__LIQUIDATION = 3;
    uint internal constant MODULEID__GOVERNANCE = 4;
    uint internal constant MODULEID__EXEC = 5;
    uint internal constant MODULEID__SWAP = 6;

    uint internal constant MAX_EXTERNAL_SINGLE_PROXY_MODULEID = 499_999;

    // Public multi-proxy modules
    uint internal constant MODULEID__ETOKEN = 500_000;
    uint internal constant MODULEID__DTOKEN = 500_001;

    uint internal constant MAX_EXTERNAL_MODULEID = 999_999;

    // Internal modules
    uint internal constant MODULEID__RISK_MANAGER = 1_000_000;

    // Interest rate models
    //   Default for new markets
    uint internal constant MODULEID__IRM_DEFAULT = 2_000_000;
    //   Testing-only
    uint internal constant MODULEID__IRM_ZERO = 2_000_001;
    uint internal constant MODULEID__IRM_FIXED = 2_000_002;
    uint internal constant MODULEID__IRM_LINEAR = 2_000_100;
    //   Classes
    uint internal constant MODULEID__IRM_CLASS__STABLE = 2_000_500;
    uint internal constant MODULEID__IRM_CLASS__MAJOR = 2_000_501;
    uint internal constant MODULEID__IRM_CLASS__MIDCAP = 2_000_502;

    // Swap types
    uint internal constant SWAP_TYPE__UNI_EXACT_INPUT_SINGLE = 1;
    uint internal constant SWAP_TYPE__UNI_EXACT_INPUT = 2;
    uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_SINGLE = 3;
    uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT = 4;
    uint internal constant SWAP_TYPE__1INCH = 5;

    uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_SINGLE_REPAY = 6;
    uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_REPAY = 7;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"bytes32","name":"moduleGitCommit_","type":"bytes32"},{"components":[{"internalType":"address","name":"referenceAsset","type":"address"},{"internalType":"address","name":"uniswapFactory","type":"address"},{"internalType":"bytes32","name":"uniswapPoolInitCodeHash","type":"bytes32"}],"internalType":"struct RiskManager.RiskManagerSettings","name":"settings","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalBalances","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalBorrows","type":"uint256"},{"indexed":false,"internalType":"uint96","name":"reserveBalance","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"poolSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAccumulator","type":"uint256"},{"indexed":false,"internalType":"int96","name":"interestRate","type":"int96"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AssetStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"}],"name":"DelegateAverageLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"EnterMarket","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"ExitMarket","type":"event"},{"anonymous":false,"inputs":[],"name":"Genesis","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"GovConvertReserves","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"components":[{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"bool","name":"borrowIsolated","type":"bool"},{"internalType":"uint32","name":"collateralFactor","type":"uint32"},{"internalType":"uint32","name":"borrowFactor","type":"uint32"},{"internalType":"uint24","name":"twapWindow","type":"uint24"}],"indexed":false,"internalType":"struct Storage.AssetConfig","name":"newConfig","type":"tuple"}],"name":"GovSetAssetConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestRateModel","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"resetParams","type":"bytes"}],"name":"GovSetIRM","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint16","name":"newPricingType","type":"uint16"},{"indexed":false,"internalType":"uint32","name":"newPricingParameter","type":"uint32"}],"name":"GovSetPricingConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"uint32","name":"newReserveFee","type":"uint32"}],"name":"GovSetReserveFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"moduleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"moduleImpl","type":"address"},{"indexed":false,"internalType":"bytes32","name":"moduleGitCommit","type":"bytes32"}],"name":"InstallerInstallModule","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newGovernorAdmin","type":"address"}],"name":"InstallerSetGovernorAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newUpgradeAdmin","type":"address"}],"name":"InstallerSetUpgradeAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"violator","type":"address"},{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"repay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"yield","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"healthScore","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseDiscount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"discount","type":"uint256"}],"name":"Liquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"eToken","type":"address"},{"indexed":true,"internalType":"address","name":"dToken","type":"address"}],"name":"MarketActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"pToken","type":"address"}],"name":"PTokenActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PTokenUnWrap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PTokenWrap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"uint256","name":"moduleId","type":"uint256"}],"name":"ProxyCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidator","type":"address"},{"indexed":true,"internalType":"address","name":"violator","type":"address"},{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"uint256","name":"repay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minYield","type":"uint256"}],"name":"RequestLiquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestRepay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"accountIn","type":"address"},{"indexed":true,"internalType":"address","name":"accountOut","type":"address"},{"indexed":true,"internalType":"address","name":"underlyingIn","type":"address"},{"indexed":false,"internalType":"address","name":"underlyingOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"swapType","type":"uint256"}],"name":"RequestSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestTransferDToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestTransferEToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"TrackAverageLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"UnTrackAverageLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"underlying","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"computeAssetLiquidities","outputs":[{"components":[{"internalType":"address","name":"underlying","type":"address"},{"components":[{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"liabilityValue","type":"uint256"},{"internalType":"uint256","name":"numBorrows","type":"uint256"},{"internalType":"bool","name":"borrowIsolated","type":"bool"}],"internalType":"struct IRiskManager.LiquidityStatus","name":"status","type":"tuple"}],"internalType":"struct IRiskManager.AssetLiquidity[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"computeLiquidity","outputs":[{"components":[{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"liabilityValue","type":"uint256"},{"internalType":"uint256","name":"numBorrows","type":"uint256"},{"internalType":"bool","name":"borrowIsolated","type":"bool"}],"internalType":"struct IRiskManager.LiquidityStatus","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getNewMarketParameters","outputs":[{"components":[{"internalType":"uint16","name":"pricingType","type":"uint16"},{"internalType":"uint32","name":"pricingParameters","type":"uint32"},{"components":[{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"bool","name":"borrowIsolated","type":"bool"},{"internalType":"uint32","name":"collateralFactor","type":"uint32"},{"internalType":"uint32","name":"borrowFactor","type":"uint32"},{"internalType":"uint24","name":"twapWindow","type":"uint24"}],"internalType":"struct Storage.AssetConfig","name":"config","type":"tuple"}],"internalType":"struct IRiskManager.NewMarketParameters","name":"p","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"twap","type":"uint256"},{"internalType":"uint256","name":"twapPeriod","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"underlying","type":"address"}],"name":"getPriceFull","outputs":[{"internalType":"uint256","name":"twap","type":"uint256"},{"internalType":"uint256","name":"twapPeriod","type":"uint256"},{"internalType":"uint256","name":"currPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"underlying","type":"address"},{"internalType":"uint112","name":"totalBalances","type":"uint112"},{"internalType":"uint144","name":"totalBorrows","type":"uint144"},{"internalType":"uint96","name":"reserveBalance","type":"uint96"},{"internalType":"uint256","name":"interestAccumulator","type":"uint256"},{"internalType":"uint40","name":"lastInterestAccumulatorUpdate","type":"uint40"},{"internalType":"uint8","name":"underlyingDecimals","type":"uint8"},{"internalType":"uint32","name":"interestRateModel","type":"uint32"},{"internalType":"int96","name":"interestRate","type":"int96"},{"internalType":"uint32","name":"reserveFee","type":"uint32"},{"internalType":"uint16","name":"pricingType","type":"uint16"},{"internalType":"uint32","name":"pricingParameters","type":"uint32"},{"internalType":"uint256","name":"poolSize","type":"uint256"},{"internalType":"uint256","name":"underlyingDecimalsScaler","type":"uint256"},{"internalType":"uint256","name":"maxExternalAmount","type":"uint256"}],"internalType":"struct BaseLogic.AssetCache","name":"assetCache","type":"tuple"},{"components":[{"internalType":"address","name":"eTokenAddress","type":"address"},{"internalType":"bool","name":"borrowIsolated","type":"bool"},{"internalType":"uint32","name":"collateralFactor","type":"uint32"},{"internalType":"uint32","name":"borrowFactor","type":"uint32"},{"internalType":"uint24","name":"twapWindow","type":"uint24"}],"internalType":"struct Storage.AssetConfig","name":"config","type":"tuple"}],"name":"getPriceInternal","outputs":[{"internalType":"uint256","name":"twap","type":"uint256"},{"internalType":"uint256","name":"twapPeriod","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moduleGitCommit","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"moduleId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"requireLiquidity","outputs":[],"stateMutability":"view","type":"function"}]

6101206040523480156200001257600080fd5b5060405162003c4b38038062003c4b833981016040819052620000359162000086565b620f424060805260a09190915280516001600160a01b0390811660c05260208201511660e05260400151610100526200011d565b80516001600160a01b03811681146200008157600080fd5b919050565b60008082840360808112156200009b57600080fd5b835192506060601f1982011215620000b257600080fd5b50604051606081016001600160401b0381118282101715620000e457634e487b7160e01b600052604160045260246000fd5b604052620000f56020850162000069565b8152620001056040850162000069565b60208201526060939093015160408401525092909150565b60805160a05160c05160e05161010051613ace6200017d600039600061166d0152600081816104990152611632015260008181610372015281816104d6015281816115b9015261191a0152600060fe015260006101f10152613ace6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80639693fa6b11610076578063c39b543a1161005b578063c39b543a14610213578063ebd7ba1914610228578063f70c2fde1461024857600080fd5b80639693fa6b146101be578063a1308f27146101ec57600080fd5b806337fe974a146100a857806341976e09146100d157806369a92ea3146100f95780638eddcd921461012e575b600080fd5b6100bb6100b6366004612f86565b61025b565b6040516100c89190612fa3565b60405180910390f35b6100e46100df366004612f86565b6102a0565b604080519283526020830191909152016100c8565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016100c8565b61014161013c366004612f86565b6102fa565b60408051825161ffff16815260208084015163ffffffff9081168284015293830151805173ffffffffffffffffffffffffffffffffffffffff16838501529081015115156060808401919091529281015184166080808401919091529281015190931660a082015291015162ffffff1660c082015260e0016100c8565b6101d16101cc366004612f86565b6109db565b604080519384526020840192909252908201526060016100c8565b6101207f000000000000000000000000000000000000000000000000000000000000000081565b610226610221366004612f86565b610bab565b005b61023b610236366004612f86565b610ca6565b6040516100c89190612fd0565b6100e461025636600461328d565b610e20565b61028860405180608001604052806000815260200160008152602001600081526020016000151581525090565b61029a8261029584610eae565b611047565b92915050565b60008060006102ae84611382565b805173ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604081209192506102e18683611529565b90506102ed8184610e20565b9097909650945050505050565b61033f604080516060808201835260008083526020808401829052845160a0810186528281529081018290528085018290529182018190526080820152909182015290565b60408181018051600160209091015280516000920191909152805163ffffffff6060909101525162ffffff6080909101527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811690831614156103c2576001815260006020820152919050565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600b6020526040902054161561045c57600381526000602080830182905273ffffffffffffffffffffffffffffffffffffffff8085168352600b825260408084205490911683526008909152908190205481830151750100000000000000000000000000000000000000000090910463ffffffff16910152919050565b60408051608081018252610bb8815261271060208201526101f49181019190915260646060820152600090819081805b60048110156106c05760007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631698ee82897f0000000000000000000000000000000000000000000000000000000000000000878660048110610507576105076133bc565b60200201516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ac91906133eb565b905073ffffffffffffffffffffffffffffffffffffffff81166105cf57506106b0565b60008173ffffffffffffffffffffffffffffffffffffffff16631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190613408565b905073ffffffffffffffffffffffffffffffffffffffff871615806106885750836fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16115b156106ad578196508483600481106106a2576106a26133bc565b602002015195508093505b50505b6106b981613469565b905061048c565b50505073ffffffffffffffffffffffffffffffffffffffff8216610745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6e6f2d756e69737761702d706f6f6c2d617661696c00000000000000000060448201526064015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1661076685836115b4565b73ffffffffffffffffffffffffffffffffffffffff16146107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6261642d756e69737761702d706f6f6c2d61646472000000000000000000604482015260640161073c565b6002835262ffffff811660208401526040517f32148f670000000000000000000000000000000000000000000000000000000081526090600482015273ffffffffffffffffffffffffffffffffffffffff8316906332148f6790602401600060405180830381600087803b15801561085a57600080fd5b505af192505050801561086b575060015b6109d3576108776134a2565b806308c379a01415610996575061088c6134be565b806108975750610998565b805160208201207fe01ebc6b01bbf458b3d355b6e649efe64599751670c5d19175619893ecf975291415610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f652f7269736b2f756e69737761702d706f6f6c2d6e6f742d696e697465640000604482015260640161073c565b80604051602001610938919061358b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261073c916004016135d0565b505b3d8080156109c2576040519150601f19603f3d011682016040523d82523d6000602084013e6109c7565b606091505b506109d18161173b565b505b50505b919050565b6000806000806109ea85611382565b805173ffffffffffffffffffffffffffffffffffffffff166000908152600960205260408120919250610a1d8783611529565b9050610a298184610e20565b909650945060008080610a3c84876117ac565b509194509250905061ffff821660011415610a6157670de0b6b3a76400009650610b9e565b61ffff821660021480610a78575061ffff82166003145b15610b3c576000610a898487611529565b90506000610a9785846115b4565b905060008173ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015610ae6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0a9190613621565b5050505050509050610b32838273ffffffffffffffffffffffffffffffffffffffff16611916565b9950505050610b9e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f756e6b6e6f776e2d70726963696e672d7479706500000000000000000000604482015260640161073c565b5050505050509193909250565b6000610bb68261025b565b905080606001511580610bcd575080604001516001145b610c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f626f72726f772d69736f6c6174696f6e2d76696f6c6174696f6e00000000604482015260640161073c565b602081015181511015610ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f636f6c6c61746572616c2d76696f6c6174696f6e00000000000000000000604482015260640161073c565b5050565b60606000610cb383610eae565b90506000815167ffffffffffffffff811115610cd157610cd1613062565b604051908082528060200260200182016040528015610d0a57816020015b610cf7612f01565b815260200190600190039081610cef5790505b50604080516001808252818301909252919250600091906020808301908036833701905050905060005b8351811015610e1657838181518110610d4f57610d4f6133bc565b602002602001015182600081518110610d6a57610d6a6133bc565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250838281518110610db557610db56133bc565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff9091169052610de48683611047565b838281518110610df657610df66133bc565b60200260200101516020018190525080610e0f90613469565b9050610d34565b5090949350505050565b604051600090819081808080610e3689896117ac565b9350935093509350600161ffff168361ffff161415610e6757670de0b6b3a764000096508062ffffff169550610e9e565b61ffff831660021415610b3c576000610e8085846115b4565b9050610e928a828462ffffff16611a71565b9098509650610e9e9050565b5050505080604052509250929050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526006602052604081205460609263ffffffff6601000000000000830416926a010000000000000000000090920416908267ffffffffffffffff811115610f1357610f13613062565b604051908082528060200260200182016040528015610f3c578160200160208202803683370190505b50905063ffffffff8316610f5257949350505050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600760205260408120825190918491849190610f8c57610f8c6133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260015b8463ffffffff1681101561103c5781816401000000008110610fd857610fd86133bc565b0154835173ffffffffffffffffffffffffffffffffffffffff90911690849083908110611007576110076133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261103581613469565b9050610fb4565b509095945050505050565b61107460405180608001604052806000815260200160008152602001600081526020016000151581525090565b6000808252602080830182905260408084018390526060808501849052815160a08101835284815292830184905290820183905281018290526080810191909152604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810182905260005b855181101561137857600086828151811061114d5761114d6133bc565b6020026020010151905060008061116383611382565b805173ffffffffffffffffffffffffffffffffffffffff9081166000908152600960209081526040808320938f1683526005840190915290205491985096506dffffffffffffffffffffffffffff8116906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff1681158015906111f25750604089015163ffffffff1615155b1561127f5761120285898961208d565b5061120d878a610e20565b5060019450925060006112208884612500565b9050670de0b6b3a764000061123585836136c4565b61123f9190613730565b905063ee6b28008a6040015163ffffffff168261125c91906136c4565b6112669190613730565b9050808b60000181815161127a9190613744565b905250505b801561136257836112a85761129585898961208d565b506112a0878a610e20565b506001945092505b60408a018051906112b882613469565b9052506020890151156112cd57600160608b01525b60006112da89898f612533565b9050670de0b6b3a76400006112ef85836136c4565b6112f99190613730565b9050896060015163ffffffff16600014156113265771ffffffffffffffffffffffffffffffffffff611349565b60608a015163ffffffff1661133f63ee6b2800836136c4565b6113499190613730565b9050808b60200181815161135d9190613744565b905250505b50505050508061137190613469565b9050611130565b5050505092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff828116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff166080820152906114eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640161073c565b606081015163ffffffff9081161415611509576342c1d80060608201525b608081015162ffffff908116141561029a57610708608082015292915050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c08101919091526115ad83838361208d565b5092915050565b6000827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff80821690831611156115fb57905b6040805173ffffffffffffffffffffffffffffffffffffffff808516602083015283169181019190915262ffffff851660608201527f000000000000000000000000000000000000000000000000000000000000000090608001604051602081830303815290604052805190602001207f00000000000000000000000000000000000000000000000000000000000000006040516020016116fc939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012095945050505050565b80511561174a57805181602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f652f656d7074792d6572726f7200000000000000000000000000000000000000604482015260640161073c565b600080600080600361ffff1686610140015161ffff1614156118f057855173ffffffffffffffffffffffffffffffffffffffff9081166000908152600b602052604081205490911694506117ff85611382565b6080810151815173ffffffffffffffffffffffffffffffffffffffff16600090815260096020526040902080547a010000000000000000000000000000000000000000000000000000810461ffff1697507c0100000000000000000000000000000000000000000000000000000000900463ffffffff16955090935090915060038514156118e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f652f6e65737465642d70726963652d666f7277617264696e6700000000000000604482015260640161073c565b505061190d565b505083516101408501516101608601516080860151929450909250905b92959194509250565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1610156119bc576101a08301516119ab83806119a6670de0b6b3a76400007801000000000000000000000000000000000000000000000000613730565b6125b5565b6119b59190613730565b9050611a36565b6119fd8283856101a00151670de0b6b3a76400006119da91906136c4565b6119a6907801000000000000000000000000000000000000000000000000613730565b905080611a1a57506ec097ce7bc90715b34b9f100000000061029a565b611a33816ec097ce7bc90715b34b9f1000000000613730565b90505b6ec097ce7bc90715b34b9f1000000000811115611a6357506ec097ce7bc90715b34b9f100000000061029a565b8061029a5750600192915050565b6040805160028082526060820183526000928392839290916020830190803683370190505090508381600081518110611aac57611aac6133bc565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110611adb57611adb6133bc565b602002602001019063ffffffff16908163ffffffff16815250506000808673ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b84604051602401611b28919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611bb1919061379a565b600060405180830381855afa9150503d8060008114611bec576040519150601f19603f3d011682016040523d82523d6000602084013e611bf1565b606091505b509150915081611fe85760405160206024820152600360448201527f4f4c4400000000000000000000000000000000000000000000000000000000006064820152608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f08c379a000000000000000000000000000000000000000000000000000000000178152915190912082519183019190912014611cc857611cc88161173b565b6000808873ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3a9190613621565b5050509350935050506000808a73ffffffffffffffffffffffffffffffffffffffff1663252c09d784866001611d7091906137b6565b611d7a91906137dc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261ffff9091166004820152602401608060405180830381865afa158015611dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df5919061380f565b93505050915080611e96576040517f252c09d70000000000000000000000000000000000000000000000000000000081526000600482015273ffffffffffffffffffffffffffffffffffffffff8c169063252c09d790602401608060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061380f565b5091935050505b611ea663ffffffff83164261386a565b99508987600081518110611ebc57611ebc6133bc565b602002602001019063ffffffff16908163ffffffff16815250508a73ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b88604051602401611f06919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f8f919061379a565b600060405180830381855afa9150503d8060008114611fca576040519150601f19603f3d011682016040523d82523d6000602084013e611fcf565b606091505b50909650945085611fe357611fe38561173b565b505050505b600081806020019051810190611ffe9190613881565b905060008782600081518110612016576120166133bc565b602002602001015183600181518110612031576120316133bc565b6020026020010151612043919061392f565b61204d9190613997565b9050600061205a82612682565b905061207c8b8273ffffffffffffffffffffffffffffffffffffffff16611916565b9b989a509798505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152815464ffffffffff811660a083015265010000000000810460ff90811660c084018190526601000000000000830463ffffffff90811660e08601526a01000000000000000000008404600b0b610100860152760100000000000000000000000000000000000000000000840481166101208601527a010000000000000000000000000000000000000000000000000000840461ffff166101408601527c010000000000000000000000000000000000000000000000000000000090930490921661016084015260018401547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16606084015260038401546dffffffffffffffffffffffffffff80821660208601526e01000000000000000000000000000090910471ffffffffffffffffffffffffffffffffffff166040850152600485015460808501526012839003909116600a0a6101a08401819052600092918161221257612212613701565b046101c084015260006122258430612a16565b9050836101c001518111612246576101a0840151810261018085015261224f565b60006101808501525b8360a0015164ffffffffff1642146124f7576001925060008460a0015164ffffffffff164261227e919061386a565b905060006b033b2e3c9fd0803ce800000086608001516122ca886101000151600b0b6b033b2e3c9fd0803ce80000006122b79190613a0b565b856b033b2e3c9fd0803ce8000000612b33565b6122d491906136c4565b6122de9190613730565b90506000866080015182886040015171ffffffffffffffffffffffffffffffffffff1661230b91906136c4565b6123159190613730565b606088015160208901519192506bffffffffffffffffffffffff16906dffffffffffffffffffffffffffff166000612355633b9aca0063ee6b28006136c4565b6101208b015163ffffffff90811614612373578a6101200151612379565b6336d616005b63ffffffff168b6040015171ffffffffffffffffffffffffffffffffffff16866123a3919061386a565b6123ad91906136c4565b6123b79190613730565b9050801561242f5760006123cf633b9aca0086613730565b8b61018001516123df9190613744565b90506123eb828261386a565b6123f584836136c4565b6123ff9190613730565b92508a602001516dffffffffffffffffffffffffffff1683612421919061386a565b61242b9085613744565b9350505b6dffffffffffffffffffffffffffff821180159061245f575071ffffffffffffffffffffffffffffffffffff8411155b156124f05761246d84612bf0565b71ffffffffffffffffffffffffffffffffffff1660408b015260808a0185905264ffffffffff421660a08b015260208a01516dffffffffffffffffffffffffffff1682146124f0576124be83612c98565b6bffffffffffffffffffffffff1660608b01526124da82612d36565b6dffffffffffffffffffffffffffff1660208b01525b5050505050505b50509392505050565b60008061250c84612db0565b9050670de0b6b3a764000061252182856136c4565b61252b9190613730565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600584016020526040812054633b9aca00906125a190859061259c908890839088906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff16612e47565b612ea3565b6125ab9190613730565b90505b9392505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050806000141561260d576000841161260257600080fd5b5082900490506125ae565b80841161261957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008060008360020b12612699578260020b6126a1565b8260020b6000035b9050620d89e8811115612710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f5400000000000000000000000000000000000000000000000000000000000000604482015260640161073c565b60006001821661273157700100000000000000000000000000000000612743565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612777576ffff97272373d413259a46990580e213a0260801c5b6004821615612796576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60088216156127b5576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60108216156127d4576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156127f3576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612812576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612831576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612851576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612871576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612891576ff3392b0822b70005940c7a398e4b70f30260801c5b6108008216156128b1576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6110008216156128d1576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156128f1576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612911576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612931576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612952576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615612972576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615612991576d2216e584f5fa1ea926041bedfe980260801c5b620800008216156129ae576b048a170391f7dc42444e8fa20260801c5b60008460020b13156129ed57807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff816129e9576129e9613701565b0490505b640100000000810615612a01576001612a04565b60005b60ff16602082901c0192505050919050565b60408051835173ffffffffffffffffffffffffffffffffffffffff848116602480850191909152845180850390910181526044840185526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790529351600094859384931691614e2091612aad9161379a565b6000604051808303818686fa925050503d8060008114612ae9576040519150601f19603f3d011682016040523d82523d6000602084013e612aee565b606091505b5091509150811580612b01575060208151105b15612b1157600093505050612b2a565b80806020019051810190612b259190613a7f565b935050505b60405292915050565b6000838015612bd357600184168015612b4e57859250612b52565b8392505b50600283046002850494505b8415612bcd578586028687820414612b7557600080fd5b81810181811015612b8557600080fd5b8590049650506001851615612bc2578583028387820414158715151615612bab57600080fd5b81810181811015612bbb57600080fd5b8590049350505b600285049450612b5e565b50612be8565b838015612be357600092506124f7565b839250505b509392505050565b600071ffffffffffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f652f646562742d616d6f756e742d746f6f2d6c617267652d746f2d656e636f6460448201527f6500000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b5090565b60006bffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f652f736d616c6c2d616d6f756e742d746f6f2d6c617267652d746f2d656e636f60448201527f6465000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b60006dffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f616d6f756e742d746f6f2d6c617267652d746f2d656e636f646500000000604482015260640161073c565b600081602001516dffffffffffffffffffffffffffff1660001415612dde5750670de0b6b3a7640000919050565b81602001516dffffffffffffffffffffffffffff16633b9aca00836040015171ffffffffffffffffffffffffffffffffffff16612e1b9190613730565b836101800151612e2b9190613744565b612e3d90670de0b6b3a76400006136c4565b61029a9190613730565b600081612e565750600061252b565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005860160205260409020600101546080850151612e9090846136c4565b612e9a9190613730565b95945050505050565b600081612eb25750600061029a565b6101a0830151633b9aca000280807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8582010181612ef257612ef2613701565b0402949350505050565b905290565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001612efc60405180608001604052806000815260200160008152602001600081526020016000151581525090565b73ffffffffffffffffffffffffffffffffffffffff81168114612f7857600080fd5b50565b80356109d681612f56565b600060208284031215612f9857600080fd5b81356125ae81612f56565b8151815260208083015190820152604080830151908201526060808301511515908201526080810161029a565b6020808252825182820181905260009190848201906040850190845b81811015613056578351805173ffffffffffffffffffffffffffffffffffffffff168452850151613042868501828051825260208101516020830152604081015160408301526060810151151560608301525050565b509284019260a09290920191600101612fec565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156130d5576130d5613062565b6040525050565b6040516101e0810167ffffffffffffffff8111828210171561310057613100613062565b60405290565b80356dffffffffffffffffffffffffffff811681146109d657600080fd5b803571ffffffffffffffffffffffffffffffffffff811681146109d657600080fd5b80356bffffffffffffffffffffffff811681146109d657600080fd5b803564ffffffffff811681146109d657600080fd5b60ff81168114612f7857600080fd5b80356109d681613177565b63ffffffff81168114612f7857600080fd5b80356109d681613191565b8035600b81900b81146109d657600080fd5b61ffff81168114612f7857600080fd5b80356109d6816131c0565b8015158114612f7857600080fd5b600060a082840312156131fb57600080fd5b60405160a0810181811067ffffffffffffffff8211171561321e5761321e613062565b604052905080823561322f81612f56565b8152602083013561323f816131db565b6020820152604083013561325281613191565b6040820152606083013561326581613191565b6060820152608083013562ffffff8116811461328057600080fd5b6080919091015292915050565b6000808284036102808112156132a257600080fd5b6101e0808212156132b257600080fd5b6132ba6130dc565b91506132c585612f7b565b82526132d360208601613106565b60208301526132e460408601613124565b60408301526132f560608601613146565b60608301526080850135608083015261331060a08601613162565b60a083015261332160c08601613186565b60c083015261333260e086016131a3565b60e08301526101006133458187016131ae565b908301526101206133578682016131a3565b908301526101406133698682016131d0565b9083015261016061337b8682016131a3565b9083015261018085810135908301526101a080860135908301526101c0808601359083015290925082906133b1868287016131e9565b925050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156133fd57600080fd5b81516125ae81612f56565b60006020828403121561341a57600080fd5b81516fffffffffffffffffffffffffffffffff811681146125ae57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561349b5761349b61343a565b5060010190565b600060033d11156134bb5760046000803e5060005160e01c5b90565b600060443d10156134cc5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff816024840111818411171561351a57505050505090565b82850191508151818111156135325750505050505090565b843d870101602082850101111561354c5750505050505090565b61103c60208286010187613091565b60005b8381101561357657818101518382015260200161355e565b83811115613585576000848401525b50505050565b7f652f7269736b2f756e69737761702f00000000000000000000000000000000008152600082516135c381600f85016020870161355b565b91909101600f0192915050565b60208152600082518060208401526135ef81604085016020870161355b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600080600080600080600060e0888a03121561363c57600080fd5b875161364781612f56565b8097505060208801518060020b811461365f57600080fd5b6040890151909650613670816131c0565b6060890151909550613681816131c0565b6080890151909450613692816131c0565b60a08901519093506136a381613177565b60c08901519092506136b4816131db565b8091505092959891949750929550565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156136fc576136fc61343a565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261373f5761373f613701565b500490565b600082198211156137575761375761343a565b500190565b6020808252825182820181905260009190848201906040850190845b8181101561305657835163ffffffff1683529284019291840191600101613778565b600082516137ac81846020870161355b565b9190910192915050565b600061ffff8083168185168083038211156137d3576137d361343a565b01949350505050565b600061ffff808416806137f1576137f1613701565b92169190910692915050565b8051600681900b81146109d657600080fd5b6000806000806080858703121561382557600080fd5b845161383081613191565b935061383e602086016137fd565b9250604085015161384e81612f56565b606086015190925061385f816131db565b939692955090935050565b60008282101561387c5761387c61343a565b500390565b6000602080838503121561389457600080fd5b825167ffffffffffffffff808211156138ac57600080fd5b818501915085601f8301126138c057600080fd5b8151818111156138d2576138d2613062565b8060051b91506040516138e785840182613091565b8181529183018401918481018884111561390057600080fd5b938501935b8385101561392357613916856137fd565b8152938501938501613905565b50979650505050505050565b60008160060b8360060b60008112817fffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000018312811516156139725761397261343a565b81667fffffffffffff01831381161561398d5761398d61343a565b5090039392505050565b60008160060b8360060b806139ae576139ae613701565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000083141615613a0257613a0261343a565b90059392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615613a4557613a4561343a565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615613a7957613a7961343a565b50500190565b600060208284031215613a9157600080fd5b505191905056fea264697066735822122049da3334e4e4abd0c5d85f3a1e678e0ca391f95c3fb85f584b53ad8f03a4f2cb64736f6c634300080a003300000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80639693fa6b11610076578063c39b543a1161005b578063c39b543a14610213578063ebd7ba1914610228578063f70c2fde1461024857600080fd5b80639693fa6b146101be578063a1308f27146101ec57600080fd5b806337fe974a146100a857806341976e09146100d157806369a92ea3146100f95780638eddcd921461012e575b600080fd5b6100bb6100b6366004612f86565b61025b565b6040516100c89190612fa3565b60405180910390f35b6100e46100df366004612f86565b6102a0565b604080519283526020830191909152016100c8565b6101207f00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a1381565b6040519081526020016100c8565b61014161013c366004612f86565b6102fa565b60408051825161ffff16815260208084015163ffffffff9081168284015293830151805173ffffffffffffffffffffffffffffffffffffffff16838501529081015115156060808401919091529281015184166080808401919091529281015190931660a082015291015162ffffff1660c082015260e0016100c8565b6101d16101cc366004612f86565b6109db565b604080519384526020840192909252908201526060016100c8565b6101207f00000000000000000000000000000000000000000000000000000000000f424081565b610226610221366004612f86565b610bab565b005b61023b610236366004612f86565b610ca6565b6040516100c89190612fd0565b6100e461025636600461328d565b610e20565b61028860405180608001604052806000815260200160008152602001600081526020016000151581525090565b61029a8261029584610eae565b611047565b92915050565b60008060006102ae84611382565b805173ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604081209192506102e18683611529565b90506102ed8184610e20565b9097909650945050505050565b61033f604080516060808201835260008083526020808401829052845160a0810186528281529081018290528085018290529182018190526080820152909182015290565b60408181018051600160209091015280516000920191909152805163ffffffff6060909101525162ffffff6080909101527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff90811690831614156103c2576001815260006020820152919050565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600b6020526040902054161561045c57600381526000602080830182905273ffffffffffffffffffffffffffffffffffffffff8085168352600b825260408084205490911683526008909152908190205481830151750100000000000000000000000000000000000000000090910463ffffffff16910152919050565b60408051608081018252610bb8815261271060208201526101f49181019190915260646060820152600090819081805b60048110156106c05760007f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98473ffffffffffffffffffffffffffffffffffffffff16631698ee82897f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2878660048110610507576105076133bc565b60200201516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff938416600482015292909116602483015262ffffff166044820152606401602060405180830381865afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ac91906133eb565b905073ffffffffffffffffffffffffffffffffffffffff81166105cf57506106b0565b60008173ffffffffffffffffffffffffffffffffffffffff16631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561061c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106409190613408565b905073ffffffffffffffffffffffffffffffffffffffff871615806106885750836fffffffffffffffffffffffffffffffff16816fffffffffffffffffffffffffffffffff16115b156106ad578196508483600481106106a2576106a26133bc565b602002015195508093505b50505b6106b981613469565b905061048c565b50505073ffffffffffffffffffffffffffffffffffffffff8216610745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6e6f2d756e69737761702d706f6f6c2d617661696c00000000000000000060448201526064015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1661076685836115b4565b73ffffffffffffffffffffffffffffffffffffffff16146107e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f652f6261642d756e69737761702d706f6f6c2d61646472000000000000000000604482015260640161073c565b6002835262ffffff811660208401526040517f32148f670000000000000000000000000000000000000000000000000000000081526090600482015273ffffffffffffffffffffffffffffffffffffffff8316906332148f6790602401600060405180830381600087803b15801561085a57600080fd5b505af192505050801561086b575060015b6109d3576108776134a2565b806308c379a01415610996575061088c6134be565b806108975750610998565b805160208201207fe01ebc6b01bbf458b3d355b6e649efe64599751670c5d19175619893ecf975291415610927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f652f7269736b2f756e69737761702d706f6f6c2d6e6f742d696e697465640000604482015260640161073c565b80604051602001610938919061358b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261073c916004016135d0565b505b3d8080156109c2576040519150601f19603f3d011682016040523d82523d6000602084013e6109c7565b606091505b506109d18161173b565b505b50505b919050565b6000806000806109ea85611382565b805173ffffffffffffffffffffffffffffffffffffffff166000908152600960205260408120919250610a1d8783611529565b9050610a298184610e20565b909650945060008080610a3c84876117ac565b509194509250905061ffff821660011415610a6157670de0b6b3a76400009650610b9e565b61ffff821660021480610a78575061ffff82166003145b15610b3c576000610a898487611529565b90506000610a9785846115b4565b905060008173ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015610ae6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0a9190613621565b5050505050509050610b32838273ffffffffffffffffffffffffffffffffffffffff16611916565b9950505050610b9e565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f756e6b6e6f776e2d70726963696e672d7479706500000000000000000000604482015260640161073c565b5050505050509193909250565b6000610bb68261025b565b905080606001511580610bcd575080604001516001145b610c33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f626f72726f772d69736f6c6174696f6e2d76696f6c6174696f6e00000000604482015260640161073c565b602081015181511015610ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f636f6c6c61746572616c2d76696f6c6174696f6e00000000000000000000604482015260640161073c565b5050565b60606000610cb383610eae565b90506000815167ffffffffffffffff811115610cd157610cd1613062565b604051908082528060200260200182016040528015610d0a57816020015b610cf7612f01565b815260200190600190039081610cef5790505b50604080516001808252818301909252919250600091906020808301908036833701905050905060005b8351811015610e1657838181518110610d4f57610d4f6133bc565b602002602001015182600081518110610d6a57610d6a6133bc565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250838281518110610db557610db56133bc565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff9091169052610de48683611047565b838281518110610df657610df66133bc565b60200260200101516020018190525080610e0f90613469565b9050610d34565b5090949350505050565b604051600090819081808080610e3689896117ac565b9350935093509350600161ffff168361ffff161415610e6757670de0b6b3a764000096508062ffffff169550610e9e565b61ffff831660021415610b3c576000610e8085846115b4565b9050610e928a828462ffffff16611a71565b9098509650610e9e9050565b5050505080604052509250929050565b73ffffffffffffffffffffffffffffffffffffffff80821660009081526006602052604081205460609263ffffffff6601000000000000830416926a010000000000000000000090920416908267ffffffffffffffff811115610f1357610f13613062565b604051908082528060200260200182016040528015610f3c578160200160208202803683370190505b50905063ffffffff8316610f5257949350505050565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600760205260408120825190918491849190610f8c57610f8c6133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260015b8463ffffffff1681101561103c5781816401000000008110610fd857610fd86133bc565b0154835173ffffffffffffffffffffffffffffffffffffffff90911690849083908110611007576110076133bc565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261103581613469565b9050610fb4565b509095945050505050565b61107460405180608001604052806000815260200160008152602001600081526020016000151581525090565b6000808252602080830182905260408084018390526060808501849052815160a08101835284815292830184905290820183905281018290526080810191909152604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810182905260005b855181101561137857600086828151811061114d5761114d6133bc565b6020026020010151905060008061116383611382565b805173ffffffffffffffffffffffffffffffffffffffff9081166000908152600960209081526040808320938f1683526005840190915290205491985096506dffffffffffffffffffffffffffff8116906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff1681158015906111f25750604089015163ffffffff1615155b1561127f5761120285898961208d565b5061120d878a610e20565b5060019450925060006112208884612500565b9050670de0b6b3a764000061123585836136c4565b61123f9190613730565b905063ee6b28008a6040015163ffffffff168261125c91906136c4565b6112669190613730565b9050808b60000181815161127a9190613744565b905250505b801561136257836112a85761129585898961208d565b506112a0878a610e20565b506001945092505b60408a018051906112b882613469565b9052506020890151156112cd57600160608b01525b60006112da89898f612533565b9050670de0b6b3a76400006112ef85836136c4565b6112f99190613730565b9050896060015163ffffffff16600014156113265771ffffffffffffffffffffffffffffffffffff611349565b60608a015163ffffffff1661133f63ee6b2800836136c4565b6113499190613730565b9050808b60200181815161135d9190613744565b905250505b50505050508061137190613469565b9050611130565b5050505092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff828116600090815260086020908152604091829020825160a081018452905493841680825274010000000000000000000000000000000000000000850460ff161515928201929092527501000000000000000000000000000000000000000000840463ffffffff90811693820193909352790100000000000000000000000000000000000000000000000000840490921660608301527d01000000000000000000000000000000000000000000000000000000000090920462ffffff166080820152906114eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f652f6d61726b65742d6e6f742d61637469766174656400000000000000000000604482015260640161073c565b606081015163ffffffff9081161415611509576342c1d80060608201525b608081015162ffffff908116141561029a57610708608082015292915050565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c08101919091526115ad83838361208d565b5092915050565b6000827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff80821690831611156115fb57905b6040805173ffffffffffffffffffffffffffffffffffffffff808516602083015283169181019190915262ffffff851660608201527f0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f98490608001604051602081830303815290604052805190602001207fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b546040516020016116fc939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830191909152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012095945050505050565b80511561174a57805181602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f652f656d7074792d6572726f7200000000000000000000000000000000000000604482015260640161073c565b600080600080600361ffff1686610140015161ffff1614156118f057855173ffffffffffffffffffffffffffffffffffffffff9081166000908152600b602052604081205490911694506117ff85611382565b6080810151815173ffffffffffffffffffffffffffffffffffffffff16600090815260096020526040902080547a010000000000000000000000000000000000000000000000000000810461ffff1697507c0100000000000000000000000000000000000000000000000000000000900463ffffffff16955090935090915060038514156118e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f652f6e65737465642d70726963652d666f7277617264696e6700000000000000604482015260640161073c565b505061190d565b505083516101408501516101608601516080860151929450909250905b92959194509250565b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1610156119bc576101a08301516119ab83806119a6670de0b6b3a76400007801000000000000000000000000000000000000000000000000613730565b6125b5565b6119b59190613730565b9050611a36565b6119fd8283856101a00151670de0b6b3a76400006119da91906136c4565b6119a6907801000000000000000000000000000000000000000000000000613730565b905080611a1a57506ec097ce7bc90715b34b9f100000000061029a565b611a33816ec097ce7bc90715b34b9f1000000000613730565b90505b6ec097ce7bc90715b34b9f1000000000811115611a6357506ec097ce7bc90715b34b9f100000000061029a565b8061029a5750600192915050565b6040805160028082526060820183526000928392839290916020830190803683370190505090508381600081518110611aac57611aac6133bc565b602002602001019063ffffffff16908163ffffffff1681525050600081600181518110611adb57611adb6133bc565b602002602001019063ffffffff16908163ffffffff16815250506000808673ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b84604051602401611b28919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611bb1919061379a565b600060405180830381855afa9150503d8060008114611bec576040519150601f19603f3d011682016040523d82523d6000602084013e611bf1565b606091505b509150915081611fe85760405160206024820152600360448201527f4f4c4400000000000000000000000000000000000000000000000000000000006064820152608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f08c379a000000000000000000000000000000000000000000000000000000000178152915190912082519183019190912014611cc857611cc88161173b565b6000808873ffffffffffffffffffffffffffffffffffffffff16633850c7bd6040518163ffffffff1660e01b815260040160e060405180830381865afa158015611d16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3a9190613621565b5050509350935050506000808a73ffffffffffffffffffffffffffffffffffffffff1663252c09d784866001611d7091906137b6565b611d7a91906137dc565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815261ffff9091166004820152602401608060405180830381865afa158015611dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df5919061380f565b93505050915080611e96576040517f252c09d70000000000000000000000000000000000000000000000000000000081526000600482015273ffffffffffffffffffffffffffffffffffffffff8c169063252c09d790602401608060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061380f565b5091935050505b611ea663ffffffff83164261386a565b99508987600081518110611ebc57611ebc6133bc565b602002602001019063ffffffff16908163ffffffff16815250508a73ffffffffffffffffffffffffffffffffffffffff1663883bdbfd60e01b88604051602401611f06919061375c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051611f8f919061379a565b600060405180830381855afa9150503d8060008114611fca576040519150601f19603f3d011682016040523d82523d6000602084013e611fcf565b606091505b50909650945085611fe357611fe38561173b565b505050505b600081806020019051810190611ffe9190613881565b905060008782600081518110612016576120166133bc565b602002602001015183600181518110612031576120316133bc565b6020026020010151612043919061392f565b61204d9190613997565b9050600061205a82612682565b905061207c8b8273ffffffffffffffffffffffffffffffffffffffff16611916565b9b989a509798505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83168152815464ffffffffff811660a083015265010000000000810460ff90811660c084018190526601000000000000830463ffffffff90811660e08601526a01000000000000000000008404600b0b610100860152760100000000000000000000000000000000000000000000840481166101208601527a010000000000000000000000000000000000000000000000000000840461ffff166101408601527c010000000000000000000000000000000000000000000000000000000090930490921661016084015260018401547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16606084015260038401546dffffffffffffffffffffffffffff80821660208601526e01000000000000000000000000000090910471ffffffffffffffffffffffffffffffffffff166040850152600485015460808501526012839003909116600a0a6101a08401819052600092918161221257612212613701565b046101c084015260006122258430612a16565b9050836101c001518111612246576101a0840151810261018085015261224f565b60006101808501525b8360a0015164ffffffffff1642146124f7576001925060008460a0015164ffffffffff164261227e919061386a565b905060006b033b2e3c9fd0803ce800000086608001516122ca886101000151600b0b6b033b2e3c9fd0803ce80000006122b79190613a0b565b856b033b2e3c9fd0803ce8000000612b33565b6122d491906136c4565b6122de9190613730565b90506000866080015182886040015171ffffffffffffffffffffffffffffffffffff1661230b91906136c4565b6123159190613730565b606088015160208901519192506bffffffffffffffffffffffff16906dffffffffffffffffffffffffffff166000612355633b9aca0063ee6b28006136c4565b6101208b015163ffffffff90811614612373578a6101200151612379565b6336d616005b63ffffffff168b6040015171ffffffffffffffffffffffffffffffffffff16866123a3919061386a565b6123ad91906136c4565b6123b79190613730565b9050801561242f5760006123cf633b9aca0086613730565b8b61018001516123df9190613744565b90506123eb828261386a565b6123f584836136c4565b6123ff9190613730565b92508a602001516dffffffffffffffffffffffffffff1683612421919061386a565b61242b9085613744565b9350505b6dffffffffffffffffffffffffffff821180159061245f575071ffffffffffffffffffffffffffffffffffff8411155b156124f05761246d84612bf0565b71ffffffffffffffffffffffffffffffffffff1660408b015260808a0185905264ffffffffff421660a08b015260208a01516dffffffffffffffffffffffffffff1682146124f0576124be83612c98565b6bffffffffffffffffffffffff1660608b01526124da82612d36565b6dffffffffffffffffffffffffffff1660208b01525b5050505050505b50509392505050565b60008061250c84612db0565b9050670de0b6b3a764000061252182856136c4565b61252b9190613730565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600584016020526040812054633b9aca00906125a190859061259c908890839088906e010000000000000000000000000000900471ffffffffffffffffffffffffffffffffffff16612e47565b612ea3565b6125ab9190613730565b90505b9392505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff858709858702925082811083820303915050806000141561260d576000841161260257600080fd5b5082900490506125ae565b80841161261957600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60008060008360020b12612699578260020b6126a1565b8260020b6000035b9050620d89e8811115612710576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600160248201527f5400000000000000000000000000000000000000000000000000000000000000604482015260640161073c565b60006001821661273157700100000000000000000000000000000000612743565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612777576ffff97272373d413259a46990580e213a0260801c5b6004821615612796576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60088216156127b5576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b60108216156127d4576fffcb9843d60f6159c9db58835c9266440260801c5b60208216156127f3576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612812576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612831576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612851576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612871576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612891576ff3392b0822b70005940c7a398e4b70f30260801c5b6108008216156128b1576fe7159475a2c29b7443b29c7fa6e889d90260801c5b6110008216156128d1576fd097f3bdfd2022b8845ad8f792aa58250260801c5b6120008216156128f1576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612911576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612931576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612952576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b62020000821615612972576e5d6af8dedb81196699c329225ee6040260801c5b62040000821615612991576d2216e584f5fa1ea926041bedfe980260801c5b620800008216156129ae576b048a170391f7dc42444e8fa20260801c5b60008460020b13156129ed57807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff816129e9576129e9613701565b0490505b640100000000810615612a01576001612a04565b60005b60ff16602082901c0192505050919050565b60408051835173ffffffffffffffffffffffffffffffffffffffff848116602480850191909152845180850390910181526044840185526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f70a08231000000000000000000000000000000000000000000000000000000001790529351600094859384931691614e2091612aad9161379a565b6000604051808303818686fa925050503d8060008114612ae9576040519150601f19603f3d011682016040523d82523d6000602084013e612aee565b606091505b5091509150811580612b01575060208151105b15612b1157600093505050612b2a565b80806020019051810190612b259190613a7f565b935050505b60405292915050565b6000838015612bd357600184168015612b4e57859250612b52565b8392505b50600283046002850494505b8415612bcd578586028687820414612b7557600080fd5b81810181811015612b8557600080fd5b8590049650506001851615612bc2578583028387820414158715151615612bab57600080fd5b81810181811015612bbb57600080fd5b8590049350505b600285049450612b5e565b50612be8565b838015612be357600092506124f7565b839250505b509392505050565b600071ffffffffffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f652f646562742d616d6f756e742d746f6f2d6c617267652d746f2d656e636f6460448201527f6500000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b5090565b60006bffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f652f736d616c6c2d616d6f756e742d746f6f2d6c617267652d746f2d656e636f60448201527f6465000000000000000000000000000000000000000000000000000000000000606482015260840161073c565b60006dffffffffffffffffffffffffffff821115612c94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f652f616d6f756e742d746f6f2d6c617267652d746f2d656e636f646500000000604482015260640161073c565b600081602001516dffffffffffffffffffffffffffff1660001415612dde5750670de0b6b3a7640000919050565b81602001516dffffffffffffffffffffffffffff16633b9aca00836040015171ffffffffffffffffffffffffffffffffffff16612e1b9190613730565b836101800151612e2b9190613744565b612e3d90670de0b6b3a76400006136c4565b61029a9190613730565b600081612e565750600061252b565b73ffffffffffffffffffffffffffffffffffffffff831660009081526005860160205260409020600101546080850151612e9090846136c4565b612e9a9190613730565b95945050505050565b600081612eb25750600061029a565b6101a0830151633b9aca000280807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8582010181612ef257612ef2613701565b0402949350505050565b905290565b6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001612efc60405180608001604052806000815260200160008152602001600081526020016000151581525090565b73ffffffffffffffffffffffffffffffffffffffff81168114612f7857600080fd5b50565b80356109d681612f56565b600060208284031215612f9857600080fd5b81356125ae81612f56565b8151815260208083015190820152604080830151908201526060808301511515908201526080810161029a565b6020808252825182820181905260009190848201906040850190845b81811015613056578351805173ffffffffffffffffffffffffffffffffffffffff168452850151613042868501828051825260208101516020830152604081015160408301526060810151151560608301525050565b509284019260a09290920191600101612fec565b50909695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff821117156130d5576130d5613062565b6040525050565b6040516101e0810167ffffffffffffffff8111828210171561310057613100613062565b60405290565b80356dffffffffffffffffffffffffffff811681146109d657600080fd5b803571ffffffffffffffffffffffffffffffffffff811681146109d657600080fd5b80356bffffffffffffffffffffffff811681146109d657600080fd5b803564ffffffffff811681146109d657600080fd5b60ff81168114612f7857600080fd5b80356109d681613177565b63ffffffff81168114612f7857600080fd5b80356109d681613191565b8035600b81900b81146109d657600080fd5b61ffff81168114612f7857600080fd5b80356109d6816131c0565b8015158114612f7857600080fd5b600060a082840312156131fb57600080fd5b60405160a0810181811067ffffffffffffffff8211171561321e5761321e613062565b604052905080823561322f81612f56565b8152602083013561323f816131db565b6020820152604083013561325281613191565b6040820152606083013561326581613191565b6060820152608083013562ffffff8116811461328057600080fd5b6080919091015292915050565b6000808284036102808112156132a257600080fd5b6101e0808212156132b257600080fd5b6132ba6130dc565b91506132c585612f7b565b82526132d360208601613106565b60208301526132e460408601613124565b60408301526132f560608601613146565b60608301526080850135608083015261331060a08601613162565b60a083015261332160c08601613186565b60c083015261333260e086016131a3565b60e08301526101006133458187016131ae565b908301526101206133578682016131a3565b908301526101406133698682016131d0565b9083015261016061337b8682016131a3565b9083015261018085810135908301526101a080860135908301526101c0808601359083015290925082906133b1868287016131e9565b925050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156133fd57600080fd5b81516125ae81612f56565b60006020828403121561341a57600080fd5b81516fffffffffffffffffffffffffffffffff811681146125ae57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561349b5761349b61343a565b5060010190565b600060033d11156134bb5760046000803e5060005160e01c5b90565b600060443d10156134cc5790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff816024840111818411171561351a57505050505090565b82850191508151818111156135325750505050505090565b843d870101602082850101111561354c5750505050505090565b61103c60208286010187613091565b60005b8381101561357657818101518382015260200161355e565b83811115613585576000848401525b50505050565b7f652f7269736b2f756e69737761702f00000000000000000000000000000000008152600082516135c381600f85016020870161355b565b91909101600f0192915050565b60208152600082518060208401526135ef81604085016020870161355b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600080600080600080600060e0888a03121561363c57600080fd5b875161364781612f56565b8097505060208801518060020b811461365f57600080fd5b6040890151909650613670816131c0565b6060890151909550613681816131c0565b6080890151909450613692816131c0565b60a08901519093506136a381613177565b60c08901519092506136b4816131db565b8091505092959891949750929550565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156136fc576136fc61343a565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261373f5761373f613701565b500490565b600082198211156137575761375761343a565b500190565b6020808252825182820181905260009190848201906040850190845b8181101561305657835163ffffffff1683529284019291840191600101613778565b600082516137ac81846020870161355b565b9190910192915050565b600061ffff8083168185168083038211156137d3576137d361343a565b01949350505050565b600061ffff808416806137f1576137f1613701565b92169190910692915050565b8051600681900b81146109d657600080fd5b6000806000806080858703121561382557600080fd5b845161383081613191565b935061383e602086016137fd565b9250604085015161384e81612f56565b606086015190925061385f816131db565b939692955090935050565b60008282101561387c5761387c61343a565b500390565b6000602080838503121561389457600080fd5b825167ffffffffffffffff808211156138ac57600080fd5b818501915085601f8301126138c057600080fd5b8151818111156138d2576138d2613062565b8060051b91506040516138e785840182613091565b8181529183018401918481018884111561390057600080fd5b938501935b8385101561392357613916856137fd565b8152938501938501613905565b50979650505050505050565b60008160060b8360060b60008112817fffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000018312811516156139725761397261343a565b81667fffffffffffff01831381161561398d5761398d61343a565b5090039392505050565b60008160060b8360060b806139ae576139ae613701565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81147fffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000083141615613a0257613a0261343a565b90059392505050565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615613a4557613a4561343a565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615613a7957613a7961343a565b50500190565b600060208284031215613a9157600080fd5b505191905056fea264697066735822122049da3334e4e4abd0c5d85f3a1e678e0ca391f95c3fb85f584b53ad8f03a4f2cb64736f6c634300080a0033

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

00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54

-----Decoded View---------------
Arg [0] : moduleGitCommit_ (bytes32): 0x00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13
Arg [1] : settings (tuple):
Arg [1] : referenceAsset (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : uniswapFactory (address): 0x1F98431c8aD98523631AE4a59f267346ea31F984
Arg [3] : uniswapPoolInitCodeHash (bytes32): 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54


-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000070cfa81ef67a76c44ac1e28249cadecd34f00a13
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984
Arg [3] : e34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54


Deployed Bytecode Sourcemap

1015:13425:11:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13336:182;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;9394:404;;;;;;:::i;:::-;;:::i;:::-;;;;1303:25:15;;;1359:2;1344:18;;1337:34;;;;1276:18;9394:404:11;1129:248:15;241:40:3;;;;;;;;1528:25:15;;;1516:2;1501:18;241:40:3;1382:177:15;1733:2679:11;;;;;;:::i;:::-;;:::i;:::-;;;;1807:13:15;;1822:6;1803:26;1785:45;;1877:4;1865:17;;;1859:24;1902:10;1950:21;;;1928:20;;;1921:51;2009:17;;;2003:24;2069:21;;2092:42;2065:70;2043:20;;;2036:100;2192:25;;;2186:32;2179:40;2172:48;2167:2;2152:18;;;2145:76;;;;2268:25;;;2262:32;2258:41;;2252:3;2237:19;;;2230:70;;;;2347:23;;;2341:30;2337:39;;;2331:3;2316:19;;2309:68;2424:24;;2418:31;2451:8;2414:46;2408:3;2393:19;;2386:75;1772:3;1757:19;1733:2679:11;1564:903:15;9991:1142:11;;;;;;:::i;:::-;;:::i;:::-;;;;2674:25:15;;;2730:2;2715:18;;2708:34;;;;2758:18;;;2751:34;2662:2;2647:18;9991:1142:11;2472:319:15;205:30:3;;;;;14106:332:11;;;;;;:::i;:::-;;:::i;:::-;;13524:576;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;8677:711::-;;;;;;:::i;:::-;;:::i;13336:182::-;13409:22;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13409:22:11;13450:61;13470:7;13479:31;13502:7;13479:22;:31::i;:::-;13450:19;:61::i;:::-;13443:68;13336:182;-1:-1:-1;;13336:182:11:o;9394:404::-;9464:9;9475:15;9502:25;9530:30;9549:10;9530:18;:30::i;:::-;9619:20;;9606:34;;9570:33;9606:34;;;:12;:34;;;;;9502:58;;-1:-1:-1;9681:42:11;9698:10;9606:34;9681:16;:42::i;:::-;9650:73;;9755:36;9772:10;9784:6;9755:16;:36::i;:::-;9734:57;;;;-1:-1:-1;9394:404:11;-1:-1:-1;;;;;9394:404:11:o;1733:2679::-;1812:28;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1812:28:11;1852:8;;;;;;1878:4;1852:23;;;;:30;1892:8;;1852:30;1892:25;;:37;;;;1939:8;;1892:37;1939:21;;;;:40;1989:8;2011:16;1989:19;;;;:38;2056:14;2042:28;;;;;;;;2038:2368;;;1689:1:4;2110:35:11;;:13;2159:19;;;:31;1733:2679;;;:::o;2038:2368::-;2211:38;:24;;;2247:1;2211:24;;;:12;:24;;;;;;;:38;2207:2199;;1807:1:4;2265:38:11;;:13;2317:19;;;;:31;;;2408:24;;;;;;:12;:24;;;;;;;;;;2391:42;;:16;:42;;;;;;;:59;2363:8;;;;2391:59;;;;2317:31;2391:59;2363:25;;:87;1733:2679;;;:::o;2207:2199::-;2960:55;;;;;;;;2992:4;2960:55;;2999:5;2960:55;;;;3006:3;2960:55;;;;;;;3011:3;2960:55;;;;2874:12;;;;;;3077:563;3098:11;3094:1;:15;3077:563;;;3138:21;3180:14;3162:41;;;3204:10;3216:14;3232:4;3237:1;3232:7;;;;;;;:::i;:::-;;;;;3162:78;;;;;;;;;;9537:42:15;9606:15;;;3162:78:11;;;9588:34:15;9658:15;;;;9638:18;;;9631:43;9722:8;9710:21;9690:18;;;9683:49;9500:18;;3162:78:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3138:102;-1:-1:-1;3266:27:11;;;3262:41;;3295:8;;;3262:41;3326:17;3361:13;3346:39;;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3326:61;-1:-1:-1;3414:18:11;;;;;:47;;;3448:13;3436:25;;:9;:25;;;3414:47;3410:212;;;3496:13;3489:20;;3541:4;3546:1;3541:7;;;;;;;:::i;:::-;;;;;3535:13;;3590:9;3574:25;;3410:212;3116:524;;3077:563;3111:3;;;:::i;:::-;;;3077:563;;;-1:-1:-1;;;3676:18:11;;;3668:54;;;;;;;10900:2:15;3668:54:11;;;10882:21:15;10939:2;10919:18;;;10912:30;10978:25;10958:18;;;10951:53;11021:18;;3668:54:11;;;;;;;;;3790:4;3744:50;;:42;3770:10;3782:3;3744:25;:42::i;:::-;:50;;;3736:86;;;;;;;11252:2:15;3736:86:11;;;11234:21:15;11291:2;11271:18;;;11264:30;11330:25;11310:18;;;11303:53;11373:18;;3736:86:11;11050:347:15;3736:86:11;1750:1:4;3837:42:11;;3915:11;;;3893:19;;;:33;3945:93;;;;;1146:3:4;3945:93:11;;;11546:38:15;3945:55:11;;;;;;11519:18:15;;3945:93:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3941:455;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;4135:21;;;;;;4160:16;4135:41;4131:87;;;4178:40;;;;;12717:2:15;4178:40:11;;;12699:21:15;12756:2;12736:18;;;12729:30;12795:32;12775:18;;;12768:60;12845:18;;4178:40:11;12515:354:15;4131:87:11;4286:3;4250:40;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;4236:56;;;;;;;;:::i;3941:455::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4358:23;4370:10;4358:11;:23::i;:::-;4308:88;3941:455;2467:1939;;2207:2199;1733:2679;;;:::o;9991:1142::-;10065:9;10076:15;10093:14;10119:25;10147:30;10166:10;10147:18;:30::i;:::-;10236:20;;10223:34;;10187:33;10223:34;;;:12;:34;;;;;10119:58;;-1:-1:-1;10298:42:11;10315:10;10223:34;10298:16;:42::i;:::-;10267:73;;10372:36;10389:10;10401:6;10372:16;:36::i;:::-;10351:57;;-1:-1:-1;10351:57:11;-1:-1:-1;10420:21:11;;;10492:40;10513:10;10525:6;10492:20;:40::i;:::-;-1:-1:-1;10419:113:11;;-1:-1:-1;10419:113:11;-1:-1:-1;10419:113:11;-1:-1:-1;10547:34:11;;;1689:1:4;10547:34:11;10543:584;;;10609:4;10597:16;;10543:584;;;10634:41;;;1750:1:4;10634:41:11;;:82;;-1:-1:-1;10679:37:11;;;1807:1:4;10679:37:11;10634:82;10630:497;;;10732:31;10766:45;10783:13;10798:12;10766:16;:45::i;:::-;10732:79;;10825:12;10840:67;10866:13;10888:17;10840:25;:67::i;:::-;10825:82;;10922:20;10967:4;10952:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10921:59;;;;;;;;11006:47;11025:13;11040:12;11006:47;;:18;:47::i;:::-;10994:59;;10718:346;;;10630:497;;;11084:32;;;;;15301:2:15;11084:32:11;;;15283:21:15;15340:2;15320:18;;;15313:30;15379:24;15359:18;;;15352:52;15421:18;;11084:32:11;15099:346:15;10630:497:11;10109:1024;;;;;;9991:1142;;;;;:::o;14106:332::-;14182:29;14214:25;14231:7;14214:16;:25::i;:::-;14182:57;;14259:6;:21;;;14258:22;:48;;;;14284:6;:17;;;14305:1;14284:22;14258:48;14250:89;;;;;;;15652:2:15;14250:89:11;;;15634:21:15;15691:2;15671:18;;;15664:30;15730;15710:18;;;15703:58;15778:18;;14250:89:11;15450:352:15;14250:89:11;14383:21;;;;14357:22;;:47;;14349:82;;;;;;;16009:2:15;14349:82:11;;;15991:21:15;16048:2;16028:18;;;16021:30;16087:24;16067:18;;;16060:52;16129:18;;14349:82:11;15807:346:15;14349:82:11;14172:266;14106:332;:::o;13524:576::-;13606:23;13641:28;13672:31;13695:7;13672:22;:31::i;:::-;13641:62;;13714:30;13768:11;:18;13747:40;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;-1:-1:-1;13834:16:11;;;13848:1;13834:16;;;;;;;;;13714:73;;-1:-1:-1;13798:33:11;;13834:16;;;;;;;;;;;;-1:-1:-1;13834:16:11;13798:52;;13866:6;13861:209;13882:11;:18;13878:1;:22;13861:209;;;13966:11;13978:1;13966:14;;;;;;;;:::i;:::-;;;;;;;13944:16;13961:1;13944:19;;;;;;;;:::i;:::-;;;;;;:36;;;;;;;;;;13921:6;13928:1;13921:9;;;;;;;;:::i;:::-;;;;;;;;;;;:59;;;;;;14013:46;14033:7;14042:16;14013:19;:46::i;:::-;13994:6;14001:1;13994:9;;;;;;;;:::i;:::-;;;;;;;:16;;:65;;;;13902:3;;;;:::i;:::-;;;13861:209;;;-1:-1:-1;14087:6:11;;13524:576;-1:-1:-1;;;;13524:576:11:o;8677:711::-;2125:4:0;2119:11;8789:9:11;;;;;;;;8915:40:::1;8936:10:::0;8948:6;8915:20:::1;:40::i;:::-;8827:128;;;;;;;;1689:1:4;8970:34:11;;:11;:34;;;8966:416;;;9027:4;9020:11;;9058:10;9045:23;;;;8966:416;;;9089:41;::::0;::::1;1750:1:4;9089:41:11;9085:297;;;9146:12;9161:64;9187:10;9206:17;9161:25;:64::i;:::-;9146:79;;9260:48;9279:10;9291:4;9297:10;9260:48;;:18;:48::i;:::-;9239:69:::0;;-1:-1:-1;9239:69:11;-1:-1:-1;9085:297:11::1;::::0;-1:-1:-1;9085:297:11::1;;8817:571;;;;2518:14:0::0;2512:4;2505:28;2491:52;8677:711:11;;;;;:::o;846:631:2:-;973:22;;;;946:24;973:22;;;:13;:22;;;;;:40;918:16;;973:40;;;;;;1052:41;;;;;;973:40;1130:32;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1130:32:2;-1:-1:-1;1104:58:2;-1:-1:-1;1176:22:2;;;1172:41;;1207:6;846:631;-1:-1:-1;;;;846:631:2:o;1172:41::-;1280:23;;;1224:53;1280:23;;;:14;:23;;;;;1314:9;;1280:23;;1326:18;;1314:6;;1224:53;1314:9;;;;:::i;:::-;:30;;;;:9;;;;;;;;;;;:30;1369:1;1355:92;1376:17;1372:21;;:1;:21;1355:92;;;1426:7;1434:1;1426:10;;;;;;;:::i;:::-;;;1414:9;;1426:10;;;;;1414:6;;1421:1;;1414:9;;;;;;:::i;:::-;:22;;;;:9;;;;;;;;;;;:22;1395:3;;;:::i;:::-;;;1355:92;;;-1:-1:-1;1464:6:2;;846:631;-1:-1:-1;;;;;846:631:2:o;11158:2172:11:-;11256:29;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11256:29:11;11322:1;11297:26;;;11333:21;;;;:25;;;11368:17;;;;:21;;;11399;;;;:29;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11474:33:11;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11561:6:11;11556:1768;11577:11;:18;11573:1;:22;11556:1768;;;11616:18;11637:11;11649:1;11637:14;;;;;;;;:::i;:::-;;;;;;;11616:35;;11665:29;11716:10;11750:30;11769:10;11750:18;:30::i;:::-;11822:20;;11809:34;;;;;;;;:12;:34;;;;;;;;11873:27;;;;;:18;;;:27;;;;;:35;11822:20;;-1:-1:-1;11809:34:11;-1:-1:-1;11873:35:11;;;;11934:32;;;;;11985:12;;;;;:44;;-1:-1:-1;12001:23:11;;;;:28;;;;11985:44;11981:561;;;12049:52;12064:10;12076:12;12090:10;12049:14;:52::i;:::-;;12130:36;12147:10;12159:6;12130:16;:36::i;:::-;-1:-1:-1;12211:4:11;;-1:-1:-1;12119:47:11;-1:-1:-1;12234:20:11;12257:46;12283:10;12295:7;12257:25;:46::i;:::-;12234:69;-1:-1:-1;12365:4:11;12339:23;12357:5;12234:69;12339:23;:::i;:::-;:30;;;;:::i;:::-;12321:48;;736:13:4;12423:6:11;:23;;;12405:41;;:15;:41;;;;:::i;:::-;:63;;;;:::i;:::-;12387:81;;12512:15;12486:6;:22;;:41;;;;;;;:::i;:::-;;;-1:-1:-1;;11981:561:11;12560:9;;12556:758;;12594:24;12589:246;;12642:52;12657:10;12669:12;12683:10;12642:14;:52::i;:::-;;12727:36;12744:10;12756:6;12727:16;:36::i;:::-;-1:-1:-1;12812:4:11;;-1:-1:-1;12716:47:11;-1:-1:-1;12589:246:11;12853:17;;;:19;;;;;;:::i;:::-;;;-1:-1:-1;12894:21:11;;;;12890:55;;;12941:4;12917:21;;;:28;12890:55;12964:19;12986:49;13001:12;13015:10;13027:7;12986:14;:49::i;:::-;12964:71;-1:-1:-1;13095:4:11;13070:22;13087:5;12964:71;13070:22;:::i;:::-;:29;;;;:::i;:::-;13053:46;;13134:6;:19;;;:24;;13157:1;13134:24;;:108;;418:17:4;13134:108:11;;;13200:19;;;;13161:58;;:36;736:13:4;13161:14:11;:36;:::i;:::-;:58;;;;:::i;:::-;13117:125;;13285:14;13260:6;:21;;:39;;;;;;;:::i;:::-;;;-1:-1:-1;;12556:758:11;11602:1722;;;;;11597:3;;;;:::i;:::-;;;11556:1768;;;;11287:2043;;;11158:2172;;;;:::o;4431:466:2:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4560:28:2;;;;4532:25;4560:28;;;:16;:28;;;;;;;;;4532:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4598:69;;;;;;;17040:2:15;4598:69:2;;;17022:21:15;17079:2;17059:18;;;17052:30;17118:24;17098:18;;;17091:52;17160:18;;4598:69:2;16838:346:15;4598:69:2;4682:19;;;;4705:16;4682:39;;;;4678:88;;;1279:20:4;4723:19:2;;;:43;4678:88;4780:17;;;;4801:16;4780:37;;;;4776:90;;;1210:7:4;4819:17:2;;;:47;4884:6;4431:466;-1:-1:-1;;4431:466:2:o;9715:203::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9859:52:2;9874:10;9886:12;9900:10;9859:14;:52::i;:::-;;9715:203;;;;:::o;4436:508:11:-;4525:7;4561:10;4598:14;4626:15;;;;;;;;4622:56;;;4663:6;4622:56;4840:31;;;9537:42:15;9606:15;;;4840:31:11;;;9588:34:15;9658:15;;9638:18;;;9631:43;;;;9722:8;9710:21;;9690:18;;;9683:49;4795:14:11;;9500:18:15;;4840:31:11;;;;;;;;;;;;4830:42;;;;;;4893:23;4730:203;;;;;;;;;17487:66:15;17475:79;;17591:2;17587:15;;;;17604:66;17583:88;17579:1;17570:11;;17563:109;17697:2;17688:12;;17681:28;;;;17734:2;17725:12;;17718:28;17771:2;17762:12;;17189:591;4730:203:11;;;;;;;;;;;;;;4720:214;;4730:203;4720:214;;;;;4436:508;-1:-1:-1;;;;;4436:508:11:o;2580:232:0:-;2650:13;;:17;2646:126;;2740:6;2734:13;2725:6;2721:2;2717:15;2710:38;2646:126;2782:23;;;;;17987:2:15;2782:23:0;;;17969:21:15;18026:2;18006:18;;;17999:30;18065:15;18045:18;;;18038:43;18098:18;;2782:23:0;17785:337:15;7687:984:11;7796:18;7816;7836:24;7862:17;1807:1:4;7895:48:11;;:10;:22;;;:48;;;7891:774;;;7985:21;;7972:35;;;;;;;;:12;:35;;;;;;;;;;-1:-1:-1;8053:30:11;7972:35;8053:18;:30::i;:::-;8110:20;;;;8197:23;;8184:37;;8145:36;8184:37;;;:12;:37;;;;;8249:27;;;;;;;;-1:-1:-1;8310:33:11;;;;;;-1:-1:-1;8110:20:11;;-1:-1:-1;8110:20:11;;-1:-1:-1;1807:1:4;8366:37:11;;;8358:75;;;;;;;18329:2:15;8358:75:11;;;18311:21:15;18368:2;18348:18;;;18341:30;18407:27;18387:18;;;18380:55;18452:18;;8358:75:11;18127:349:15;8358:75:11;7945:499;;7891:774;;;-1:-1:-1;;8477:21:11;;8526:22;;;;8582:28;;;;8637:17;;;;8477:21;;-1:-1:-1;8526:22:11;;-1:-1:-1;8582:28:11;7891:774;7687:984;;;;;;;:::o;4951:629::-;5050:10;5117:14;5076:56;;5084:10;:21;;;5076:56;;;5072:421;;;5226:35;;;;5156:67;5172:12;;5200:22;5218:4;5205:9;5200:22;:::i;:::-;5156:15;:67::i;:::-;:105;;;;:::i;:::-;5148:113;;5072:421;;;5300:107;5316:12;5330;5370:10;:35;;;5363:4;:42;;;;:::i;:::-;5344:62;;5349:9;5344:62;:::i;5300:107::-;5292:115;-1:-1:-1;5425:10:11;5421:27;;-1:-1:-1;5444:4:11;5437:11;;5421:27;5470:12;5477:5;5470:4;:12;:::i;:::-;5462:20;;5072:421;5515:4;5507:5;:12;5503:70;;;-1:-1:-1;5529:4:11;5503:70;;;5552:10;5548:25;;-1:-1:-1;5572:1:11;4951:629;;;;:::o;5586:2095::-;5742:15;;;5755:1;5742:15;;;;;;;;5690:4;;;;;;5742:15;;;;;;;;;;;;-1:-1:-1;5742:15:11;5712:45;;5792:3;5768:11;5780:1;5768:14;;;;;;;;:::i;:::-;;;;;;:28;;;;;;;;;;;5823:1;5806:11;5818:1;5806:14;;;;;;;;:::i;:::-;;;;;;:18;;;;;;;;;;;5836:12;5850:17;5871:4;:15;;5910:31;;;5943:11;5887:68;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5871:85;;;;5887:68;5871:85;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5835:121;;;;5972:7;5967:1260;;6028:47;;19614:2:15;6028:47:11;;;19596:21:15;19653:1;19633:18;;;19626:29;19691:5;19671:18;;;19664:33;19714:18;;6028:47:11;;;;;;;;;;;;;;;;;;;;;;;;;6018:58;;;;;5999:15;;;;;;;;;:77;5995:100;;6078:17;6090:4;6078:11;:17::i;:::-;6312:12;6326:18;6366:4;6351:26;;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6308:71;;;;;;;;;6395:25;6423:16;6458:4;6443:33;;;6491:11;6478:5;6486:1;6478:9;;;;:::i;:::-;6477:25;;;;:::i;:::-;6443:60;;;;;;;;;;11576:6:15;11564:19;;;6443:60:11;;;11546:38:15;11519:18;;6443:60:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6394:109;;;;;;6814:11;6809:80;;6853:36;;;;;6887:1;6853:36;;;1528:25:15;6853:33:11;;;;;;1501:18:15;;6853:36:11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;6827:62:11;;-1:-1:-1;;;6809:80:11;6975:36;;;;:15;:36;:::i;:::-;6969:42;;7049:3;7025:11;7037:1;7025:14;;;;;;;;:::i;:::-;;;;;;:28;;;;;;;;;;;7086:4;:15;;7125:31;;;7158:11;7102:68;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7086:85;;;;7102:68;7086:85;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7068:103:11;;-1:-1:-1;7068:103:11;-1:-1:-1;7068:103:11;7185:31;;7199:17;7211:4;7199:11;:17::i;:::-;5981:1246;;;;5967:1260;7332:30;7376:4;7365:27;;;;;;;;;;;;:::i;:::-;7332:60;;7459:10;7532:3;7500:15;7516:1;7500:18;;;;;;;;:::i;:::-;;;;;;;7479:15;7495:1;7479:18;;;;;;;;:::i;:::-;;;;;;;:39;;;;:::i;:::-;7478:59;;;;:::i;:::-;7459:79;;7549:20;7572:33;7600:4;7572:27;:33::i;:::-;7549:56;;7624:44;7643:10;7655:12;7624:44;;:18;:44::i;:::-;7616:58;7670:3;;-1:-1:-1;5586:2095:11;;-1:-1:-1;;;;;;;;;5586:2095:11:o;5504:3513:2:-;5682:34;;;;;5796:42;;;;;5753:40;;;:85;5907:31;;;;;;;5875:29;;;:63;;;5979:30;;;;;;;5948:28;;;:61;6045:25;;;;;5796:42;6019:23;;:51;6104:23;;;;;6080:21;;;:47;6162:24;;;;;6137:22;;;:49;6227:30;;;;;;;6196:28;;;:61;5796:42;6296:27;;;;;;;;6268:25;;;:55;6361:26;;;;;;;;6334:24;;;:53;6423:25;;;;;;-1:-1:-1;6397:23:2;;:51;6492:32;;;;-1:-1:-1;6459:30:2;;:65;6628:2;:23;;;6623:29;;;6045:25;6623:29;6585:35;;;:67;;;-1:-1:-1;;5907:31:2;6623:29;6697:53;;;;:::i;:::-;;6666:28;;;:84;6771:13;6787:40;6666:10;6821:4;6787:13;:40::i;:::-;6771:56;;6853:10;:28;;;6841:8;:40;6837:207;;6942:35;;;;6931:46;;6909:19;;;:68;6837:207;;;7032:1;7010:19;;;:23;6837:207;7130:10;:40;;;7111:59;;:15;:59;7107:1904;;7194:4;7186:12;;7213:11;7245:10;:40;;;7227:58;;:15;:58;;;;:::i;:::-;7213:72;;7335:27;7469:4;7435:10;:30;;;7366:66;7385:10;:23;;;7381:28;;7412:4;7381:35;;;;:::i;:::-;7419:6;7427:4;7366:9;:66::i;:::-;:99;;;;:::i;:::-;7365:108;;;;:::i;:::-;7335:138;;7488:20;7562:10;:30;;;7537:22;7511:10;:23;;;:48;;;;;;:::i;:::-;:81;;;;:::i;:::-;7632:25;;;;7695:24;;;;7488:104;;-1:-1:-1;7607:50:2;;;7671:48;;7607:22;7952:43;490:3:4;824:13;7952:43:2;:::i;:::-;7829:21;;;;7854:16;7829:41;;;;:87;;7895:10;:21;;;7829:87;;;923:20:4;7829:87:2;7751:166;;7770:10;:23;;;7752:41;;:15;:41;;;;:::i;:::-;7751:166;;;;:::i;:::-;:245;;;;:::i;:::-;7734:262;-1:-1:-1;8015:14:2;;8011:311;;8049:15;8090:41;490:3:4;8090:15:2;:41;:::i;:::-;8067:10;:19;;;:65;;;;:::i;:::-;8049:83;-1:-1:-1;8202:22:2;8215:9;8049:83;8202:22;:::i;:::-;8169:29;8182:16;8169:10;:29;:::i;:::-;:56;;;;:::i;:::-;8150:75;;8283:10;:24;;;8264:43;;:16;:43;;;;:::i;:::-;8243:64;;;;:::i;:::-;;;8031:291;8011:311;280:17:4;8420:35:2;;;;;:78;;-1:-1:-1;418:17:4;8459:39:2;;;8420:78;8416:585;;;8544:33;8561:15;8544:16;:33::i;:::-;8518:59;;:23;;;:59;8595:30;;;:55;;;8668:66;8718:15;8668:66;:40;;;:66;8777:24;;;;8757:44;;;;8753:234;;8853:36;8871:17;8853;:36::i;:::-;8825:64;;:25;;;:64;8938:30;8951:16;8938:12;:30::i;:::-;8911:57;;:24;;;:57;8753:234;7172:1839;;;;;;7107:1904;5648:3369;;5504:3513;;;;;:::o;11611:220::-;11712:4;11728:17;11748:31;11768:10;11748:19;:31::i;:::-;11728:51;-1:-1:-1;11820:4:2;11796:21;11728:51;11796:6;:21;:::i;:::-;:28;;;;:::i;:::-;11789:35;11611:220;-1:-1:-1;;;;11611:220:2:o;17666:298::-;17897:27;;;17795:4;17897:27;;;:18;;;:27;;;;;:32;490:3:4;;17818:113:2;;17830:10;;17842:88;;17897:18;;17830:10;;17897:27;;:32;;;;;17842:19;:88::i;:::-;17818:11;:113::i;:::-;:139;;;;:::i;:::-;17811:146;;17666:298;;;;;;:::o;953:3809:12:-;1065:14;;;1593:6;1590:1;1587;1580:20;1629:1;1626;1622:9;1613:18;;1680:5;1676:2;1673:13;1665:5;1661:2;1657:14;1653:34;1644:43;;;1769:5;1778:1;1769:10;1765:179;;;1817:1;1803:11;:15;1795:24;;;;;;-1:-1:-1;1870:23:12;;;;-1:-1:-1;1920:13:12;;1765:179;2071:5;2057:11;:19;2049:28;;;;;;2354:17;2430:11;2427:1;2424;2417:25;3727:1;2827;2812:12;;:16;;2797:32;;2924:22;;;;3708:1;:15;;3707:21;;3954:17;;;3950:21;;3943:28;4012:17;;;4008:21;;4001:28;4071:17;;;4067:21;;4060:28;4130:17;;;4126:21;;4119:28;4189:17;;;4185:21;;4178:28;4249:17;;;4245:21;;;4238:28;;;2782:12;3296;;;3292:23;;;3288:31;;;2559:20;;;2548:32;;;3347:12;;;;2602:21;;3052:16;;;;3338:21;;;;4713:11;;;-1:-1:-1;;;;953:3809:12:o;1558:2611:14:-;1621:20;1671:15;1696:1;1689:4;:8;;;:57;;1740:4;1733:12;;1689:57;;;1716:4;1709:12;;1708:13;;1689:57;1671:75;-1:-1:-1;840:9:14;1764:33;;;1756:47;;;;;;;23816:2:15;1756:47:14;;;23798:21:15;23855:1;23835:18;;;23828:29;23893:3;23873:18;;;23866:31;23914:18;;1756:47:14;23614:324:15;1756:47:14;1814:13;1840:3;1830:13;;:93;;1888:35;1830:93;;;1851:34;1830:93;1814:109;;;-1:-1:-1;1947:3:14;1937:13;;:18;1933:83;;1974:34;1966:42;2013:3;1965:51;1933:83;2040:3;2030:13;;:18;2026:83;;2067:34;2059:42;2106:3;2058:51;2026:83;2133:3;2123:13;;:18;2119:83;;2160:34;2152:42;2199:3;2151:51;2119:83;2226:4;2216:14;;:19;2212:84;;2254:34;2246:42;2293:3;2245:51;2212:84;2320:4;2310:14;;:19;2306:84;;2348:34;2340:42;2387:3;2339:51;2306:84;2414:4;2404:14;;:19;2400:84;;2442:34;2434:42;2481:3;2433:51;2400:84;2508:4;2498:14;;:19;2494:84;;2536:34;2528:42;2575:3;2527:51;2494:84;2602:5;2592:15;;:20;2588:85;;2631:34;2623:42;2670:3;2622:51;2588:85;2697:5;2687:15;;:20;2683:85;;2726:34;2718:42;2765:3;2717:51;2683:85;2792:5;2782:15;;:20;2778:85;;2821:34;2813:42;2860:3;2812:51;2778:85;2887:5;2877:15;;:20;2873:85;;2916:34;2908:42;2955:3;2907:51;2873:85;2982:6;2972:16;;:21;2968:86;;3012:34;3004:42;3051:3;3003:51;2968:86;3078:6;3068:16;;:21;3064:86;;3108:34;3100:42;3147:3;3099:51;3064:86;3174:6;3164:16;;:21;3160:86;;3204:34;3196:42;3243:3;3195:51;3160:86;3270:6;3260:16;;:21;3256:86;;3300:34;3292:42;3339:3;3291:51;3256:86;3366:7;3356:17;;:22;3352:86;;3397:33;3389:41;3435:3;3388:50;3352:86;3462:7;3452:17;;:22;3448:85;;3493:32;3485:40;3530:3;3484:49;3448:85;3557:7;3547:17;;:22;3543:83;;3588:30;3580:38;3623:3;3579:47;3543:83;3650:7;3640:17;;:22;3636:78;;3681:25;3673:33;3711:3;3672:42;3636:78;3736:1;3729:4;:8;;;3725:47;;;3767:5;3747:17;:25;;;;;:::i;:::-;;3739:33;;3725:47;4131:7;4122:5;:17;:22;:30;;4151:1;4122:30;;;4147:1;4122:30;4105:48;;4115:2;4106:5;:11;;4105:48;4082:72;;1651:2512;;1558:2611;;;:::o;11837:857:2:-;2125:4:0;2119:11;;12105:21:2;;:32:::1;24107:55:15::0;;;12150:58:2::1;::::0;;::::1;24089:74:15::0;;;;12150:58:2;;;;;;;;;;24062:18:15;;;12150:58:2;;::::1;::::0;::::1;::::0;;::::1;;12173:25:::0;12150:58:::1;::::0;;12105:104;;11938:4;;;;;;12105:32:::1;::::0;12143:5:::1;::::0;12105:104:::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12069:140;;;;12605:7;12604:8;:28;;;;12630:2;12616:4;:11;:16;12604:28;12600:42;;;12641:1;12634:8;;;;;;12600:42;12671:4;12660:27;;;;;;;;;;;;:::i;:::-;12653:34;;;;2150:1:0;2512:4:::0;2505:28;11837:857:2;;-1:-1:-1;;11837:857:2:o;835:1036:13:-;899:6;947:1;949:53;;;;1048:9;;;1058:20;;;;1094:1;1089:6;;1041:56;;1058:20;1072:4;1067:9;;1041:56;;1136:1;1130:4;1126:12;1191:1;1188;1184:9;1179:14;;1173:668;1196:1;1173:668;;;1255:1;1252;1248:9;1303:1;1299;1295:2;1291:10;1288:17;1278:44;;1318:1;1316;1309:11;1278:44;1366:4;1362:2;1358:13;1407:2;1398:7;1395:15;1392:34;;;1422:1;1420;1413:11;1392:34;1452:18;;;;-1:-1:-1;;1494:8:13;;;1491:332;;;1546:1;1543;1539:9;1621:1;1617;1613:2;1609:10;1606:17;1599:25;1594:1;1587:9;1580:17;1576:49;1573:68;;;1637:1;1635;1628:11;1573:68;1689:4;1685:2;1681:13;1734:2;1725:7;1722:15;1719:34;;;1749:1;1747;1740:11;1719:34;1783:18;;;;-1:-1:-1;;1491:332:13;1211:1;1209;1205:8;1200:13;;1173:668;;;1177:18;940:915;;949:53;964:1;966:18;;;;999:1;994:6;;957:44;;966:18;979:4;974:9;;957:44;940:915;;835:1036;;;;;:::o;10645:196:2:-;10707:7;418:17:4;10734:30:2;;;10726:76;;;;;;;24565:2:15;10726:76:2;;;24547:21:15;24604:2;24584:18;;;24577:30;24643:34;24623:18;;;24616:62;24714:3;24694:18;;;24687:31;24735:19;;10726:76:2;24363:397:15;10726:76:2;-1:-1:-1;10827:6:2;10645:196::o;10442:197::-;10505:6;350:16:4;10531:31:2;;;10523:78;;;;;;;24967:2:15;10523:78:2;;;24949:21:15;25006:2;24986:18;;;24979:30;25045:34;25025:18;;;25018:62;25116:4;25096:18;;;25089:32;25138:19;;10523:78:2;24765:398:15;10254:182:2;10312:7;280:17:4;10339:25:2;;;10331:66;;;;;;;25370:2:15;10331:66:2;;;25352:21:15;25409:2;25389:18;;;25382:30;25448;25428:18;;;25421:58;25496:18;;10331:66:2;25168:352:15;10847:276:2;10928:4;10948:10;:24;;;:29;;10976:1;10948:29;10944:46;;;-1:-1:-1;10986:4:2;;10847:276;-1:-1:-1;10847:276:2:o;10944:46::-;11092:10;:24;;;11007:109;;490:3:4;11031:10:2;:23;;;:49;;;;;;:::i;:::-;11008:10;:19;;;:73;;;;:::i;:::-;11007:82;;11085:4;11007:82;:::i;:::-;:109;;;;:::i;16531:461::-;16676:4;16751:9;16747:23;;-1:-1:-1;16769:1:2;16762:8;;16747:23;16938:27;;;;;;;:18;;;:27;;;;;:47;;;16905:30;;;;16898:37;;:4;:37;:::i;:::-;:87;;;;:::i;:::-;16891:94;16531:461;-1:-1:-1;;;;;16531:461:2:o;17290:304::-;17374:4;17394:9;17390:23;;-1:-1:-1;17412:1:2;17405:8;;17390:23;17487:35;;;;490:3:4;17461:61:2;;;17544:16;:12;;;:16;17461:61;17543:26;;;;:::i;:::-;;:34;;17290:304;-1:-1:-1;;;;17290:304:2:o;-1:-1:-1:-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:154:15;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;69:93;14:154;:::o;173:134::-;241:20;;270:31;241:20;270:31;:::i;312:247::-;371:6;424:2;412:9;403:7;399:23;395:32;392:52;;;440:1;437;430:12;392:52;479:9;466:23;498:31;523:5;498:31;:::i;853:271::-;645:12;;633:25;;707:4;696:16;;;690:23;674:14;;;667:47;763:4;752:16;;;746:23;730:14;;;723:47;833:4;822:16;;;816:23;809:31;802:39;786:14;;;779:63;1053:3;1038:19;;1066:52;564:284;2978:904;3213:2;3265:21;;;3335:13;;3238:18;;;3357:22;;;3184:4;;3213:2;3436:15;;;;3410:2;3395:18;;;3184:4;3479:377;3493:6;3490:1;3487:13;3479:377;;;3552:13;;3594:9;;3605:42;3590:58;3578:71;;3688:11;;3682:18;3713:61;3761:12;;;3682:18;651:5;645:12;640:3;633:25;707:4;700:5;696:16;690:23;683:4;678:3;674:14;667:47;763:4;756:5;752:16;746:23;739:4;734:3;730:14;723:47;833:4;826:5;822:16;816:23;809:31;802:39;795:4;790:3;786:14;779:63;;;564:284;3713:61;-1:-1:-1;3831:15:15;;;;3803:4;3794:14;;;;;3515:1;3508:9;3479:377;;;-1:-1:-1;3873:3:15;;2978:904;-1:-1:-1;;;;;;2978:904:15:o;3887:184::-;3939:77;3936:1;3929:88;4036:4;4033:1;4026:15;4060:4;4057:1;4050:15;4076:308;4182:66;4177:2;4171:4;4167:13;4163:86;4155:6;4151:99;4316:6;4304:10;4301:22;4280:18;4268:10;4265:34;4262:62;4259:88;;;4327:18;;:::i;:::-;4363:2;4356:22;-1:-1:-1;;4076:308:15:o;4389:250::-;4456:2;4450:9;4498:6;4486:19;;4535:18;4520:34;;4556:22;;;4517:62;4514:88;;;4582:18;;:::i;:::-;4618:2;4611:22;4389:250;:::o;4644:184::-;4712:20;;4772:30;4761:42;;4751:53;;4741:81;;4818:1;4815;4808:12;4833:192;4901:20;;4961:38;4950:50;;4940:61;;4930:89;;5015:1;5012;5005:12;5030:179;5097:20;;5157:26;5146:38;;5136:49;;5126:77;;5199:1;5196;5189:12;5214:165;5281:20;;5341:12;5330:24;;5320:35;;5310:63;;5369:1;5366;5359:12;5384:114;5468:4;5461:5;5457:16;5450:5;5447:27;5437:55;;5488:1;5485;5478:12;5503:130;5569:20;;5598:29;5569:20;5598:29;:::i;5638:121::-;5723:10;5716:5;5712:22;5705:5;5702:33;5692:61;;5749:1;5746;5739:12;5764:132;5831:20;;5860:30;5831:20;5860:30;:::i;5901:161::-;5967:20;;6027:2;6016:21;;;6006:32;;5996:60;;6052:1;6049;6042:12;6067:117;6152:6;6145:5;6141:18;6134:5;6131:29;6121:57;;6174:1;6171;6164:12;6189:132;6256:20;;6285:30;6256:20;6285:30;:::i;6326:118::-;6412:5;6405:13;6398:21;6391:5;6388:32;6378:60;;6434:1;6431;6424:12;6449:1066;6507:5;6555:4;6543:9;6538:3;6534:19;6530:30;6527:50;;;6573:1;6570;6563:12;6527:50;6606:2;6600:9;6648:4;6640:6;6636:17;6719:6;6707:10;6704:22;6683:18;6671:10;6668:34;6665:62;6662:88;;;6730:18;;:::i;:::-;6766:2;6759:22;6799:6;-1:-1:-1;6799:6:15;6829:23;;6861:33;6829:23;6861:33;:::i;:::-;6903:23;;6978:2;6963:18;;6950:32;6991:30;6950:32;6991:30;:::i;:::-;7049:2;7037:15;;7030:32;7114:2;7099:18;;7086:32;7127;7086;7127;:::i;:::-;7187:2;7175:15;;7168:32;7252:2;7237:18;;7224:32;7265;7224;7265;:::i;:::-;7325:2;7313:15;;7306:32;7390:3;7375:19;;7362:33;7439:8;7426:22;;7414:35;;7404:63;;7463:1;7460;7453:12;7404:63;7495:3;7483:16;;;;7476:33;6449:1066;;-1:-1:-1;;6449:1066:15:o;7520:1613::-;7644:6;7652;7696:9;7687:7;7683:23;7726:3;7722:2;7718:12;7715:32;;;7743:1;7740;7733:12;7715:32;7766:6;7792:2;7788;7784:11;7781:31;;;7808:1;7805;7798:12;7781:31;7834:17;;:::i;:::-;7821:30;;7874:29;7893:9;7874:29;:::i;:::-;7867:5;7860:44;7936:38;7970:2;7959:9;7955:18;7936:38;:::i;:::-;7931:2;7924:5;7920:14;7913:62;8007:38;8041:2;8030:9;8026:18;8007:38;:::i;:::-;8002:2;7995:5;7991:14;7984:62;8078:37;8111:2;8100:9;8096:18;8078:37;:::i;:::-;8073:2;8066:5;8062:14;8055:61;8177:3;8166:9;8162:19;8149:33;8143:3;8136:5;8132:15;8125:58;8216:38;8249:3;8238:9;8234:19;8216:38;:::i;:::-;8210:3;8203:5;8199:15;8192:63;8288:37;8320:3;8309:9;8305:19;8288:37;:::i;:::-;8282:3;8275:5;8271:15;8264:62;8359:38;8392:3;8381:9;8377:19;8359:38;:::i;:::-;8353:3;8346:5;8342:15;8335:63;8417:3;8452:36;8484:2;8473:9;8469:18;8452:36;:::i;:::-;8436:14;;;8429:60;8508:3;8543:37;8561:18;;;8543:37;:::i;:::-;8527:14;;;8520:61;8600:3;8635:37;8653:18;;;8635:37;:::i;:::-;8619:14;;;8612:61;8692:3;8727:37;8745:18;;;8727:37;:::i;:::-;8711:14;;;8704:61;8784:3;8832:18;;;8819:32;8803:14;;;8796:56;8871:3;8919:18;;;8906:32;8890:14;;;8883:56;8958:3;9006:18;;;8993:32;8977:14;;;8970:56;8715:5;;-1:-1:-1;8715:5:15;;9069:58;9119:7;9099:18;;;9069:58;:::i;:::-;9059:68;;;;7520:1613;;;;;:::o;9138:184::-;9190:77;9187:1;9180:88;9287:4;9284:1;9277:15;9311:4;9308:1;9301:15;9743:251;9813:6;9866:2;9854:9;9845:7;9841:23;9837:32;9834:52;;;9882:1;9879;9872:12;9834:52;9914:9;9908:16;9933:31;9958:5;9933:31;:::i;9999:305::-;10069:6;10122:2;10110:9;10101:7;10097:23;10093:32;10090:52;;;10138:1;10135;10128:12;10090:52;10170:9;10164:16;10220:34;10213:5;10209:46;10202:5;10199:57;10189:85;;10270:1;10267;10260:12;10309:184;10361:77;10358:1;10351:88;10458:4;10455:1;10448:15;10482:4;10479:1;10472:15;10498:195;10537:3;10568:66;10561:5;10558:77;10555:103;;;10638:18;;:::i;:::-;-1:-1:-1;10685:1:15;10674:13;;10498:195::o;11595:179::-;11630:3;11672:1;11654:16;11651:23;11648:120;;;11718:1;11715;11712;11697:23;-1:-1:-1;11755:1:15;11749:8;11744:3;11740:18;11648:120;11595:179;:::o;11779:731::-;11818:3;11860:4;11842:16;11839:26;11836:39;;;11779:731;:::o;11836:39::-;11902:2;11896:9;11924:66;12045:2;12027:16;12023:25;12020:1;12014:4;11999:50;12078:4;12072:11;12102:16;12137:18;12208:2;12201:4;12193:6;12189:17;12186:25;12181:2;12173:6;12170:14;12167:45;12164:58;;;12215:5;;;;;11779:731;:::o;12164:58::-;12252:6;12246:4;12242:17;12231:28;;12288:3;12282:10;12315:2;12307:6;12304:14;12301:27;;;12321:5;;;;;;11779:731;:::o;12301:27::-;12405:2;12386:16;12380:4;12376:27;12372:36;12365:4;12356:6;12351:3;12347:16;12343:27;12340:69;12337:82;;;12412:5;;;;;;11779:731;:::o;12337:82::-;12428:57;12479:4;12470:6;12462;12458:19;12454:30;12448:4;12428:57;:::i;12874:258::-;12946:1;12956:113;12970:6;12967:1;12964:13;12956:113;;;13046:11;;;13040:18;13027:11;;;13020:39;12992:2;12985:10;12956:113;;;13087:6;13084:1;13081:13;13078:48;;;13122:1;13113:6;13108:3;13104:16;13097:27;13078:48;;12874:258;;;:::o;13137:434::-;13399:17;13394:3;13387:30;13369:3;13446:6;13440:13;13462:62;13517:6;13512:2;13507:3;13503:12;13496:4;13488:6;13484:17;13462:62;:::i;:::-;13544:16;;;;13562:2;13540:25;;13137:434;-1:-1:-1;;13137:434:15:o;13576:442::-;13725:2;13714:9;13707:21;13688:4;13757:6;13751:13;13800:6;13795:2;13784:9;13780:18;13773:34;13816:66;13875:6;13870:2;13859:9;13855:18;13850:2;13842:6;13838:15;13816:66;:::i;:::-;13934:2;13922:15;13939:66;13918:88;13903:104;;;;14009:2;13899:113;;13576:442;-1:-1:-1;;13576:442:15:o;14023:1071::-;14137:6;14145;14153;14161;14169;14177;14185;14238:3;14226:9;14217:7;14213:23;14209:33;14206:53;;;14255:1;14252;14245:12;14206:53;14287:9;14281:16;14306:31;14331:5;14306:31;:::i;:::-;14356:5;14346:15;;;14406:2;14395:9;14391:18;14385:25;14455:7;14452:1;14441:22;14432:7;14429:35;14419:63;;14478:1;14475;14468:12;14419:63;14553:2;14538:18;;14532:25;14501:7;;-1:-1:-1;14566:32:15;14532:25;14566:32;:::i;:::-;14669:2;14654:18;;14648:25;14617:7;;-1:-1:-1;14682:32:15;14648:25;14682:32;:::i;:::-;14785:3;14770:19;;14764:26;14733:7;;-1:-1:-1;14799:32:15;14764:26;14799:32;:::i;:::-;14902:3;14887:19;;14881:26;14850:7;;-1:-1:-1;14916:31:15;14881:26;14916:31;:::i;:::-;15018:3;15003:19;;14997:26;14966:7;;-1:-1:-1;15032:30:15;14997:26;15032:30;:::i;:::-;15081:7;15071:17;;;14023:1071;;;;;;;;;;:::o;16158:228::-;16198:7;16324:1;16256:66;16252:74;16249:1;16246:81;16241:1;16234:9;16227:17;16223:105;16220:131;;;16331:18;;:::i;:::-;-1:-1:-1;16371:9:15;;16158:228::o;16391:184::-;16443:77;16440:1;16433:88;16540:4;16537:1;16530:15;16564:4;16561:1;16554:15;16580:120;16620:1;16646;16636:35;;16651:18;;:::i;:::-;-1:-1:-1;16685:9:15;;16580:120::o;16705:128::-;16745:3;16776:1;16772:6;16769:1;16766:13;16763:39;;;16782:18;;:::i;:::-;-1:-1:-1;16818:9:15;;16705:128::o;18481:647::-;18650:2;18702:21;;;18772:13;;18675:18;;;18794:22;;;18621:4;;18650:2;18873:15;;;;18847:2;18832:18;;;18621:4;18916:186;18930:6;18927:1;18924:13;18916:186;;;18995:13;;19010:10;18991:30;18979:43;;19077:15;;;;19042:12;;;;18952:1;18945:9;18916:186;;19133:274;19262:3;19300:6;19294:13;19316:53;19362:6;19357:3;19350:4;19342:6;19338:17;19316:53;:::i;:::-;19385:16;;;;;19133:274;-1:-1:-1;;19133:274:15:o;19743:224::-;19782:3;19810:6;19843:2;19840:1;19836:10;19873:2;19870:1;19866:10;19904:3;19900:2;19896:12;19891:3;19888:21;19885:47;;;19912:18;;:::i;:::-;19948:13;;19743:224;-1:-1:-1;;;;19743:224:15:o;19972:179::-;20003:1;20029:6;20062:2;20059:1;20055:10;20084:3;20074:37;;20091:18;;:::i;:::-;20129:10;;20125:20;;;;;19972:179;-1:-1:-1;;19972:179:15:o;20350:164::-;20427:13;;20480:1;20469:20;;;20459:31;;20449:59;;20504:1;20501;20494:12;20519:593;20610:6;20618;20626;20634;20687:3;20675:9;20666:7;20662:23;20658:33;20655:53;;;20704:1;20701;20694:12;20655:53;20736:9;20730:16;20755:30;20779:5;20755:30;:::i;:::-;20804:5;-1:-1:-1;20828:47:15;20871:2;20856:18;;20828:47;:::i;:::-;20818:57;;20920:2;20909:9;20905:18;20899:25;20933:33;20958:7;20933:33;:::i;:::-;21037:2;21022:18;;21016:25;20985:7;;-1:-1:-1;21050:30:15;21016:25;21050:30;:::i;:::-;20519:593;;;;-1:-1:-1;20519:593:15;;-1:-1:-1;;20519:593:15:o;21307:125::-;21347:4;21375:1;21372;21369:8;21366:34;;;21380:18;;:::i;:::-;-1:-1:-1;21417:9:15;;21307:125::o;21437:997::-;21530:6;21561:2;21604;21592:9;21583:7;21579:23;21575:32;21572:52;;;21620:1;21617;21610:12;21572:52;21653:9;21647:16;21682:18;21723:2;21715:6;21712:14;21709:34;;;21739:1;21736;21729:12;21709:34;21777:6;21766:9;21762:22;21752:32;;21822:7;21815:4;21811:2;21807:13;21803:27;21793:55;;21844:1;21841;21834:12;21793:55;21873:2;21867:9;21895:2;21891;21888:10;21885:36;;;21901:18;;:::i;:::-;21947:2;21944:1;21940:10;21930:20;;21979:2;21973:9;21991:40;22027:2;22023;22019:11;22011:6;21991:40;:::i;:::-;22066:18;;;22142:11;;;22138:20;;;22100:15;;;22170:19;;;22167:39;;;22202:1;22199;22192:12;22167:39;22226:11;;;;22246:157;22262:6;22257:3;22254:15;22246:157;;;22328:32;22356:3;22328:32;:::i;:::-;22316:45;;22279:12;;;;22381;;22246:157;;;-1:-1:-1;22422:6:15;21437:997;-1:-1:-1;;;;;;;21437:997:15:o;22439:404::-;22477:4;22521:1;22518;22507:16;22557:1;22554;22543:16;22587:1;22582:3;22578:11;22698:3;22630:66;22626:76;22621:3;22617:86;22612:2;22605:10;22601:103;22598:129;;;22707:18;;:::i;:::-;22778:3;22760:16;22756:26;22751:3;22747:36;22743:2;22739:45;22736:71;;;22787:18;;:::i;:::-;-1:-1:-1;22824:13:15;;;22439:404;-1:-1:-1;;;22439:404:15:o;22848:389::-;22886:1;22927;22924;22913:16;22963:1;22960;22949:16;22984:3;22974:37;;22991:18;;:::i;:::-;23112:66;23107:3;23104:75;23035:66;23030:3;23027:75;23023:157;23020:183;;;23183:18;;:::i;:::-;23217:14;;;22848:389;-1:-1:-1;;;22848:389:15:o;23242:367::-;23281:3;23316:1;23313;23309:9;23425:1;23357:66;23353:74;23350:1;23346:82;23341:2;23334:10;23330:99;23327:125;;;23432:18;;:::i;:::-;23551:1;23483:66;23479:74;23476:1;23472:82;23468:2;23464:91;23461:117;;;23558:18;;:::i;:::-;-1:-1:-1;;23594:9:15;;23242:367::o;24174:184::-;24244:6;24297:2;24285:9;24276:7;24272:23;24268:32;24265:52;;;24313:1;24310;24303:12;24265:52;-1:-1:-1;24336:16:15;;24174:184;-1:-1:-1;24174:184:15:o

Swarm Source

ipfs://49da3334e4e4abd0c5d85f3a1e678e0ca391f95c3fb85f584b53ad8f03a4f2cb

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

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