Contract

0xd6C90A7B61F3e0Ac04e2F4B0359aB0ac09035507

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
4343222024-12-15 7:51:1218 days ago1734249072  Contract Creation0 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FluidVaultResolver

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
paris EvmVersion
File 1 of 26 : main.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { Helpers } from "./helpers.sol";
import { TickMath } from "../../../libraries/tickMath.sol";
import { BigMathMinified } from "../../../libraries/bigMathMinified.sol";
import { IFluidOracle } from "../../../oracle/fluidOracle.sol";
import { IFluidVault } from "../../../protocols/vault/interfaces/iVault.sol";
import { IFluidVaultT1 } from "../../../protocols/vault/interfaces/iVaultT1.sol";
import { Structs as FluidLiquidityResolverStructs } from "../liquidity/structs.sol";
import { LiquiditySlotsLink } from "../../../libraries/liquiditySlotsLink.sol";
import { LiquidityCalcs } from "../../../libraries/liquidityCalcs.sol";
import { DexCalcs } from "../../../libraries/dexCalcs.sol";
import { DexSlotsLink } from "../../../libraries/dexSlotsLink.sol";
import { AddressCalcs } from "../../../libraries/addressCalcs.sol";
import { IFluidStorageReadable } from "./variables.sol";
import { FluidProtocolTypes } from "../../../libraries/fluidProtocolTypes.sol";

interface TokenInterface {
    function balanceOf(address) external view returns (uint);
}

/// @notice Fluid Vault protocol resolver
/// Implements various view-only methods to give easy access to Vault protocol data.
/// For vaults with Smart Col / Smart Debt from the Dex protocol, combine this data with Data fetched
/// from the DexResolver e.g. via MultiCall to fetch Vault limits, shares exchange rates etc. at the Dex.
contract FluidVaultResolver is Helpers {
    constructor(address factory_, address liquidityResolver_) Helpers(factory_, liquidityResolver_) {}

    /// @notice Get the address of a vault.
    /// @param vaultId_ The ID of the vault.
    /// @return vault_ The address of the vault.
    function getVaultAddress(uint vaultId_) public view returns (address vault_) {
        return AddressCalcs.addressCalc(address(FACTORY), vaultId_);
    }

    /// @notice Get the type of a vault.
    /// @param vault_ The address of the vault.
    /// @return vaultType_ The type of the vault. 0 if not a Fluid vault.
    function getVaultType(address vault_) public view returns (uint vaultType_) {
        if (vault_.code.length == 0) {
            return 0;
        }
        try IFluidVault(vault_).TYPE() returns (uint type_) {
            return type_;
        } catch {
            if (getVaultAddress(getVaultId(vault_)) != vault_) {
                return 0;
            }
            // if TYPE() is not available but address is valid vault id, it must be vault T1
            return FluidProtocolTypes.VAULT_T1_TYPE;
        }
    }

    /// @notice Get the ID of a vault.
    /// @param vault_ The address of the vault.
    /// @return id_ The ID of the vault.
    function getVaultId(address vault_) public view returns (uint id_) {
        id_ = IFluidVault(vault_).VAULT_ID();
    }

    /// @notice Get the token configuration.
    /// @param nftId_ The ID of the NFT.
    /// @return The token configuration.
    function getTokenConfig(uint nftId_) public view returns (uint) {
        return FACTORY.readFromStorage(calculateStorageSlotUintMapping(3, nftId_));
    }

    /// @notice Get the raw variables of a vault.
    /// @param vault_ The address of the vault.
    /// @return The raw variables of the vault.
    function getVaultVariablesRaw(address vault_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(normalSlot(0));
    }

    /// @notice Get the raw variables of a vault.
    /// @param vault_ The address of the vault.
    /// @return The raw variables of the vault.
    function getVaultVariables2Raw(address vault_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(normalSlot(1));
    }

    /// @notice Get the absorbed liquidity of a vault.
    /// @param vault_ The address of the vault.
    /// @return The absorbed liquidity of the vault.
    function getAbsorbedLiquidityRaw(address vault_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(normalSlot(2));
    }

    /// @notice Get the position data of a vault.
    /// @param vault_ The address of the vault.
    /// @param positionId_ The ID of the position.
    /// @return The position data of the vault.
    function getPositionDataRaw(address vault_, uint positionId_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(calculateStorageSlotUintMapping(3, positionId_));
    }

    /// @notice Get the raw tick data of a vault.
    /// @param vault_ The address of the vault.
    /// @param tick_ The tick value.
    /// @return The raw tick data of the vault.
    // if tick > 0 then key_ = tick / 256
    // if tick < 0 then key_ = (tick / 256) - 1
    function getTickDataRaw(address vault_, int tick_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(calculateStorageSlotIntMapping(5, tick_));
    }

    /// @notice Get the raw tick data of a vault.
    /// @param vault_ The address of the vault.
    /// @param key_ The tick key.
    /// @return The raw tick data of the vault.
    function getTickHasDebtRaw(address vault_, int key_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(calculateStorageSlotIntMapping(4, key_));
    }

    /// @notice Get the raw tick data of a vault.
    /// @param vault_ The address of the vault.
    /// @param tick_ The tick value.
    /// @param id_ The ID of the tick.
    /// @return The raw tick data of the vault.
    // id_ = (realId_ / 3) + 1
    function getTickIdDataRaw(address vault_, int tick_, uint id_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(calculateDoubleIntUintMapping(6, tick_, id_));
    }

    /// @notice Get the raw branch data of a vault.
    /// @param vault_ The address of the vault.
    /// @param branch_ The branch value.
    /// @return The raw branch data of the vault.
    function getBranchDataRaw(address vault_, uint branch_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(calculateStorageSlotUintMapping(7, branch_));
    }

    /// @notice Get the raw rate of a vault.
    /// @param vault_ The address of the vault.
    /// @return The raw rate of the vault.
    function getRateRaw(address vault_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(normalSlot(8));
    }

    /// @notice Get the rebalancer of a vault.
    /// @param vault_ The address of the vault.
    /// @return The rebalancer of the vault.
    function getRebalancer(address vault_) public view returns (address) {
        return address(uint160(IFluidVault(vault_).readFromStorage(normalSlot(9))));
    }

    /// @notice Get the absorbed dust debt of a vault.
    /// @param vault_ The address of the vault.
    /// @return The absorbed dust debt of the vault.
    function getAbsorbedDustDebt(address vault_) public view returns (uint) {
        return IFluidVault(vault_).readFromStorage(normalSlot(10));
    }

    /// @notice Get the DEX from address of a vault.
    /// @param vault_ The address of the vault.
    /// @return The DEX from address of the vault.
    function getDexFromAddress(address vault_) public view returns (address) {
        return address(uint160(IFluidVault(vault_).readFromStorage(normalSlot(11))));
    }

    /// @notice Get the total number of vaults.
    /// @return The total number of vaults.
    function getTotalVaults() public view returns (uint) {
        return FACTORY.totalVaults();
    }

    /// @notice Get the addresses of all the vaults.
    /// @return vaults_ The addresses of all the vaults.
    function getAllVaultsAddresses() public view returns (address[] memory vaults_) {
        uint totalVaults_ = getTotalVaults();
        vaults_ = new address[](totalVaults_);
        for (uint i = 0; i < totalVaults_; i++) {
            vaults_[i] = getVaultAddress((i + 1));
        }
    }

    /// @notice Get the contract for deployer index of a vault.
    /// @param vault_ The address of the vault.
    /// @param index_ The index of the deployer.
    /// @return The contract for deployer index of the vault.
    function getContractForDeployerIndex(address vault_, uint index_) public view returns (address) {
        IFluidVault.ConstantViews memory constants_ = _getVaultConstants(vault_, getVaultType(vault_));
        if (constants_.deployer == address(0) || index_ == 0) {
            return address(0);
        }
        return AddressCalcs.addressCalc(constants_.deployer, index_);
    }

    /// @dev Get the constants of a vault.
    /// @param vault_ The address of the vault.
    /// @param vaultType_ The type of the vault.
    /// @return constants_ The constants of the vault.
    function _getVaultConstants(
        address vault_,
        uint vaultType_
    ) internal view returns (IFluidVault.ConstantViews memory constants_) {
        if (vaultType_ == FluidProtocolTypes.VAULT_T1_TYPE) {
            try IFluidVaultT1(vault_).constantsView() returns (IFluidVaultT1.ConstantViews memory constantsT1_) {
                constants_.liquidity = constantsT1_.liquidity;
                constants_.factory = constantsT1_.factory;
                constants_.operateImplementation = address(vault_);
                constants_.adminImplementation = constantsT1_.adminImplementation;
                constants_.secondaryImplementation = constantsT1_.secondaryImplementation;
                constants_.deployer = address(0);
                constants_.supply = constantsT1_.liquidity;
                constants_.borrow = constantsT1_.liquidity;
                constants_.supplyToken.token0 = constantsT1_.supplyToken;
                constants_.supplyToken.token1 = address(0);
                constants_.borrowToken.token0 = constantsT1_.borrowToken;
                constants_.borrowToken.token1 = address(0);
                constants_.vaultId = constantsT1_.vaultId;
                constants_.vaultType = FluidProtocolTypes.VAULT_T1_TYPE;
                constants_.supplyExchangePriceSlot = constantsT1_.liquiditySupplyExchangePriceSlot;
                constants_.borrowExchangePriceSlot = constantsT1_.liquidityBorrowExchangePriceSlot;
                constants_.userSupplySlot = constantsT1_.liquidityUserSupplySlot;
                constants_.userBorrowSlot = constantsT1_.liquidityUserBorrowSlot;
            } catch {
                // vault address is likely not a fluid vault or not deployed yet etc.
                // vault type is detected as being T1 when TYPE() is not present, which could also happen
                // on non-Fluid-vault contracts
            }
        } else {
            constants_ = IFluidVault(vault_).constantsView();
        }
    }

    /// @dev Get the configuration of a vault.
    /// @param vault_ The address of the vault.
    /// @param vaultType_ The type of the vault.
    /// @return configs_ The configuration of the vault.
    function _getVaultConfig(address vault_, uint vaultType_) internal view returns (Configs memory configs_) {
        uint vaultVariables2_ = getVaultVariables2Raw(vault_);
        configs_.supplyRateMagnifier = uint16(vaultVariables2_ & X16);
        configs_.borrowRateMagnifier = uint16((vaultVariables2_ >> 16) & X16);
        configs_.collateralFactor = (uint16((vaultVariables2_ >> 32) & X10)) * 10;
        configs_.liquidationThreshold = (uint16((vaultVariables2_ >> 42) & X10)) * 10;
        configs_.liquidationMaxLimit = (uint16((vaultVariables2_ >> 52) & X10) * 10);
        configs_.withdrawalGap = uint16((vaultVariables2_ >> 62) & X10) * 10;
        configs_.liquidationPenalty = uint16((vaultVariables2_ >> 72) & X10);
        configs_.borrowFee = uint16((vaultVariables2_ >> 82) & X10);

        if (vaultType_ == FluidProtocolTypes.VAULT_T1_TYPE) {
            configs_.oracle = address(uint160(vaultVariables2_ >> 96));
        } else {
            /// Next 30 bits => 92-121 => bits to calculate address of oracle
            uint index_ = (vaultVariables2_ >> 92) & X30;
            if (index_ > 0) {
                configs_.oracle = getContractForDeployerIndex(vault_, index_);
            }
            /// Next 33 bits => 122-154 => last update timestamp
            configs_.lastUpdateTimestamp = uint((vaultVariables2_ >> 122) & X33);
        }

        if (configs_.oracle != address(0)) {
            try IFluidOracle(configs_.oracle).getExchangeRateOperate() returns (uint exchangeRate_) {
                configs_.oraclePriceOperate = exchangeRate_;
                configs_.oraclePriceLiquidate = IFluidOracle(configs_.oracle).getExchangeRateLiquidate();
            } catch {
                // deprecated backward compatible for older vaults oracles
                configs_.oraclePriceOperate = IFluidOracle(configs_.oracle).getExchangeRate();
                configs_.oraclePriceLiquidate = configs_.oraclePriceOperate;
            }
        }

        configs_.rebalancer = getRebalancer(vault_);
    }

    /// @dev Get the exchange prices and rates of a vault.
    /// @param vault_ The address of the vault.
    /// @param vaultType_ The type of the vault.
    /// @param configs_ The configuration of the vault.
    /// @param liquiditySupplyRate_ The liquidity supply rate, only set in case of NOT smart collateral.
    /// @param liquidityBorrowRate_ The liquidity borrow rate, only set in case of NOT smart debt.
    /// @return exchangePricesAndRates_ The exchange prices and rates of the vault.
    function _getExchangePricesAndRates(
        address vault_,
        uint vaultType_,
        Configs memory configs_,
        uint liquiditySupplyRate_,
        uint liquidityBorrowRate_
    ) internal view returns (ExchangePricesAndRates memory exchangePricesAndRates_) {
        uint exchangePrices_ = getRateRaw(vault_);
        exchangePricesAndRates_.lastStoredLiquiditySupplyExchangePrice = exchangePrices_ & X64;
        exchangePricesAndRates_.lastStoredLiquidityBorrowExchangePrice = (exchangePrices_ >> 64) & X64;
        exchangePricesAndRates_.lastStoredVaultSupplyExchangePrice = (exchangePrices_ >> 128) & X64;
        exchangePricesAndRates_.lastStoredVaultBorrowExchangePrice = (exchangePrices_ >> 192) & X64;

        (
            exchangePricesAndRates_.liquiditySupplyExchangePrice,
            exchangePricesAndRates_.liquidityBorrowExchangePrice,
            exchangePricesAndRates_.vaultSupplyExchangePrice,
            exchangePricesAndRates_.vaultBorrowExchangePrice
        ) = IFluidVault(vault_).updateExchangePrices(getVaultVariables2Raw(vault_));

        exchangePricesAndRates_.supplyRateLiquidity = liquiditySupplyRate_;
        exchangePricesAndRates_.borrowRateLiquidity = liquidityBorrowRate_;

        if (
            vaultType_ == FluidProtocolTypes.VAULT_T2_SMART_COL_TYPE ||
            vaultType_ == FluidProtocolTypes.VAULT_T4_SMART_COL_SMART_DEBT_TYPE
        ) {
            // in case of smart collateral supply magnifier bits stores supply interest rate positive or negative
            // negative meaning charging users, positive means incentivizing users
            exchangePricesAndRates_.supplyRateVault = int256((configs_.supplyRateMagnifier >> 1) & X15);
            // if first bit == 1 then positive else negative
            if ((configs_.supplyRateMagnifier & 1) == 0) {
                exchangePricesAndRates_.supplyRateVault = -exchangePricesAndRates_.supplyRateVault;
            }
            exchangePricesAndRates_.rewardsOrFeeRateSupply = exchangePricesAndRates_.supplyRateVault;
        } else {
            // NOT smart col
            unchecked {
                exchangePricesAndRates_.supplyRateVault = int256(
                    (liquiditySupplyRate_ * configs_.supplyRateMagnifier) / 10000
                );
                exchangePricesAndRates_.rewardsOrFeeRateSupply = int256(uint(configs_.supplyRateMagnifier)) - 10000;
            }
        }

        if (
            vaultType_ == FluidProtocolTypes.VAULT_T3_SMART_DEBT_TYPE ||
            vaultType_ == FluidProtocolTypes.VAULT_T4_SMART_COL_SMART_DEBT_TYPE
        ) {
            // in case of smart debt borrow magnifier bits stores borrow interest rate positive or negative
            // negative meaning incentivizing users, positive means charging users
            exchangePricesAndRates_.borrowRateVault = int256((configs_.borrowRateMagnifier >> 1) & X15);
            // if first bit == 1 then positive else negative
            if ((configs_.borrowRateMagnifier & 1) == 0) {
                exchangePricesAndRates_.borrowRateVault = -exchangePricesAndRates_.borrowRateVault;
            }
            exchangePricesAndRates_.rewardsOrFeeRateBorrow = exchangePricesAndRates_.borrowRateVault;
        } else {
            unchecked {
                // NOT smart debt
                exchangePricesAndRates_.borrowRateVault = int256(
                    (liquidityBorrowRate_ * configs_.borrowRateMagnifier) / 10000
                );
                exchangePricesAndRates_.rewardsOrFeeRateBorrow = int256(uint(configs_.borrowRateMagnifier)) - 10000;
            }
        }
    }

    /// @dev Get the total supply and borrow of a vault.
    /// @param vault_ The address of the vault.
    /// @param exchangePricesAndRates_ The exchange prices and rates of the vault.
    /// @param constantsVariables_ The constants and variables of the vault.
    /// @return totalSupplyAndBorrow_ The total supply and borrow of the vault.
    function _getTotalSupplyAndBorrow(
        address vault_,
        ExchangePricesAndRates memory exchangePricesAndRates_,
        IFluidVault.ConstantViews memory constantsVariables_
    ) internal view returns (TotalSupplyAndBorrow memory totalSupplyAndBorrow_) {
        uint vaultVariables_ = getVaultVariablesRaw(vault_);
        uint absorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);
        uint totalSupplyLiquidityOrDex_ = IFluidStorageReadable(constantsVariables_.supply).readFromStorage(
            constantsVariables_.userSupplySlot
        );
        // extracting user's supply
        if (constantsVariables_.supplyToken.token1 == address(0)) {
            totalSupplyLiquidityOrDex_ =
                (totalSupplyLiquidityOrDex_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) &
                X64;
        } else {
            totalSupplyLiquidityOrDex_ = (totalSupplyLiquidityOrDex_ >> DexSlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;
        }
        // converting big number into normal number
        totalSupplyLiquidityOrDex_ = (totalSupplyLiquidityOrDex_ >> 8) << (totalSupplyLiquidityOrDex_ & X8);

        uint totalBorrowLiquidityOrDex_ = IFluidStorageReadable(constantsVariables_.borrow).readFromStorage(
            constantsVariables_.userBorrowSlot
        );
        // extracting user's borrow
        if (constantsVariables_.borrowToken.token1 == address(0)) {
            totalBorrowLiquidityOrDex_ =
                (totalBorrowLiquidityOrDex_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) &
                X64;
        } else {
            totalBorrowLiquidityOrDex_ = (totalBorrowLiquidityOrDex_ >> DexSlotsLink.BITS_USER_BORROW_AMOUNT) & X64;
        }
        // converting big number into normal number
        totalBorrowLiquidityOrDex_ = (totalBorrowLiquidityOrDex_ >> 8) << (totalBorrowLiquidityOrDex_ & X8);

        totalSupplyAndBorrow_.totalSupplyVault = (vaultVariables_ >> 82) & X64;
        // Converting bignumber into normal number
        totalSupplyAndBorrow_.totalSupplyVault =
            (totalSupplyAndBorrow_.totalSupplyVault >> 8) <<
            (totalSupplyAndBorrow_.totalSupplyVault & X8);
        totalSupplyAndBorrow_.totalBorrowVault = (vaultVariables_ >> 146) & X64;
        // Converting bignumber into normal number
        totalSupplyAndBorrow_.totalBorrowVault =
            (totalSupplyAndBorrow_.totalBorrowVault >> 8) <<
            (totalSupplyAndBorrow_.totalBorrowVault & X8);

        totalSupplyAndBorrow_.totalSupplyLiquidityOrDex = totalSupplyLiquidityOrDex_;
        totalSupplyAndBorrow_.totalBorrowLiquidityOrDex = totalBorrowLiquidityOrDex_;

        totalSupplyAndBorrow_.absorbedBorrow = absorbedLiquidity_ & X128;
        totalSupplyAndBorrow_.absorbedSupply = absorbedLiquidity_ >> 128;

        unchecked {
            // converting raw total supply & total borrow into normal amounts
            totalSupplyAndBorrow_.totalSupplyVault =
                (totalSupplyAndBorrow_.totalSupplyVault * exchangePricesAndRates_.vaultSupplyExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            totalSupplyAndBorrow_.totalBorrowVault =
                (totalSupplyAndBorrow_.totalBorrowVault * exchangePricesAndRates_.vaultBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;

            // below logic multiply with liquidity exchange price also works for case of smart debt / smart col because
            // liquiditySupplyExchangePrice and liquidityBorrowExchangePrice will be EXCHANGE_PRICES_PRECISION
            totalSupplyAndBorrow_.totalSupplyLiquidityOrDex =
                (totalSupplyAndBorrow_.totalSupplyLiquidityOrDex *
                    exchangePricesAndRates_.liquiditySupplyExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            totalSupplyAndBorrow_.totalBorrowLiquidityOrDex =
                (totalSupplyAndBorrow_.totalBorrowLiquidityOrDex *
                    exchangePricesAndRates_.liquidityBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;

            totalSupplyAndBorrow_.absorbedSupply =
                (totalSupplyAndBorrow_.absorbedSupply * exchangePricesAndRates_.vaultSupplyExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            totalSupplyAndBorrow_.absorbedBorrow =
                (totalSupplyAndBorrow_.absorbedBorrow * exchangePricesAndRates_.vaultBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
        }
    }

    /// @dev Calculates limits and availability for a user's vault operations.
    /// @param exchangePricesAndRates_ Exchange prices and rates for the vault.
    /// @param constantsVariables_ Constants and variables for the vault.
    /// @param withdrawalGapConfig_ Configuration for the withdrawal gap.
    /// @param borrowLimit_ The borrow limit for the user. Only set if not smart debt.
    /// @param borrowLimitUtilization_ The utilization of the borrow limit. Only set if not smart debt.
    /// @param borrowableUntilLimit_ The limit until which borrowing is allowed. Only set if not smart debt.
    /// @param liquidityUserSupplyData_ User's supply data at Liquidity.
    /// @param liquidityUserBorrowData_ User's borrow data at Liquidity.
    /// @return limitsAndAvailability_ The calculated limits and availability for the user's vault operations.
    /// @return liquidityOrDexUserSupplyData_ The User's supply data at Liquidity OR dex.
    /// @return liquidityOrDexUserSupplyData_ The User's borrow data at Liquidity OR dex.
    function _getLimitsAndAvailability(
        ExchangePricesAndRates memory exchangePricesAndRates_,
        IFluidVault.ConstantViews memory constantsVariables_,
        uint withdrawalGapConfig_,
        uint borrowLimit_,
        uint borrowLimitUtilization_,
        uint borrowableUntilLimit_,
        FluidLiquidityResolverStructs.UserSupplyData memory liquidityUserSupplyData_,
        FluidLiquidityResolverStructs.UserBorrowData memory liquidityUserBorrowData_
    )
        internal
        view
        returns (
            LimitsAndAvailability memory limitsAndAvailability_,
            FluidLiquidityResolverStructs.UserSupplyData memory,
            FluidLiquidityResolverStructs.UserBorrowData memory
        )
    {
        // fetching user's supply slot data
        uint userSupplyLiquidityOrDexData_ = IFluidStorageReadable(constantsVariables_.supply).readFromStorage(
            constantsVariables_.userSupplySlot
        );
        if (userSupplyLiquidityOrDexData_ > 0) {
            {
                uint userSupply_;
                uint supplyLimitRaw_;
                if (constantsVariables_.supply == address(constantsVariables_.liquidity)) {
                    userSupply_ = (userSupplyLiquidityOrDexData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;
                    userSupply_ = (userSupply_ >> 8) << (userSupply_ & X8);

                    supplyLimitRaw_ = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(
                        userSupplyLiquidityOrDexData_,
                        userSupply_
                    );
                } else {
                    // smart col -> using Dex libraries
                    userSupply_ = (userSupplyLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;
                    userSupply_ = (userSupply_ >> 8) << (userSupply_ & X8);

                    supplyLimitRaw_ = DexCalcs.calcWithdrawalLimitBeforeOperate(
                        userSupplyLiquidityOrDexData_,
                        userSupply_
                    );

                    liquidityUserSupplyData_.modeWithInterest = false;
                    liquidityUserSupplyData_.supply = userSupply_;
                    liquidityUserSupplyData_.lastUpdateTimestamp =
                        (userSupplyLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) &
                        X33;
                    liquidityUserSupplyData_.expandPercent =
                        (userSupplyLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) &
                        X14;
                    liquidityUserSupplyData_.expandDuration =
                        (userSupplyLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) &
                        X24;
                }

                unchecked {
                    // liquiditySupplyExchangePrice is EXCHANGE_PRICES_PRECISION in case of smart col
                    limitsAndAvailability_.withdrawLimit =
                        (supplyLimitRaw_ * exchangePricesAndRates_.liquiditySupplyExchangePrice) /
                        EXCHANGE_PRICES_PRECISION;

                    // totalSupplyLiquidityOrDex = user supply
                    limitsAndAvailability_.withdrawableUntilLimit = userSupply_ > limitsAndAvailability_.withdrawLimit
                        ? userSupply_ - limitsAndAvailability_.withdrawLimit
                        : 0;

                    uint withdrawalGap_ = limitsAndAvailability_.withdrawLimit == 0
                        ? 0 // apply withdrawal gap only if withdraw limit is actually active (not below base limit)
                        : (userSupply_ * withdrawalGapConfig_) / 1e4;

                    limitsAndAvailability_.withdrawableUntilLimit = (limitsAndAvailability_.withdrawableUntilLimit >
                        withdrawalGap_)
                        ? (((limitsAndAvailability_.withdrawableUntilLimit - withdrawalGap_) * 999999) / 1000000)
                        : 0;
                }
            }

            limitsAndAvailability_.withdrawable = limitsAndAvailability_.withdrawableUntilLimit;
            if (constantsVariables_.supplyToken.token1 == address(0)) {
                // NOT smart col -> check withdrawableUntilLimit against available balance at Liquidity
                // if smart col -> must check manually against balances using data returned at DexResolver
                uint balanceOf_;
                if (constantsVariables_.supplyToken.token0 == NATIVE_TOKEN_ADDRESS) {
                    balanceOf_ = address(constantsVariables_.liquidity).balance;
                } else {
                    balanceOf_ = TokenInterface(constantsVariables_.supplyToken.token0).balanceOf(
                        address(constantsVariables_.liquidity)
                    );
                }
                if (balanceOf_ < limitsAndAvailability_.withdrawableUntilLimit) {
                    limitsAndAvailability_.withdrawable = balanceOf_;
                }
            } else {
                // mirror limits in liquidityUserSupplyData_
                liquidityUserSupplyData_.withdrawalLimit = limitsAndAvailability_.withdrawLimit;
                // exchange price for SC is 1 so no conversion needed for base withdrawal limit
                liquidityUserSupplyData_.baseWithdrawalLimit = BigMathMinified.fromBigNumber(
                    (userSupplyLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18,
                    8,
                    X8
                );
                liquidityUserSupplyData_.withdrawableUntilLimit = limitsAndAvailability_.withdrawableUntilLimit;
                liquidityUserSupplyData_.withdrawable = limitsAndAvailability_.withdrawable;
            }
        }

        uint userBorrowLiquidityOrDexData_ = IFluidStorageReadable(constantsVariables_.borrow).readFromStorage(
            constantsVariables_.userBorrowSlot
        );
        if (userBorrowLiquidityOrDexData_ > 0) {
            if (constantsVariables_.borrowToken.token1 == address(0)) {
                // NOT smart debt. fetch limit from LiquidityResolver

                limitsAndAvailability_.borrowLimit = borrowLimit_;
                limitsAndAvailability_.borrowLimitUtilization = borrowLimitUtilization_;

                unchecked {
                    limitsAndAvailability_.borrowableUntilLimit = (borrowableUntilLimit_ * 999999) / 1000000;
                }

                uint balanceOf_;
                if (constantsVariables_.borrowToken.token0 == NATIVE_TOKEN_ADDRESS) {
                    balanceOf_ = address(constantsVariables_.liquidity).balance;
                } else {
                    balanceOf_ = TokenInterface(constantsVariables_.borrowToken.token0).balanceOf(
                        address(constantsVariables_.liquidity)
                    );
                }
                limitsAndAvailability_.borrowable = balanceOf_ > limitsAndAvailability_.borrowableUntilLimit
                    ? limitsAndAvailability_.borrowableUntilLimit
                    : balanceOf_;
            } else {
                // smart debt -> using Dex libraries
                uint userBorrow_ = (userBorrowLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_BORROW_AMOUNT) & X64;
                userBorrow_ = (userBorrow_ >> 8) << (userBorrow_ & X8);

                limitsAndAvailability_.borrowLimit = DexCalcs.calcBorrowLimitBeforeOperate(
                    userBorrowLiquidityOrDexData_,
                    userBorrow_
                );

                unchecked {
                    limitsAndAvailability_.borrowableUntilLimit = limitsAndAvailability_.borrowLimit > userBorrow_
                        ? limitsAndAvailability_.borrowLimit - userBorrow_
                        : 0;

                    limitsAndAvailability_.borrowableUntilLimit =
                        (limitsAndAvailability_.borrowableUntilLimit * 999999) /
                        1000000;
                }

                limitsAndAvailability_.borrowable = limitsAndAvailability_.borrowableUntilLimit;

                liquidityUserBorrowData_.modeWithInterest = false;
                liquidityUserBorrowData_.borrow = userBorrow_;
                liquidityUserBorrowData_.borrowLimit = limitsAndAvailability_.borrowLimit;
                liquidityUserBorrowData_.borrowableUntilLimit = limitsAndAvailability_.borrowableUntilLimit;
                liquidityUserBorrowData_.borrowable = limitsAndAvailability_.borrowable;

                liquidityUserBorrowData_.lastUpdateTimestamp =
                    (userBorrowLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) &
                    X33;
                liquidityUserBorrowData_.expandPercent =
                    (userBorrowLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) &
                    X14;
                liquidityUserBorrowData_.expandDuration =
                    (userBorrowLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_BORROW_EXPAND_DURATION) &
                    X24;

                liquidityUserBorrowData_.baseBorrowLimit = BigMathMinified.fromBigNumber(
                    (userBorrowLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18,
                    8,
                    X8
                );
                liquidityUserBorrowData_.maxBorrowLimit = BigMathMinified.fromBigNumber(
                    (userBorrowLiquidityOrDexData_ >> DexSlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18,
                    8,
                    X8
                );
            }
        }

        limitsAndAvailability_.minimumBorrowing =
            (10001 * exchangePricesAndRates_.vaultBorrowExchangePrice) /
            EXCHANGE_PRICES_PRECISION;

        return (limitsAndAvailability_, liquidityUserSupplyData_, liquidityUserBorrowData_);
    }

    /// @notice Retrieves the state of a given vault.
    /// @param vault_ The address of the vault to retrieve the state for.
    /// @return vaultState_ The state of the vault, including top tick, current and total branches,
    ///                     total supply and borrow, total positions, and current branch state.
    function getVaultState(address vault_) public view returns (VaultState memory vaultState_) {
        uint vaultVariables_ = getVaultVariablesRaw(vault_);

        vaultState_.topTick = tickHelper(((vaultVariables_ >> 2) & X20));
        vaultState_.currentBranch = (vaultVariables_ >> 22) & X30;
        vaultState_.totalBranch = (vaultVariables_ >> 52) & X30;
        vaultState_.totalSupply = BigMathMinified.fromBigNumber((vaultVariables_ >> 82) & X64, 8, X8);
        vaultState_.totalBorrow = BigMathMinified.fromBigNumber((vaultVariables_ >> 146) & X64, 8, X8);
        vaultState_.totalPositions = (vaultVariables_ >> 210) & X32;

        uint currentBranchData_ = getBranchDataRaw(vault_, vaultState_.currentBranch);
        vaultState_.currentBranchState.status = currentBranchData_ & 3;
        vaultState_.currentBranchState.minimaTick = tickHelper(((currentBranchData_ >> 2) & X20));
        vaultState_.currentBranchState.debtFactor = (currentBranchData_ >> 116) & X50;
        vaultState_.currentBranchState.partials = (currentBranchData_ >> 22) & X30;
        vaultState_.currentBranchState.debtLiquidity = BigMathMinified.fromBigNumber(
            (currentBranchData_ >> 52) & X64,
            8,
            X8
        );
        vaultState_.currentBranchState.baseBranchId = (currentBranchData_ >> 166) & X30;
        vaultState_.currentBranchState.baseBranchMinima = tickHelper(((currentBranchData_ >> 196) & X20));
    }

    /// @notice Retrieves the entire data for a given vault.
    /// @param vault_ The address of the vault to retrieve the data for.
    /// @return vaultData_ The entire data of the vault.
    function getVaultEntireData(address vault_) public view returns (VaultEntireData memory vaultData_) {
        vaultData_.vault = vault_;
        uint vaultType_ = getVaultType(vault_);

        if (vaultType_ != 0) {
            vaultData_.constantVariables = _getVaultConstants(vault_, vaultType_);

            vaultData_.isSmartCol = vaultData_.constantVariables.supplyToken.token1 != address(0);
            vaultData_.isSmartDebt = vaultData_.constantVariables.borrowToken.token1 != address(0);

            // in case of NOT smart debt, the borrow limits are fetched from liquidity resolver
            uint borrowLimit_;
            uint borrowLimitUtilization_;
            uint borrowableUntilLimit_;

            {
                uint liquiditySupplyRate_;
                uint liquidityBorrowRate_;
                if (!vaultData_.isSmartCol) {
                    // NOT smart col
                    (
                        FluidLiquidityResolverStructs.UserSupplyData memory liquidityUserSupplyData_,
                        FluidLiquidityResolverStructs.OverallTokenData memory liquiditySupplyTokenData_
                    ) = LIQUIDITY_RESOLVER.getUserSupplyData(vault_, vaultData_.constantVariables.supplyToken.token0);

                    vaultData_.liquidityUserSupplyData = liquidityUserSupplyData_;

                    liquiditySupplyRate_ = liquiditySupplyTokenData_.supplyRate;
                }

                if (!vaultData_.isSmartDebt) {
                    // NOT smart debt
                    (
                        FluidLiquidityResolverStructs.UserBorrowData memory liquidityUserBorrowData_,
                        FluidLiquidityResolverStructs.OverallTokenData memory liquidityBorrowTokenData_
                    ) = LIQUIDITY_RESOLVER.getUserBorrowData(vault_, vaultData_.constantVariables.borrowToken.token0);

                    vaultData_.liquidityUserBorrowData = liquidityUserBorrowData_;

                    liquidityBorrowRate_ = liquidityBorrowTokenData_.borrowRate;

                    borrowLimit_ = liquidityUserBorrowData_.borrowLimit;
                    borrowLimitUtilization_ = liquidityUserBorrowData_.borrowLimitUtilization;
                    borrowableUntilLimit_ = liquidityUserBorrowData_.borrowableUntilLimit;
                }

                vaultData_.configs = _getVaultConfig(vault_, vaultData_.constantVariables.vaultType);
                vaultData_.exchangePricesAndRates = _getExchangePricesAndRates(
                    vault_,
                    vaultType_,
                    vaultData_.configs,
                    liquiditySupplyRate_,
                    liquidityBorrowRate_
                );
            }
            vaultData_.totalSupplyAndBorrow = _getTotalSupplyAndBorrow(
                vault_,
                vaultData_.exchangePricesAndRates,
                vaultData_.constantVariables
            );
            (
                vaultData_.limitsAndAvailability,
                vaultData_.liquidityUserSupplyData,
                vaultData_.liquidityUserBorrowData
            ) = _getLimitsAndAvailability(
                vaultData_.exchangePricesAndRates,
                vaultData_.constantVariables,
                vaultData_.configs.withdrawalGap,
                borrowLimit_,
                borrowLimitUtilization_,
                borrowableUntilLimit_,
                vaultData_.liquidityUserSupplyData,
                vaultData_.liquidityUserBorrowData
            );
            vaultData_.vaultState = getVaultState(vault_);
        }
    }

    /// @notice Retrieves the entire data for a list of vaults.
    /// @param vaults_ The list of vault addresses.
    /// @return vaultsData_ An array of VaultEntireData structures containing the data for each vault.
    function getVaultsEntireData(
        address[] memory vaults_
    ) external view returns (VaultEntireData[] memory vaultsData_) {
        uint length_ = vaults_.length;
        vaultsData_ = new VaultEntireData[](length_);
        for (uint i; i < length_; i++) {
            vaultsData_[i] = getVaultEntireData(vaults_[i]);
        }
    }

    /// @notice Retrieves the entire data for all vaults.
    /// @return vaultsData_ An array of VaultEntireData structures containing the data for each vault.
    function getVaultsEntireData() external view returns (VaultEntireData[] memory vaultsData_) {
        address[] memory vaults_ = getAllVaultsAddresses();
        uint length_ = vaults_.length;
        vaultsData_ = new VaultEntireData[](length_);
        for (uint i; i < length_; i++) {
            vaultsData_[i] = getVaultEntireData(vaults_[i]);
        }
    }

    /// @notice Retrieves the position data for a given NFT ID and the corresponding vault data.
    /// @param nftId_ The NFT ID for which to retrieve the position data.
    /// @return userPosition_ The UserPosition structure containing the position data.
    /// @return vaultData_ The VaultEntireData structure containing the vault data.
    function positionByNftId(
        uint nftId_
    ) public view returns (UserPosition memory userPosition_, VaultEntireData memory vaultData_) {
        userPosition_.nftId = nftId_;
        address vault_ = vaultByNftId(nftId_);
        if (vault_ != address(0)) {
            uint positionData_ = getPositionDataRaw(vault_, nftId_);
            vaultData_ = getVaultEntireData(vault_);

            userPosition_.owner = FACTORY.ownerOf(nftId_);
            userPosition_.isSupplyPosition = (positionData_ & 1) == 1;
            userPosition_.supply = (positionData_ >> 45) & X64;
            // Converting big number into normal number
            userPosition_.supply = (userPosition_.supply >> 8) << (userPosition_.supply & X8);
            userPosition_.beforeSupply = userPosition_.supply;
            userPosition_.dustBorrow = (positionData_ >> 109) & X64;
            // Converting big number into normal number
            userPosition_.dustBorrow = (userPosition_.dustBorrow >> 8) << (userPosition_.dustBorrow & X8);
            userPosition_.beforeDustBorrow = userPosition_.dustBorrow;
            if (!userPosition_.isSupplyPosition) {
                userPosition_.tick = (positionData_ & 2) == 2
                    ? int((positionData_ >> 2) & X19)
                    : -int((positionData_ >> 2) & X19);
                userPosition_.tickId = (positionData_ >> 21) & X24;
                userPosition_.borrow =
                    (TickMath.getRatioAtTick(int24(userPosition_.tick)) * userPosition_.supply) >>
                    96;
                userPosition_.beforeBorrow = userPosition_.borrow - userPosition_.beforeDustBorrow;

                uint tickData_ = getTickDataRaw(vault_, userPosition_.tick);

                if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > userPosition_.tickId)) {
                    // user got liquidated
                    userPosition_.isLiquidated = true;
                    (userPosition_.tick, userPosition_.borrow, userPosition_.supply, , ) = IFluidVault(vault_)
                        .fetchLatestPosition(userPosition_.tick, userPosition_.tickId, userPosition_.borrow, tickData_);
                }

                if (userPosition_.borrow > userPosition_.dustBorrow) {
                    userPosition_.borrow = userPosition_.borrow - userPosition_.dustBorrow;
                } else {
                    userPosition_.borrow = 0;
                    userPosition_.dustBorrow = 0;
                }
            }

            // converting raw amounts into normal
            userPosition_.beforeSupply =
                (userPosition_.beforeSupply * vaultData_.exchangePricesAndRates.vaultSupplyExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            userPosition_.beforeBorrow =
                (userPosition_.beforeBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            userPosition_.beforeDustBorrow =
                (userPosition_.beforeDustBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            userPosition_.supply =
                (userPosition_.supply * vaultData_.exchangePricesAndRates.vaultSupplyExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            userPosition_.borrow =
                (userPosition_.borrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
            userPosition_.dustBorrow =
                (userPosition_.dustBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /
                EXCHANGE_PRICES_PRECISION;
        }
    }

    /// @notice Returns an array of NFT IDs for all positions of a given user.
    /// @param user_ The address of the user for whom to fetch positions.
    /// @return nftIds_ An array of NFT IDs representing the user's positions.
    function positionsNftIdOfUser(address user_) public view returns (uint[] memory nftIds_) {
        uint totalPositions_ = FACTORY.balanceOf(user_);
        nftIds_ = new uint[](totalPositions_);
        for (uint i; i < totalPositions_; i++) {
            nftIds_[i] = FACTORY.tokenOfOwnerByIndex(user_, i);
        }
    }

    /// @notice Returns the vault address associated with a given NFT ID.
    /// @param nftId_ The NFT ID for which to fetch the vault address.
    /// @return vault_ The address of the vault associated with the NFT ID.
    function vaultByNftId(uint nftId_) public view returns (address vault_) {
        uint tokenConfig_ = getTokenConfig(nftId_);
        vault_ = FACTORY.getVaultAddress((tokenConfig_ >> 192) & X32);
    }

    /// @notice Fetches all positions and their corresponding vault data for a given user.
    /// @param user_ The address of the user for whom to fetch positions and vault data.
    /// @return userPositions_ An array of UserPosition structs representing the user's positions.
    /// @return vaultsData_ An array of VaultEntireData structs representing the vault data for each position.
    function positionsByUser(
        address user_
    ) external view returns (UserPosition[] memory userPositions_, VaultEntireData[] memory vaultsData_) {
        uint[] memory nftIds_ = positionsNftIdOfUser(user_);
        uint length_ = nftIds_.length;
        userPositions_ = new UserPosition[](length_);
        vaultsData_ = new VaultEntireData[](length_);
        for (uint i = 0; i < length_; i++) {
            (userPositions_[i], vaultsData_[i]) = positionByNftId(nftIds_[i]);
        }
    }

    /// @notice Returns the total number of positions across all users.
    /// @return The total number of positions.
    function totalPositions() external view returns (uint) {
        return FACTORY.totalSupply();
    }

    /// @notice fetches available liquidations
    /// @param vault_ address of vault for which to fetch
    /// @param tokenInAmt_ token in aka debt to payback, leave 0 to get max
    /// @return liquidationData_ liquidation related data. Check out structs.sol
    function getVaultLiquidation(
        address vault_,
        uint tokenInAmt_
    ) public returns (LiquidationStruct memory liquidationData_) {
        tokenInAmt_ = tokenInAmt_ == 0 ? X128 : tokenInAmt_;

        uint vaultType_ = getVaultType(vault_);
        if (vaultType_ != 0) {
            liquidationData_.vault = vault_;
            IFluidVault.ConstantViews memory constants_ = _getVaultConstants(vault_, vaultType_);

            if (constants_.vaultType == FluidProtocolTypes.VAULT_T1_TYPE) {
                liquidationData_.token0In = constants_.borrowToken.token0;
                liquidationData_.token0Out = constants_.supplyToken.token0;

                // running without absorb
                try IFluidVaultT1(vault_).liquidate(tokenInAmt_, 0, 0x000000000000000000000000000000000000dEaD, false) {
                    // Handle successful execution
                } catch Error(string memory) {
                    // Handle generic errors with a reason
                } catch (bytes memory lowLevelData_) {
                    (liquidationData_.inAmt, liquidationData_.outAmt) = _decodeLiquidationResult(lowLevelData_);
                }

                // running with absorb
                try IFluidVaultT1(vault_).liquidate(tokenInAmt_, 0, 0x000000000000000000000000000000000000dEaD, true) {
                    // Handle successful execution
                } catch Error(string memory) {
                    // Handle generic errors with a reason
                } catch (bytes memory lowLevelData_) {
                    (liquidationData_.inAmtWithAbsorb, liquidationData_.outAmtWithAbsorb) = _decodeLiquidationResult(
                        lowLevelData_
                    );
                }
            } else {
                liquidationData_.token0In = constants_.borrowToken.token0;
                liquidationData_.token0Out = constants_.supplyToken.token0;
                liquidationData_.token1In = constants_.borrowToken.token1;
                liquidationData_.token1Out = constants_.supplyToken.token1;

                // running without absorb
                try IFluidVault(vault_).simulateLiquidate(0, false) {
                    // Handle successful execution
                } catch Error(string memory) {
                    // Handle generic errors with a reason
                } catch (bytes memory lowLevelData_) {
                    (liquidationData_.inAmt, liquidationData_.outAmt) = _decodeLiquidationResult(lowLevelData_);
                }

                // running with absorb
                try IFluidVault(vault_).simulateLiquidate(0, true) {
                    // Handle successful execution
                } catch Error(string memory) {
                    // Handle generic errors with a reason
                } catch (bytes memory lowLevelData_) {
                    (liquidationData_.inAmtWithAbsorb, liquidationData_.outAmtWithAbsorb) = _decodeLiquidationResult(
                        lowLevelData_
                    );
                }
            }

            liquidationData_.absorbAvailable =
                liquidationData_.inAmtWithAbsorb > liquidationData_.inAmt ||
                liquidationData_.outAmtWithAbsorb > liquidationData_.outAmt;
        }
    }

    /// @dev helper method to decode liquidation result revert data
    function _decodeLiquidationResult(bytes memory lowLevelData_) internal pure returns (uint amtIn_, uint amtOut_) {
        // Check if the error data is long enough to contain a selector
        if (lowLevelData_.length >= 68) {
            bytes4 errorSelector_;
            assembly {
                // Extract the selector from the error data
                errorSelector_ := mload(add(lowLevelData_, 0x20))
            }
            if (errorSelector_ == IFluidVault.FluidLiquidateResult.selector) {
                assembly {
                    amtOut_ := mload(add(lowLevelData_, 36))
                    amtIn_ := mload(add(lowLevelData_, 68))
                }
            } // else -> tokenInAmtTwo & tokenOutAmtTwo remains 0
        }
    }

    /// @notice Retrieves liquidation data for multiple vaults.
    /// @param vaults_ The array of vault addresses.
    /// @param tokensInAmt_ The array of token amounts to liquidate.
    /// @return liquidationsData_ An array of LiquidationStruct containing the liquidation data for each vault.
    function getMultipleVaultsLiquidation(
        address[] memory vaults_,
        uint[] memory tokensInAmt_
    ) external returns (LiquidationStruct[] memory liquidationsData_) {
        uint length_ = vaults_.length;
        liquidationsData_ = new LiquidationStruct[](length_);
        for (uint i = 0; i < length_; i++) {
            liquidationsData_[i] = getVaultLiquidation(vaults_[i], tokensInAmt_[i]);
        }
    }

    /// @notice Retrieves liquidation data for all vaults.
    /// @return liquidationsData_ An array of LiquidationStruct containing the liquidation data for all vaults.
    function getAllVaultsLiquidation() external returns (LiquidationStruct[] memory liquidationsData_) {
        address[] memory vaults_ = getAllVaultsAddresses();
        uint length_ = vaults_.length;

        liquidationsData_ = new LiquidationStruct[](length_);
        for (uint i = 0; i < length_; i++) {
            liquidationsData_[i] = getVaultLiquidation(vaults_[i], 0);
        }
    }

    /// @notice DEPRECATED, only works for vaults v1.0.0: Retrieves absorb data for a single vault.
    /// @param vault_ The address of the vault.
    /// @return absorbData_ The AbsorbStruct containing the absorb data for the vault.
    function getVaultAbsorb(address vault_) public returns (AbsorbStruct memory absorbData_) {
        absorbData_.vault = vault_;
        uint absorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);
        try IFluidVaultT1(vault_).absorb() {
            // Handle successful execution
            uint newAbsorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);
            if (newAbsorbedLiquidity_ != absorbedLiquidity_) {
                absorbData_.absorbAvailable = true;
            }
        } catch Error(string memory) {} catch (bytes memory) {}
    }

    /// @notice DEPRECATED, only works for vaults v1.0.0: Retrieves absorb data for multiple vaults.
    /// @param vaults_ The array of vault addresses.
    /// @return absorbData_ An array of AbsorbStruct containing the absorb data for each vault.
    function getVaultsAbsorb(address[] memory vaults_) public returns (AbsorbStruct[] memory absorbData_) {
        uint length_ = vaults_.length;
        absorbData_ = new AbsorbStruct[](length_);
        for (uint i = 0; i < length_; i++) {
            absorbData_[i] = getVaultAbsorb(vaults_[i]);
        }
    }

    /// @notice DEPRECATED, only works for vaults v1.0.0: Retrieves absorb data for all vaults.
    /// @return absorbData_ An array of AbsorbStruct containing the absorb data for all vaults.
    function getVaultsAbsorb() public returns (AbsorbStruct[] memory absorbData_) {
        return getVaultsAbsorb(getAllVaultsAddresses());
    }
}

File 2 of 26 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

File 3 of 26 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

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

pragma solidity ^0.8.0;

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

File 5 of 26 : addressCalcs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @notice implements calculation of address for contracts deployed through CREATE.
/// Accepts contract deployed from which address & nonce
library AddressCalcs {

    /// @notice                         Computes the address of a contract based
    /// @param deployedFrom_            Address from which the contract was deployed
    /// @param nonce_                   Nonce at which the contract was deployed
    /// @return contract_               Address of deployed contract
    function addressCalc(address deployedFrom_, uint nonce_) internal pure returns (address contract_) {
        // @dev based on https://ethereum.stackexchange.com/a/61413

        // nonce of smart contract always starts with 1. so, with nonce 0 there won't be any deployment
        // hence, nonce of vault deployment starts with 1.
        bytes memory data;
        if (nonce_ == 0x00) {
            return address(0);
        } else if (nonce_ <= 0x7f) {
            data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployedFrom_, uint8(nonce_));
        } else if (nonce_ <= 0xff) {
            data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployedFrom_, bytes1(0x81), uint8(nonce_));
        } else if (nonce_ <= 0xffff) {
            data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployedFrom_, bytes1(0x82), uint16(nonce_));
        } else if (nonce_ <= 0xffffff) {
            data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployedFrom_, bytes1(0x83), uint24(nonce_));
        } else {
            data = abi.encodePacked(bytes1(0xda), bytes1(0x94), deployedFrom_, bytes1(0x84), uint32(nonce_));
        }

        return address(uint160(uint256(keccak256(data))));
    }

}

File 6 of 26 : bigMathMinified.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.
/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision
/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can
/// result in significant gas cost reduction due to storage space reduction.
/// Also note, a valid big number is as follows: if the exponent is > 0, then coefficient last bits should be occupied to have max precision.
/// @dev roundUp is more like a increase 1, which happens everytime for the same number.
/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.
library BigMathMinified {
    /// @dev constants to use for `roundUp` input param to increase readability
    bool internal constant ROUND_DOWN = false;
    bool internal constant ROUND_UP = true;

    /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).
    /// e.g.:
    /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]
    /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)
    ///                                     => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000
    ///                                                                        ^-------------------- 51(exponent) -------------- ^
    /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011               (2236301563)
    /// exponent =                                            0011,0011     (51)
    /// bigNumber =   1000,0101,0100,1011,0100,0000,1111,1011,0011,0011     (572493200179)
    ///
    /// @param normal number which needs to be converted into Big Number
    /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))
    /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))
    /// @param roundUp signals if result should be rounded down or up
    /// @return bigNumber converted bigNumber (coefficient << exponent)
    function toBigNumber(
        uint256 normal,
        uint256 coefficientSize,
        uint256 exponentSize,
        bool roundUp
    ) internal pure returns (uint256 bigNumber) {
        assembly {
            let lastBit_
            let number_ := normal
            if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                number_ := shr(0x80, number_)
                lastBit_ := 0x80
            }
            if gt(number_, 0xFFFFFFFFFFFFFFFF) {
                number_ := shr(0x40, number_)
                lastBit_ := add(lastBit_, 0x40)
            }
            if gt(number_, 0xFFFFFFFF) {
                number_ := shr(0x20, number_)
                lastBit_ := add(lastBit_, 0x20)
            }
            if gt(number_, 0xFFFF) {
                number_ := shr(0x10, number_)
                lastBit_ := add(lastBit_, 0x10)
            }
            if gt(number_, 0xFF) {
                number_ := shr(0x8, number_)
                lastBit_ := add(lastBit_, 0x8)
            }
            if gt(number_, 0xF) {
                number_ := shr(0x4, number_)
                lastBit_ := add(lastBit_, 0x4)
            }
            if gt(number_, 0x3) {
                number_ := shr(0x2, number_)
                lastBit_ := add(lastBit_, 0x2)
            }
            if gt(number_, 0x1) {
                lastBit_ := add(lastBit_, 1)
            }
            if gt(number_, 0) {
                lastBit_ := add(lastBit_, 1)
            }
            if lt(lastBit_, coefficientSize) {
                // for throw exception
                lastBit_ := coefficientSize
            }
            let exponent := sub(lastBit_, coefficientSize)
            let coefficient := shr(exponent, normal)
            if and(roundUp, gt(exponent, 0)) {
                // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number
                coefficient := add(coefficient, 1)
                if eq(shl(coefficientSize, 1), coefficient) {
                    // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits
                    // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.
                    coefficient := shl(sub(coefficientSize, 1), 1)
                    exponent := add(exponent, 1)
                }
            }
            if iszero(lt(exponent, shl(exponentSize, 1))) {
                // if exponent is >= exponentSize, the normal number is too big to fit within
                // BigNumber with too small sizes for coefficient and exponent
                revert(0, 0)
            }
            bigNumber := shl(exponentSize, coefficient)
            bigNumber := add(bigNumber, exponent)
        }
    }

    /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`
    function fromBigNumber(
        uint256 bigNumber,
        uint256 exponentSize,
        uint256 exponentMask
    ) internal pure returns (uint256 normal) {
        assembly {
            let coefficient := shr(exponentSize, bigNumber)
            let exponent := and(bigNumber, exponentMask)
            normal := shl(exponent, coefficient)
        }
    }

    /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).
    /// e.g.
    /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111
    /// lastBit =                   ^---------------------------------   83   ----------------------------------------^
    function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {
        assembly {
            let number_ := normal
            if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                number_ := shr(0x80, number_)
                lastBit := 0x80
            }
            if gt(number_, 0xFFFFFFFFFFFFFFFF) {
                number_ := shr(0x40, number_)
                lastBit := add(lastBit, 0x40)
            }
            if gt(number_, 0xFFFFFFFF) {
                number_ := shr(0x20, number_)
                lastBit := add(lastBit, 0x20)
            }
            if gt(number_, 0xFFFF) {
                number_ := shr(0x10, number_)
                lastBit := add(lastBit, 0x10)
            }
            if gt(number_, 0xFF) {
                number_ := shr(0x8, number_)
                lastBit := add(lastBit, 0x8)
            }
            if gt(number_, 0xF) {
                number_ := shr(0x4, number_)
                lastBit := add(lastBit, 0x4)
            }
            if gt(number_, 0x3) {
                number_ := shr(0x2, number_)
                lastBit := add(lastBit, 0x2)
            }
            if gt(number_, 0x1) {
                lastBit := add(lastBit, 1)
            }
            if gt(number_, 0) {
                lastBit := add(lastBit, 1)
            }
        }
    }
}

File 7 of 26 : dexCalcs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { BigMathMinified } from "./bigMathMinified.sol";
import { DexSlotsLink } from "./dexSlotsLink.sol";

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// @DEV ATTENTION: ON ANY CHANGES HERE, MAKE SURE THAT LOGIC IN VAULTS WILL STILL BE VALID.
// SOME CODE THERE ASSUMES DEXCALCS == LIQUIDITYCALCS.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

/// @notice implements calculation methods used for Fluid Dex such as updated withdrawal / borrow limits.
library DexCalcs {
    // constants used for BigMath conversion from and to storage
    uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;
    uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;

    uint256 internal constant FOUR_DECIMALS = 1e4;
    uint256 internal constant X14 = 0x3fff;
    uint256 internal constant X18 = 0x3ffff;
    uint256 internal constant X24 = 0xffffff;
    uint256 internal constant X33 = 0x1ffffffff;
    uint256 internal constant X64 = 0xffffffffffffffff;

    ///////////////////////////////////////////////////////////////////////////
    //////////                      CALC LIMITS                       /////////
    ///////////////////////////////////////////////////////////////////////////

    /// @dev calculates withdrawal limit before an operate execution:
    /// amount of user supply that must stay supplied (not amount that can be withdrawn).
    /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M
    /// @param userSupplyData_ user supply data packed uint256 from storage
    /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and converted from BigMath
    /// @return currentWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction.
    ///         returned value is in raw for with interest mode, normal amount for interest free mode!
    function calcWithdrawalLimitBeforeOperate(
        uint256 userSupplyData_,
        uint256 userSupply_
    ) internal view returns (uint256 currentWithdrawalLimit_) {
        // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet).
        // first tx where timestamp is 0 will enter `if (lastWithdrawalLimit_ == 0)` because lastWithdrawalLimit_ is not set yet.
        // returning max withdrawal allowed, which is not exactly right but doesn't matter because the first interaction must be
        // a deposit anyway. Important is that it would not revert.

        // Note the first time a deposit brings the user supply amount to above the base withdrawal limit, the active limit
        // is the fully expanded limit immediately.

        // extract last set withdrawal limit
        uint256 lastWithdrawalLimit_ = (userSupplyData_ >> DexSlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) &
            X64;
        lastWithdrawalLimit_ =
            (lastWithdrawalLimit_ >> DEFAULT_EXPONENT_SIZE) <<
            (lastWithdrawalLimit_ & DEFAULT_EXPONENT_MASK);
        if (lastWithdrawalLimit_ == 0) {
            // withdrawal limit is not activated. Max withdrawal allowed
            return 0;
        }

        uint256 maxWithdrawableLimit_;
        uint256 temp_;
        unchecked {
            // extract max withdrawable percent of user supply and
            // calculate maximum withdrawable amount expandPercentage of user supply at full expansion duration elapsed
            // e.g.: if 10% expandPercentage, meaning 10% is withdrawable after full expandDuration has elapsed.

            // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            maxWithdrawableLimit_ =
                (((userSupplyData_ >> DexSlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14) * userSupply_) /
                FOUR_DECIMALS;

            // time elapsed since last withdrawal limit was set (in seconds)
            // @dev last process timestamp is guaranteed to exist for withdrawal, as a supply must have happened before.
            // last timestamp can not be > current timestamp
            temp_ = block.timestamp - ((userSupplyData_ >> DexSlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33);
        }
        // calculate withdrawable amount of expandPercent that is elapsed of expandDuration.
        // e.g. if 60% of expandDuration has elapsed, then user should be able to withdraw 6% of user supply, down to 94%.
        // Note: no explicit check for this needed, it is covered by setting minWithdrawalLimit_ if needed.
        temp_ =
            (maxWithdrawableLimit_ * temp_) /
            // extract expand duration: After this, decrement won't happen (user can withdraw 100% of withdraw limit)
            ((userSupplyData_ >> DexSlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24); // expand duration can never be 0
        // calculate expanded withdrawal limit: last withdrawal limit - withdrawable amount.
        // Note: withdrawable amount here can grow bigger than userSupply if timeElapsed is a lot bigger than expandDuration,
        // which would cause the subtraction `lastWithdrawalLimit_ - withdrawableAmount_` to revert. In that case, set 0
        // which will cause minimum (fully expanded) withdrawal limit to be set in lines below.
        unchecked {
            // underflow explicitly checked & handled
            currentWithdrawalLimit_ = lastWithdrawalLimit_ > temp_ ? lastWithdrawalLimit_ - temp_ : 0;
            // calculate minimum withdrawal limit: minimum amount of user supply that must stay supplied at full expansion.
            // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_
            temp_ = userSupply_ - maxWithdrawableLimit_;
        }
        // if withdrawal limit is decreased below minimum then set minimum
        // (e.g. when more than expandDuration time has elapsed)
        if (temp_ > currentWithdrawalLimit_) {
            currentWithdrawalLimit_ = temp_;
        }
    }

    /// @dev calculates withdrawal limit after an operate execution:
    /// amount of user supply that must stay supplied (not amount that can be withdrawn).
    /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M
    /// @param userSupplyData_ user supply data packed uint256 from storage
    /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and added / subtracted with the executed operate amount
    /// @param newWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction, result from `calcWithdrawalLimitBeforeOperate`
    /// @return withdrawalLimit_ updated withdrawal limit that should be written to storage. returned value is in
    ///                          raw for with interest mode, normal amount for interest free mode!
    function calcWithdrawalLimitAfterOperate(
        uint256 userSupplyData_,
        uint256 userSupply_,
        uint256 newWithdrawalLimit_
    ) internal pure returns (uint256) {
        // temp_ => base withdrawal limit. below this, maximum withdrawals are allowed
        uint256 temp_ = (userSupplyData_ >> DexSlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        // if user supply is below base limit then max withdrawals are allowed
        if (userSupply_ < temp_) {
            return 0;
        }
        // temp_ => withdrawal limit expandPercent (is in 1e2 decimals)
        temp_ = (userSupplyData_ >> DexSlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;
        unchecked {
            // temp_ => minimum withdrawal limit: userSupply - max withdrawable limit (userSupply * expandPercent))
            // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_
            temp_ = userSupply_ - ((userSupply_ * temp_) / FOUR_DECIMALS);
        }
        // if new (before operation) withdrawal limit is less than minimum limit then set minimum limit.
        // e.g. can happen on new deposits. withdrawal limit is instantly fully expanded in a scenario where
        // increased deposit amount outpaces withrawals.
        if (temp_ > newWithdrawalLimit_) {
            return temp_;
        }
        return newWithdrawalLimit_;
    }

    /// @dev calculates borrow limit before an operate execution:
    /// total amount user borrow can reach (not borrowable amount in current operation).
    /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M
    /// @param userBorrowData_ user borrow data packed uint256 from storage
    /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_`
    /// @return currentBorrowLimit_ current borrow limit updated for expansion since last interaction. returned value is in
    ///                             raw for with interest mode, normal amount for interest free mode!
    function calcBorrowLimitBeforeOperate(
        uint256 userBorrowData_,
        uint256 userBorrow_
    ) internal view returns (uint256 currentBorrowLimit_) {
        // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet) -> base limit.
        // first tx where timestamp is 0 will enter `if (maxExpandedBorrowLimit_ < baseBorrowLimit_)` because `userBorrow_` and thus
        // `maxExpansionLimit_` and thus `maxExpandedBorrowLimit_` is 0 and `baseBorrowLimit_` can not be 0.

        // temp_ = extract borrow expand percent (is in 1e2 decimals)
        uint256 temp_ = (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;

        uint256 maxExpansionLimit_;
        uint256 maxExpandedBorrowLimit_;
        unchecked {
            // calculate max expansion limit: Max amount limit can expand to since last interaction
            // userBorrow_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            maxExpansionLimit_ = ((userBorrow_ * temp_) / FOUR_DECIMALS);

            // calculate max borrow limit: Max point limit can increase to since last interaction
            maxExpandedBorrowLimit_ = userBorrow_ + maxExpansionLimit_;
        }

        // currentBorrowLimit_ = extract base borrow limit
        currentBorrowLimit_ = (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;
        currentBorrowLimit_ =
            (currentBorrowLimit_ >> DEFAULT_EXPONENT_SIZE) <<
            (currentBorrowLimit_ & DEFAULT_EXPONENT_MASK);

        if (maxExpandedBorrowLimit_ < currentBorrowLimit_) {
            return currentBorrowLimit_;
        }
        // time elapsed since last borrow limit was set (in seconds)
        unchecked {
            // temp_ = timeElapsed_ (last timestamp can not be > current timestamp)
            temp_ = block.timestamp - ((userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33); // extract last update timestamp
        }

        // currentBorrowLimit_ = expandedBorrowableAmount + extract last set borrow limit
        currentBorrowLimit_ =
            // calculate borrow limit expansion since last interaction for `expandPercent` that is elapsed of `expandDuration`.
            // divisor is extract expand duration (after this, full expansion to expandPercentage happened).
            ((maxExpansionLimit_ * temp_) /
                ((userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24)) + // expand duration can never be 0
            //  extract last set borrow limit
            BigMathMinified.fromBigNumber(
                (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) & X64,
                DEFAULT_EXPONENT_SIZE,
                DEFAULT_EXPONENT_MASK
            );

        // if timeElapsed is bigger than expandDuration, new borrow limit would be > max expansion,
        // so set to `maxExpandedBorrowLimit_` in that case.
        // also covers the case where last process timestamp = 0 (timeElapsed would simply be very big)
        if (currentBorrowLimit_ > maxExpandedBorrowLimit_) {
            currentBorrowLimit_ = maxExpandedBorrowLimit_;
        }
        // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)
        temp_ = (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        if (currentBorrowLimit_ > temp_) {
            currentBorrowLimit_ = temp_;
        }
    }

    /// @dev calculates borrow limit after an operate execution:
    /// total amount user borrow can reach (not borrowable amount in current operation).
    /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M
    /// @param userBorrowData_ user borrow data packed uint256 from storage
    /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_` and added / subtracted with the executed operate amount
    /// @param newBorrowLimit_ current borrow limit updated for expansion since last interaction, result from `calcBorrowLimitBeforeOperate`
    /// @return borrowLimit_ updated borrow limit that should be written to storage.
    ///                      returned value is in raw for with interest mode, normal amount for interest free mode!
    function calcBorrowLimitAfterOperate(
        uint256 userBorrowData_,
        uint256 userBorrow_,
        uint256 newBorrowLimit_
    ) internal pure returns (uint256 borrowLimit_) {
        // temp_ = extract borrow expand percent
        uint256 temp_ = (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; // (is in 1e2 decimals)

        unchecked {
            // borrowLimit_ = calculate maximum borrow limit at full expansion.
            // userBorrow_ needs to be at least 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            borrowLimit_ = userBorrow_ + ((userBorrow_ * temp_) / FOUR_DECIMALS);
        }

        // temp_ = extract base borrow limit
        temp_ = (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        if (borrowLimit_ < temp_) {
            // below base limit, borrow limit is always base limit
            return temp_;
        }
        // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)
        temp_ = (userBorrowData_ >> DexSlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        // make sure fully expanded borrow limit is not above hard max borrow limit
        if (borrowLimit_ > temp_) {
            borrowLimit_ = temp_;
        }
        // if new borrow limit (from before operate) is > max borrow limit, set max borrow limit.
        // (e.g. on a repay shrinking instantly to fully expanded borrow limit from new borrow amount. shrinking is instant)
        if (newBorrowLimit_ > borrowLimit_) {
            return borrowLimit_;
        }
        return newBorrowLimit_;
    }
}

File 8 of 26 : dexSlotsLink.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @notice library that helps in reading / working with storage slot data of Fluid Dex.
/// @dev as all data for Fluid Dex is internal, any data must be fetched directly through manual
/// slot reading through this library or, if gas usage is less important, through the FluidDexResolver.
library DexSlotsLink {
    /// @dev storage slot for variables at Dex
    uint256 internal constant DEX_VARIABLES_SLOT = 0;
    /// @dev storage slot for variables2 at Dex
    uint256 internal constant DEX_VARIABLES2_SLOT = 1;
    /// @dev storage slot for total supply shares at Dex
    uint256 internal constant DEX_TOTAL_SUPPLY_SHARES_SLOT = 2;
    /// @dev storage slot for user supply mapping at Dex
    uint256 internal constant DEX_USER_SUPPLY_MAPPING_SLOT = 3;
    /// @dev storage slot for total borrow shares at Dex
    uint256 internal constant DEX_TOTAL_BORROW_SHARES_SLOT = 4;
    /// @dev storage slot for user borrow mapping at Dex
    uint256 internal constant DEX_USER_BORROW_MAPPING_SLOT = 5;
    /// @dev storage slot for oracle mapping at Dex
    uint256 internal constant DEX_ORACLE_MAPPING_SLOT = 6;
    /// @dev storage slot for range and threshold shifts at Dex
    uint256 internal constant DEX_RANGE_THRESHOLD_SHIFTS_SLOT = 7;
    /// @dev storage slot for center price shift at Dex
    uint256 internal constant DEX_CENTER_PRICE_SHIFT_SLOT = 8;

    // --------------------------------
    // @dev stacked uint256 storage slots bits position data for each:

    // UserSupplyData
    uint256 internal constant BITS_USER_SUPPLY_ALLOWED = 0;
    uint256 internal constant BITS_USER_SUPPLY_AMOUNT = 1;
    uint256 internal constant BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT = 65;
    uint256 internal constant BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP = 129;
    uint256 internal constant BITS_USER_SUPPLY_EXPAND_PERCENT = 162;
    uint256 internal constant BITS_USER_SUPPLY_EXPAND_DURATION = 176;
    uint256 internal constant BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT = 200;

    // UserBorrowData
    uint256 internal constant BITS_USER_BORROW_ALLOWED = 0;
    uint256 internal constant BITS_USER_BORROW_AMOUNT = 1;
    uint256 internal constant BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT = 65;
    uint256 internal constant BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP = 129;
    uint256 internal constant BITS_USER_BORROW_EXPAND_PERCENT = 162;
    uint256 internal constant BITS_USER_BORROW_EXPAND_DURATION = 176;
    uint256 internal constant BITS_USER_BORROW_BASE_BORROW_LIMIT = 200;
    uint256 internal constant BITS_USER_BORROW_MAX_BORROW_LIMIT = 218;

    // --------------------------------

    /// @notice Calculating the slot ID for Dex contract for single mapping at `slot_` for `key_`
    function calculateMappingStorageSlot(uint256 slot_, address key_) internal pure returns (bytes32) {
        return keccak256(abi.encode(key_, slot_));
    }

    /// @notice Calculating the slot ID for Dex contract for double mapping at `slot_` for `key1_` and `key2_`
    function calculateDoubleMappingStorageSlot(
        uint256 slot_,
        address key1_,
        address key2_
    ) internal pure returns (bytes32) {
        bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));
        return keccak256(abi.encode(key2_, intermediateSlot_));
    }
}

File 9 of 26 : errorTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

library LibsErrorTypes {
    /***********************************|
    |         LiquidityCalcs            | 
    |__________________________________*/

    /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)
    uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;

    /// @notice thrown when rate data is set to a version that is not implemented
    uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;

    /// @notice thrown when the calculated borrow rate turns negative. This should never happen.
    uint256 internal constant LiquidityCalcs__BorrowRateNegative = 70003;

    /***********************************|
    |           SafeTransfer            | 
    |__________________________________*/

    /// @notice thrown when safe transfer from for an ERC20 fails
    uint256 internal constant SafeTransfer__TransferFromFailed = 71001;

    /// @notice thrown when safe transfer for an ERC20 fails
    uint256 internal constant SafeTransfer__TransferFailed = 71002;

    /***********************************|
    |           SafeApprove             | 
    |__________________________________*/

    /// @notice thrown when safe approve from for an ERC20 fails
    uint256 internal constant SafeApprove__ApproveFailed = 81001;
}

File 10 of 26 : fluidProtocolTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

interface IFluidProtocol {
    function TYPE() external view returns (uint256);
}

/// @notice implements helper methods to filter Fluid protocols by a certain type
library FluidProtocolTypes {
    uint256 internal constant VAULT_T1_TYPE = 10000; // VaultT1 borrow protocol type vaults
    uint256 internal constant VAULT_T2_SMART_COL_TYPE = 20000; // DEX protocol type vault
    uint256 internal constant VAULT_T3_SMART_DEBT_TYPE = 30000; // DEX protocol type vault
    uint256 internal constant VAULT_T4_SMART_COL_SMART_DEBT_TYPE = 40000; // DEX protocol type vault

    /// @dev filters input `addresses_` by protocol `type_`. Input addresses must be actual Fluid protocols, otherwise
    ///      they would be wrongly assumed to be VaultT1 even if they are not Fluid VaultT1 smart contracts.
    ///      `type_` must be a listed constant type of this library.
    ///      Example usage is to filter all vault addresses at the Vault factory by a certain type, e.g. to not include
    ///      DEX protocol type vaults.
    function filterBy(address[] memory addresses_, uint256 type_) internal view returns (address[] memory filtered_) {
        uint256 curType_;
        uint256 filteredProtocols_ = addresses_.length;
        for (uint256 i; i < addresses_.length; ) {
            try IFluidProtocol(addresses_[i]).TYPE() returns (uint256 protocolType_) {
                curType_ = protocolType_;
            } catch {
                curType_ = VAULT_T1_TYPE;
            }

            if (curType_ != type_) {
                addresses_[i] = address(0);
                --filteredProtocols_;
            }

            unchecked {
                ++i;
            }
        }

        filtered_ = new address[](filteredProtocols_);
        uint256 index_;
        unchecked {
            for (uint256 i; i < addresses_.length; ) {
                if (addresses_[i] != address(0)) {
                    filtered_[index_] = addresses_[i];
                    ++index_;
                }
                ++i;
            }
        }
    }
}

File 11 of 26 : liquidityCalcs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { LibsErrorTypes as ErrorTypes } from "./errorTypes.sol";
import { LiquiditySlotsLink } from "./liquiditySlotsLink.sol";
import { BigMathMinified } from "./bigMathMinified.sol";

/// @notice implements calculation methods used for Fluid liquidity such as updated exchange prices,
/// borrow rate, withdrawal / borrow limits, revenue amount.
library LiquidityCalcs {
    error FluidLiquidityCalcsError(uint256 errorId_);

    /// @notice emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535
    event BorrowRateMaxCap();

    /// @dev constants as from Liquidity variables.sol
    uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;

    /// @dev Ignoring leap years
    uint256 internal constant SECONDS_PER_YEAR = 365 days;
    // constants used for BigMath conversion from and to storage
    uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;
    uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;

    uint256 internal constant FOUR_DECIMALS = 1e4;
    uint256 internal constant TWELVE_DECIMALS = 1e12;
    uint256 internal constant X14 = 0x3fff;
    uint256 internal constant X15 = 0x7fff;
    uint256 internal constant X16 = 0xffff;
    uint256 internal constant X18 = 0x3ffff;
    uint256 internal constant X24 = 0xffffff;
    uint256 internal constant X33 = 0x1ffffffff;
    uint256 internal constant X64 = 0xffffffffffffffff;

    ///////////////////////////////////////////////////////////////////////////
    //////////                  CALC EXCHANGE PRICES                  /////////
    ///////////////////////////////////////////////////////////////////////////

    /// @dev calculates interest (exchange prices) for a token given its' exchangePricesAndConfig from storage.
    /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage
    /// @return supplyExchangePrice_ updated supplyExchangePrice
    /// @return borrowExchangePrice_ updated borrowExchangePrice
    function calcExchangePrices(
        uint256 exchangePricesAndConfig_
    ) internal view returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {
        // Extracting exchange prices
        supplyExchangePrice_ =
            (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) &
            X64;
        borrowExchangePrice_ =
            (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) &
            X64;

        if (supplyExchangePrice_ == 0 || borrowExchangePrice_ == 0) {
            revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__ExchangePriceZero);
        }

        uint256 temp_ = exchangePricesAndConfig_ & X16; // temp_ = borrowRate

        unchecked {
            // last timestamp can not be > current timestamp
            uint256 secondsSinceLastUpdate_ = block.timestamp -
                ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33);

            uint256 borrowRatio_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &
                X15;
            if (secondsSinceLastUpdate_ == 0 || temp_ == 0 || borrowRatio_ == 1) {
                // if no time passed, borrow rate is 0, or no raw borrowings: no exchange price update needed
                // (if borrowRatio_ == 1 means there is only borrowInterestFree, as first bit is 1 and rest is 0)
                return (supplyExchangePrice_, borrowExchangePrice_);
            }

            // calculate new borrow exchange price.
            // formula borrowExchangePriceIncrease: previous price * borrow rate * secondsSinceLastUpdate_.
            // nominator is max uint112 (uint64 * uint16 * uint32). Divisor can not be 0.
            borrowExchangePrice_ +=
                (borrowExchangePrice_ * temp_ * secondsSinceLastUpdate_) /
                (SECONDS_PER_YEAR * FOUR_DECIMALS);

            // FOR SUPPLY EXCHANGE PRICE:
            // all yield paid by borrowers (in mode with interest) goes to suppliers in mode with interest.
            // formula: previous price * supply rate * secondsSinceLastUpdate_.
            // where supply rate = (borrow rate  - revenueFee%) * ratioSupplyYield. And
            // ratioSupplyYield = utilization * supplyRatio * borrowRatio
            //
            // Example:
            // supplyRawInterest is 80, supplyInterestFree is 20. totalSupply is 100. BorrowedRawInterest is 50.
            // BorrowInterestFree is 10. TotalBorrow is 60. borrow rate 40%, revenueFee 10%.
            // yield is 10 (so half a year must have passed).
            // supplyRawInterest must become worth 89. totalSupply must become 109. BorrowedRawInterest must become 60.
            // borrowInterestFree must still be 10. supplyInterestFree still 20. totalBorrow 70.
            // supplyExchangePrice would have to go from 1 to 1,125 (+ 0.125). borrowExchangePrice from 1 to 1,2 (+0.2).
            // utilization is 60%. supplyRatio = 20 / 80 = 25% (only 80% of lenders receiving yield).
            // borrowRatio = 10 / 50 = 20% (only 83,333% of borrowers paying yield):
            // x of borrowers paying yield = 100% - (20 / (100 + 20)) = 100% - 16.6666666% = 83,333%.
            // ratioSupplyYield = 60% * 83,33333% * (100% + 20%) = 62,5%
            // supplyRate = (40% * (100% - 10%)) * = 36% * 62,5% = 22.5%
            // increase in supplyExchangePrice, assuming 100 as previous price.
            // 100 * 22,5% * 1/2 (half a year) = 0,1125.
            // cross-check supplyRawInterest worth = 80 * 1.1125 = 89. totalSupply worth = 89 + 20.

            // -------------- 1. calculate ratioSupplyYield --------------------------------
            // step1: utilization * supplyRatio (or actually part of lenders receiving yield)

            // temp_ => supplyRatio (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)
            // if first bit 0 then ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)
            // else ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)
            temp_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) & X15;

            if (temp_ == 1) {
                // if no raw supply: no exchange price update needed
                // (if supplyRatio_ == 1 means there is only supplyInterestFree, as first bit is 1 and rest is 0)
                return (supplyExchangePrice_, borrowExchangePrice_);
            }

            // ratioSupplyYield precision is 1e27 as 100% for increased precision when supplyInterestFree > supplyWithInterest
            if (temp_ & 1 == 1) {
                // ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)
                temp_ = temp_ >> 1;

                // Note: case where temp_ == 0 (only supplyInterestFree, no yield) already covered by early return
                // in the if statement a little above.

                // based on above example but supplyRawInterest is 20, supplyInterestFree is 80. no fee.
                // supplyRawInterest must become worth 30. totalSupply must become 110.
                // supplyExchangePrice would have to go from 1 to 1,5. borrowExchangePrice from 1 to 1,2.
                // so ratioSupplyYield must come out as 2.5 (250%).
                // supplyRatio would be (20 * 10_000 / 80) = 2500. but must be inverted.
                temp_ = (1e27 * FOUR_DECIMALS) / temp_; // e.g. 1e31 / 2500 = 4e27. (* 1e27 for precision)
                // e.g. 5_000 * (1e27 + 4e27) / 1e27 = 25_000 (=250%).
                temp_ =
                    // utilization * (100% + 100% / supplyRatio)
                    (((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) *
                        (1e27 + temp_)) / // extract utilization (max 16_383 so there is no way this can overflow).
                    (FOUR_DECIMALS);
                // max possible value of temp_ here is 16383 * (1e27 + 1e31) / 1e4 = ~1.64e31
            } else {
                // ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)
                temp_ = temp_ >> 1;
                // if temp_ == 0 then only supplyWithInterest => full yield. temp_ is already 0

                // e.g. 5_000 * 10_000 + (20 * 10_000 / 80) / 10_000 = 5000 * 12500 / 10000 = 6250 (=62.5%).
                temp_ =
                    // 1e27 * utilization * (100% + supplyRatio) / 100%
                    (1e27 *
                        ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) * // extract utilization (max 16_383 so there is no way this can overflow).
                        (FOUR_DECIMALS + temp_)) /
                    (FOUR_DECIMALS * FOUR_DECIMALS);
                // max possible temp_ value: 1e27 * 16383 * 2e4 / 1e8 = 3.2766e27
            }
            // from here temp_ => ratioSupplyYield (utilization * supplyRatio part) scaled by 1e27. max possible value ~1.64e31

            // step2 of ratioSupplyYield: add borrowRatio (only x% of borrowers paying yield)
            if (borrowRatio_ & 1 == 1) {
                // ratio is borrowWithInterest / borrowInterestFree (borrowInterestFree is bigger)
                borrowRatio_ = borrowRatio_ >> 1;
                // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.

                // Note: case where borrowRatio_ == 0 (only borrowInterestFree, no yield) already covered
                // at the beginning of the method by early return if `borrowRatio_ == 1`.

                // based on above example but borrowRawInterest is 10, borrowInterestFree is 50. no fee. borrowRatio = 20%.
                // so only 16.66% of borrowers are paying yield. so the 100% - part of the formula is not needed.
                // x of borrowers paying yield = (borrowRatio / (100 + borrowRatio)) = 16.6666666%
                // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.
                borrowRatio_ = (borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_);
                // max value here for borrowRatio_ is (1e31 / (1e4 + 1e4))= 5e26 (= 50% of borrowers paying yield).
            } else {
                // ratio is borrowInterestFree / borrowWithInterest (borrowWithInterest is bigger)
                borrowRatio_ = borrowRatio_ >> 1;

                // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.
                // x of borrowers paying yield = 100% - (borrowRatio / (100 + borrowRatio)) = 100% - 16.6666666% = 83,333%.
                borrowRatio_ = (1e27 - ((borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_)));
                // borrowRatio can never be > 100%. so max subtraction can be 100% - 100% / 200%.
                // or if borrowRatio_ is 0 -> 100% - 0. or if borrowRatio_ is 1 -> 100% - 1 / 101.
                // max value here for borrowRatio_ is 1e27 - 0 = 1e27 (= 100% of borrowers paying yield).
            }

            // temp_ => ratioSupplyYield. scaled down from 1e25 = 1% each to normal percent precision 1e2 = 1%.
            // max nominator value is ~1.64e31 * 1e27 = 1.64e58. max result = 1.64e8
            temp_ = (FOUR_DECIMALS * temp_ * borrowRatio_) / 1e54;

            // 2. calculate supply rate
            // temp_ => supply rate (borrow rate  - revenueFee%) * ratioSupplyYield.
            // division part is done in next step to increase precision. (divided by 2x FOUR_DECIMALS, fee + borrowRate)
            // Note that all calculation divisions for supplyExchangePrice are rounded down.
            // Note supply rate can be bigger than the borrowRate, e.g. if there are only few lenders with interest
            // but more suppliers not earning interest.
            temp_ = ((exchangePricesAndConfig_ & X16) * // borrow rate
                temp_ * // ratioSupplyYield
                (FOUR_DECIMALS - ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14))); // revenueFee
            // fee can not be > 100%. max possible = 65535 * ~1.64e8 * 1e4 =~1.074774e17.

            // 3. calculate increase in supply exchange price
            supplyExchangePrice_ += ((supplyExchangePrice_ * temp_ * secondsSinceLastUpdate_) /
                (SECONDS_PER_YEAR * FOUR_DECIMALS * FOUR_DECIMALS * FOUR_DECIMALS));
            // max possible nominator = max uint 64 * 1.074774e17 * max uint32 = ~8.52e45. Denominator can not be 0.
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //////////                     CALC REVENUE                       /////////
    ///////////////////////////////////////////////////////////////////////////

    /// @dev gets the `revenueAmount_` for a token given its' totalAmounts and exchangePricesAndConfig from storage
    /// and the current balance of the Fluid liquidity contract for the token.
    /// @param totalAmounts_ total amounts packed uint256 read from storage
    /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage
    /// @param liquidityTokenBalance_   current balance of Liquidity contract (IERC20(token_).balanceOf(address(this)))
    /// @return revenueAmount_ collectable revenue amount
    function calcRevenue(
        uint256 totalAmounts_,
        uint256 exchangePricesAndConfig_,
        uint256 liquidityTokenBalance_
    ) internal view returns (uint256 revenueAmount_) {
        // @dev no need to super-optimize this method as it is only used by admin

        // calculate the new exchange prices based on earned interest
        (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) = calcExchangePrices(exchangePricesAndConfig_);

        // total supply = interest free + with interest converted from raw
        uint256 totalSupply_ = getTotalSupply(totalAmounts_, supplyExchangePrice_);

        if (totalSupply_ > 0) {
            // available revenue: balanceOf(token) + totalBorrowings - totalLendings.
            revenueAmount_ = liquidityTokenBalance_ + getTotalBorrow(totalAmounts_, borrowExchangePrice_);
            // ensure there is no possible case because of rounding etc. where this would revert,
            // explicitly check if >
            revenueAmount_ = revenueAmount_ > totalSupply_ ? revenueAmount_ - totalSupply_ : 0;
            // Note: if utilization > 100% (totalSupply < totalBorrow), then all the amount above 100% utilization
            // can only be revenue.
        } else {
            // if supply is 0, then rest of balance can be withdrawn as revenue so that no amounts get stuck
            revenueAmount_ = liquidityTokenBalance_;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //////////                      CALC LIMITS                       /////////
    ///////////////////////////////////////////////////////////////////////////

    /// @dev calculates withdrawal limit before an operate execution:
    /// amount of user supply that must stay supplied (not amount that can be withdrawn).
    /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M
    /// @param userSupplyData_ user supply data packed uint256 from storage
    /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and converted from BigMath
    /// @return currentWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction.
    ///         returned value is in raw for with interest mode, normal amount for interest free mode!
    function calcWithdrawalLimitBeforeOperate(
        uint256 userSupplyData_,
        uint256 userSupply_
    ) internal view returns (uint256 currentWithdrawalLimit_) {
        // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet).
        // first tx where timestamp is 0 will enter `if (lastWithdrawalLimit_ == 0)` because lastWithdrawalLimit_ is not set yet.
        // returning max withdrawal allowed, which is not exactly right but doesn't matter because the first interaction must be
        // a deposit anyway. Important is that it would not revert.

        // Note the first time a deposit brings the user supply amount to above the base withdrawal limit, the active limit
        // is the fully expanded limit immediately.

        // extract last set withdrawal limit
        uint256 lastWithdrawalLimit_ = (userSupplyData_ >>
            LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) & X64;
        lastWithdrawalLimit_ =
            (lastWithdrawalLimit_ >> DEFAULT_EXPONENT_SIZE) <<
            (lastWithdrawalLimit_ & DEFAULT_EXPONENT_MASK);
        if (lastWithdrawalLimit_ == 0) {
            // withdrawal limit is not activated. Max withdrawal allowed
            return 0;
        }

        uint256 maxWithdrawableLimit_;
        uint256 temp_;
        unchecked {
            // extract max withdrawable percent of user supply and
            // calculate maximum withdrawable amount expandPercentage of user supply at full expansion duration elapsed
            // e.g.: if 10% expandPercentage, meaning 10% is withdrawable after full expandDuration has elapsed.

            // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            maxWithdrawableLimit_ =
                (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14) * userSupply_) /
                FOUR_DECIMALS;

            // time elapsed since last withdrawal limit was set (in seconds)
            // @dev last process timestamp is guaranteed to exist for withdrawal, as a supply must have happened before.
            // last timestamp can not be > current timestamp
            temp_ =
                block.timestamp -
                ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33);
        }
        // calculate withdrawable amount of expandPercent that is elapsed of expandDuration.
        // e.g. if 60% of expandDuration has elapsed, then user should be able to withdraw 6% of user supply, down to 94%.
        // Note: no explicit check for this needed, it is covered by setting minWithdrawalLimit_ if needed.
        temp_ =
            (maxWithdrawableLimit_ * temp_) /
            // extract expand duration: After this, decrement won't happen (user can withdraw 100% of withdraw limit)
            ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24); // expand duration can never be 0
        // calculate expanded withdrawal limit: last withdrawal limit - withdrawable amount.
        // Note: withdrawable amount here can grow bigger than userSupply if timeElapsed is a lot bigger than expandDuration,
        // which would cause the subtraction `lastWithdrawalLimit_ - withdrawableAmount_` to revert. In that case, set 0
        // which will cause minimum (fully expanded) withdrawal limit to be set in lines below.
        unchecked {
            // underflow explicitly checked & handled
            currentWithdrawalLimit_ = lastWithdrawalLimit_ > temp_ ? lastWithdrawalLimit_ - temp_ : 0;
            // calculate minimum withdrawal limit: minimum amount of user supply that must stay supplied at full expansion.
            // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_
            temp_ = userSupply_ - maxWithdrawableLimit_;
        }
        // if withdrawal limit is decreased below minimum then set minimum
        // (e.g. when more than expandDuration time has elapsed)
        if (temp_ > currentWithdrawalLimit_) {
            currentWithdrawalLimit_ = temp_;
        }
    }

    /// @dev calculates withdrawal limit after an operate execution:
    /// amount of user supply that must stay supplied (not amount that can be withdrawn).
    /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M
    /// @param userSupplyData_ user supply data packed uint256 from storage
    /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and added / subtracted with the executed operate amount
    /// @param newWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction, result from `calcWithdrawalLimitBeforeOperate`
    /// @return withdrawalLimit_ updated withdrawal limit that should be written to storage. returned value is in
    ///                          raw for with interest mode, normal amount for interest free mode!
    function calcWithdrawalLimitAfterOperate(
        uint256 userSupplyData_,
        uint256 userSupply_,
        uint256 newWithdrawalLimit_
    ) internal pure returns (uint256) {
        // temp_ => base withdrawal limit. below this, maximum withdrawals are allowed
        uint256 temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        // if user supply is below base limit then max withdrawals are allowed
        if (userSupply_ < temp_) {
            return 0;
        }
        // temp_ => withdrawal limit expandPercent (is in 1e2 decimals)
        temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;
        unchecked {
            // temp_ => minimum withdrawal limit: userSupply - max withdrawable limit (userSupply * expandPercent))
            // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_
            temp_ = userSupply_ - ((userSupply_ * temp_) / FOUR_DECIMALS);
        }
        // if new (before operation) withdrawal limit is less than minimum limit then set minimum limit.
        // e.g. can happen on new deposits. withdrawal limit is instantly fully expanded in a scenario where
        // increased deposit amount outpaces withrawals.
        if (temp_ > newWithdrawalLimit_) {
            return temp_;
        }
        return newWithdrawalLimit_;
    }

    /// @dev calculates borrow limit before an operate execution:
    /// total amount user borrow can reach (not borrowable amount in current operation).
    /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M
    /// @param userBorrowData_ user borrow data packed uint256 from storage
    /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_`
    /// @return currentBorrowLimit_ current borrow limit updated for expansion since last interaction. returned value is in
    ///                             raw for with interest mode, normal amount for interest free mode!
    function calcBorrowLimitBeforeOperate(
        uint256 userBorrowData_,
        uint256 userBorrow_
    ) internal view returns (uint256 currentBorrowLimit_) {
        // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet) -> base limit.
        // first tx where timestamp is 0 will enter `if (maxExpandedBorrowLimit_ < baseBorrowLimit_)` because `userBorrow_` and thus
        // `maxExpansionLimit_` and thus `maxExpandedBorrowLimit_` is 0 and `baseBorrowLimit_` can not be 0.

        // temp_ = extract borrow expand percent (is in 1e2 decimals)
        uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;

        uint256 maxExpansionLimit_;
        uint256 maxExpandedBorrowLimit_;
        unchecked {
            // calculate max expansion limit: Max amount limit can expand to since last interaction
            // userBorrow_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            maxExpansionLimit_ = ((userBorrow_ * temp_) / FOUR_DECIMALS);

            // calculate max borrow limit: Max point limit can increase to since last interaction
            maxExpandedBorrowLimit_ = userBorrow_ + maxExpansionLimit_;
        }

        // currentBorrowLimit_ = extract base borrow limit
        currentBorrowLimit_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;
        currentBorrowLimit_ =
            (currentBorrowLimit_ >> DEFAULT_EXPONENT_SIZE) <<
            (currentBorrowLimit_ & DEFAULT_EXPONENT_MASK);

        if (maxExpandedBorrowLimit_ < currentBorrowLimit_) {
            return currentBorrowLimit_;
        }
        // time elapsed since last borrow limit was set (in seconds)
        unchecked {
            // temp_ = timeElapsed_ (last timestamp can not be > current timestamp)
            temp_ =
                block.timestamp -
                ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33); // extract last update timestamp
        }

        // currentBorrowLimit_ = expandedBorrowableAmount + extract last set borrow limit
        currentBorrowLimit_ =
            // calculate borrow limit expansion since last interaction for `expandPercent` that is elapsed of `expandDuration`.
            // divisor is extract expand duration (after this, full expansion to expandPercentage happened).
            ((maxExpansionLimit_ * temp_) /
                ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24)) + // expand duration can never be 0
            //  extract last set borrow limit
            BigMathMinified.fromBigNumber(
                (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) & X64,
                DEFAULT_EXPONENT_SIZE,
                DEFAULT_EXPONENT_MASK
            );

        // if timeElapsed is bigger than expandDuration, new borrow limit would be > max expansion,
        // so set to `maxExpandedBorrowLimit_` in that case.
        // also covers the case where last process timestamp = 0 (timeElapsed would simply be very big)
        if (currentBorrowLimit_ > maxExpandedBorrowLimit_) {
            currentBorrowLimit_ = maxExpandedBorrowLimit_;
        }
        // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)
        temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        if (currentBorrowLimit_ > temp_) {
            currentBorrowLimit_ = temp_;
        }
    }

    /// @dev calculates borrow limit after an operate execution:
    /// total amount user borrow can reach (not borrowable amount in current operation).
    /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M
    /// @param userBorrowData_ user borrow data packed uint256 from storage
    /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_` and added / subtracted with the executed operate amount
    /// @param newBorrowLimit_ current borrow limit updated for expansion since last interaction, result from `calcBorrowLimitBeforeOperate`
    /// @return borrowLimit_ updated borrow limit that should be written to storage.
    ///                      returned value is in raw for with interest mode, normal amount for interest free mode!
    function calcBorrowLimitAfterOperate(
        uint256 userBorrowData_,
        uint256 userBorrow_,
        uint256 newBorrowLimit_
    ) internal pure returns (uint256 borrowLimit_) {
        // temp_ = extract borrow expand percent
        uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; // (is in 1e2 decimals)

        unchecked {
            // borrowLimit_ = calculate maximum borrow limit at full expansion.
            // userBorrow_ needs to be at least 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).
            borrowLimit_ = userBorrow_ + ((userBorrow_ * temp_) / FOUR_DECIMALS);
        }

        // temp_ = extract base borrow limit
        temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        if (borrowLimit_ < temp_) {
            // below base limit, borrow limit is always base limit
            return temp_;
        }
        // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)
        temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;
        temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);

        // make sure fully expanded borrow limit is not above hard max borrow limit
        if (borrowLimit_ > temp_) {
            borrowLimit_ = temp_;
        }
        // if new borrow limit (from before operate) is > max borrow limit, set max borrow limit.
        // (e.g. on a repay shrinking instantly to fully expanded borrow limit from new borrow amount. shrinking is instant)
        if (newBorrowLimit_ > borrowLimit_) {
            return borrowLimit_;
        }
        return newBorrowLimit_;
    }

    ///////////////////////////////////////////////////////////////////////////
    //////////                      CALC RATES                        /////////
    ///////////////////////////////////////////////////////////////////////////

    /// @dev Calculates new borrow rate from utilization for a token
    /// @param rateData_ rate data packed uint256 from storage for the token
    /// @param utilization_ totalBorrow / totalSupply. 1e4 = 100% utilization
    /// @return rate_ rate for that particular token in 1e2 precision (e.g. 5% rate = 500)
    function calcBorrowRateFromUtilization(uint256 rateData_, uint256 utilization_) internal returns (uint256 rate_) {
        // extract rate version: 4 bits (0xF) starting from bit 0
        uint256 rateVersion_ = (rateData_ & 0xF);

        if (rateVersion_ == 1) {
            rate_ = calcRateV1(rateData_, utilization_);
        } else if (rateVersion_ == 2) {
            rate_ = calcRateV2(rateData_, utilization_);
        } else {
            revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__UnsupportedRateVersion);
        }

        if (rate_ > X16) {
            // hard cap for borrow rate at maximum value 16 bits (65535) to make sure it does not overflow storage space.
            // this is unlikely to ever happen if configs stay within expected levels.
            rate_ = X16;
            // emit event to more easily become aware
            emit BorrowRateMaxCap();
        }
    }

    /// @dev calculates the borrow rate based on utilization for rate data version 1 (with one kink) in 1e2 precision
    /// @param rateData_ rate data packed uint256 from storage for the token
    /// @param utilization_  in 1e2 (100% = 1e4)
    /// @return rate_ rate in 1e2 precision
    function calcRateV1(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {
        /// For rate v1 (one kink) ------------------------------------------------------
        /// Next 16  bits =>  4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  52- 67 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Last 188 bits =>  68-255 => blank, might come in use in future

        // y = mx + c.
        // y is borrow rate
        // x is utilization
        // m = slope (m can also be negative for declining rates)
        // c is constant (c can be negative)

        uint256 y1_;
        uint256 y2_;
        uint256 x1_;
        uint256 x2_;

        // extract kink1: 16 bits (0xFFFF) starting from bit 20
        // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two
        uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16;
        if (utilization_ < kink1_) {
            // if utilization is less than kink
            y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) & X16;
            y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;
            x1_ = 0; // 0%
            x2_ = kink1_;
        } else {
            // else utilization is greater than kink
            y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;
            y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) & X16;
            x1_ = kink1_;
            x2_ = FOUR_DECIMALS; // 100%
        }

        int256 constant_;
        int256 slope_;
        unchecked {
            // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).
            // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor)
            // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS
            slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((x2_ - x1_));

            // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.
            // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256
            // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;
            // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256
            // subtraction most extreme case would be  0 - max value slope_ * x1_ => can not underflow int256
            constant_ = int256(y1_ * TWELVE_DECIMALS) - (slope_ * int256(x1_));

            // calculating new borrow rate
            // - slope_ max value is 65535 * 1e12,
            // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)
            // - constant max value is 65535 * 1e12
            // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256
            // divisor TWELVE_DECIMALS can not be 0
            slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings
            if (slope_ < 0) {
                revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);
            }
            rate_ = uint256(slope_) / TWELVE_DECIMALS;
        }
    }

    /// @dev calculates the borrow rate based on utilization for rate data version 2 (with two kinks) in 1e4 precision
    /// @param rateData_ rate data packed uint256 from storage for the token
    /// @param utilization_  in 1e2 (100% = 1e4)
    /// @return rate_ rate in 1e4 precision
    function calcRateV2(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {
        /// For rate v2 (two kinks) -----------------------------------------------------
        /// Next 16  bits =>  4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  52- 67 => Utilization at kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  68- 83 => Rate at utilization kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Next 16  bits =>  84- 99 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)
        /// Last 156 bits => 100-255 => blank, might come in use in future

        // y = mx + c.
        // y is borrow rate
        // x is utilization
        // m = slope (m can also be negative for declining rates)
        // c is constant (c can be negative)

        uint256 y1_;
        uint256 y2_;
        uint256 x1_;
        uint256 x2_;

        // extract kink1: 16 bits (0xFFFF) starting from bit 20
        // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two
        uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) & X16;
        if (utilization_ < kink1_) {
            // if utilization is less than kink1
            y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) & X16;
            y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;
            x1_ = 0; // 0%
            x2_ = kink1_;
        } else {
            // extract kink2: 16 bits (0xFFFF) starting from bit 52
            uint256 kink2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) & X16;
            if (utilization_ < kink2_) {
                // if utilization is less than kink2
                y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;
                y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;
                x1_ = kink1_;
                x2_ = kink2_;
            } else {
                // else utilization is greater than kink2
                y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;
                y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) & X16;
                x1_ = kink2_;
                x2_ = FOUR_DECIMALS;
            }
        }

        int256 constant_;
        int256 slope_;
        unchecked {
            // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).
            // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor)
            // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS
            slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((x2_ - x1_));

            // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.
            // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256
            // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;
            // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256
            // subtraction most extreme case would be  0 - max value slope_ * x1_ => can not underflow int256
            constant_ = int256(y1_ * TWELVE_DECIMALS) - (slope_ * int256(x1_));

            // calculating new borrow rate
            // - slope_ max value is 65535 * 1e12,
            // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)
            // - constant max value is 65535 * 1e12
            // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256
            // divisor TWELVE_DECIMALS can not be 0
            slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings
            if (slope_ < 0) {
                revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);
            }
            rate_ = uint256(slope_) / TWELVE_DECIMALS;
        }
    }

    /// @dev reads the total supply out of Liquidity packed storage `totalAmounts_` for `supplyExchangePrice_`
    function getTotalSupply(
        uint256 totalAmounts_,
        uint256 supplyExchangePrice_
    ) internal pure returns (uint256 totalSupply_) {
        // totalSupply_ => supplyInterestFree
        totalSupply_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;
        totalSupply_ = (totalSupply_ >> DEFAULT_EXPONENT_SIZE) << (totalSupply_ & DEFAULT_EXPONENT_MASK);

        uint256 totalSupplyRaw_ = totalAmounts_ & X64; // no shifting as supplyRaw is first 64 bits
        totalSupplyRaw_ = (totalSupplyRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalSupplyRaw_ & DEFAULT_EXPONENT_MASK);

        // totalSupply = supplyInterestFree + supplyRawInterest normalized from raw
        totalSupply_ += ((totalSupplyRaw_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION);
    }

    /// @dev reads the total borrow out of Liquidity packed storage `totalAmounts_` for `borrowExchangePrice_`
    function getTotalBorrow(
        uint256 totalAmounts_,
        uint256 borrowExchangePrice_
    ) internal pure returns (uint256 totalBorrow_) {
        // totalBorrow_ => borrowInterestFree
        // no & mask needed for borrow interest free as it occupies the last bits in the storage slot
        totalBorrow_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);
        totalBorrow_ = (totalBorrow_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrow_ & DEFAULT_EXPONENT_MASK);

        uint256 totalBorrowRaw_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;
        totalBorrowRaw_ = (totalBorrowRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrowRaw_ & DEFAULT_EXPONENT_MASK);

        // totalBorrow = borrowInterestFree + borrowRawInterest normalized from raw
        totalBorrow_ += ((totalBorrowRaw_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION);
    }
}

File 12 of 26 : liquiditySlotsLink.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @notice library that helps in reading / working with storage slot data of Fluid Liquidity.
/// @dev as all data for Fluid Liquidity is internal, any data must be fetched directly through manual
/// slot reading through this library or, if gas usage is less important, through the FluidLiquidityResolver.
library LiquiditySlotsLink {
    /// @dev storage slot for status at Liquidity
    uint256 internal constant LIQUIDITY_STATUS_SLOT = 1;
    /// @dev storage slot for auths mapping at Liquidity
    uint256 internal constant LIQUIDITY_AUTHS_MAPPING_SLOT = 2;
    /// @dev storage slot for guardians mapping at Liquidity
    uint256 internal constant LIQUIDITY_GUARDIANS_MAPPING_SLOT = 3;
    /// @dev storage slot for user class mapping at Liquidity
    uint256 internal constant LIQUIDITY_USER_CLASS_MAPPING_SLOT = 4;
    /// @dev storage slot for exchangePricesAndConfig mapping at Liquidity
    uint256 internal constant LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT = 5;
    /// @dev storage slot for rateData mapping at Liquidity
    uint256 internal constant LIQUIDITY_RATE_DATA_MAPPING_SLOT = 6;
    /// @dev storage slot for totalAmounts mapping at Liquidity
    uint256 internal constant LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT = 7;
    /// @dev storage slot for user supply double mapping at Liquidity
    uint256 internal constant LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT = 8;
    /// @dev storage slot for user borrow double mapping at Liquidity
    uint256 internal constant LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT = 9;
    /// @dev storage slot for listed tokens array at Liquidity
    uint256 internal constant LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT = 10;
    /// @dev storage slot for listed tokens array at Liquidity
    uint256 internal constant LIQUIDITY_CONFIGS2_MAPPING_SLOT = 11;

    // --------------------------------
    // @dev stacked uint256 storage slots bits position data for each:

    // ExchangePricesAndConfig
    uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATE = 0;
    uint256 internal constant BITS_EXCHANGE_PRICES_FEE = 16;
    uint256 internal constant BITS_EXCHANGE_PRICES_UTILIZATION = 30;
    uint256 internal constant BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD = 44;
    uint256 internal constant BITS_EXCHANGE_PRICES_LAST_TIMESTAMP = 58;
    uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE = 91;
    uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE = 155;
    uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_RATIO = 219;
    uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATIO = 234;
    uint256 internal constant BITS_EXCHANGE_PRICES_USES_CONFIGS2 = 249;

    // RateData:
    uint256 internal constant BITS_RATE_DATA_VERSION = 0;
    // RateData: V1
    uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO = 4;
    uint256 internal constant BITS_RATE_DATA_V1_UTILIZATION_AT_KINK = 20;
    uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK = 36;
    uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX = 52;
    // RateData: V2
    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO = 4;
    uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1 = 20;
    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1 = 36;
    uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2 = 52;
    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2 = 68;
    uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX = 84;

    // TotalAmounts
    uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_WITH_INTEREST = 0;
    uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE = 64;
    uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST = 128;
    uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE = 192;

    // UserSupplyData
    uint256 internal constant BITS_USER_SUPPLY_MODE = 0;
    uint256 internal constant BITS_USER_SUPPLY_AMOUNT = 1;
    uint256 internal constant BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT = 65;
    uint256 internal constant BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP = 129;
    uint256 internal constant BITS_USER_SUPPLY_EXPAND_PERCENT = 162;
    uint256 internal constant BITS_USER_SUPPLY_EXPAND_DURATION = 176;
    uint256 internal constant BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT = 200;
    uint256 internal constant BITS_USER_SUPPLY_IS_PAUSED = 255;

    // UserBorrowData
    uint256 internal constant BITS_USER_BORROW_MODE = 0;
    uint256 internal constant BITS_USER_BORROW_AMOUNT = 1;
    uint256 internal constant BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT = 65;
    uint256 internal constant BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP = 129;
    uint256 internal constant BITS_USER_BORROW_EXPAND_PERCENT = 162;
    uint256 internal constant BITS_USER_BORROW_EXPAND_DURATION = 176;
    uint256 internal constant BITS_USER_BORROW_BASE_BORROW_LIMIT = 200;
    uint256 internal constant BITS_USER_BORROW_MAX_BORROW_LIMIT = 218;
    uint256 internal constant BITS_USER_BORROW_IS_PAUSED = 255;

    // Configs2
    uint256 internal constant BITS_CONFIGS2_MAX_UTILIZATION = 0;

    // --------------------------------

    /// @notice Calculating the slot ID for Liquidity contract for single mapping at `slot_` for `key_`
    function calculateMappingStorageSlot(uint256 slot_, address key_) internal pure returns (bytes32) {
        return keccak256(abi.encode(key_, slot_));
    }

    /// @notice Calculating the slot ID for Liquidity contract for double mapping at `slot_` for `key1_` and `key2_`
    function calculateDoubleMappingStorageSlot(
        uint256 slot_,
        address key1_,
        address key2_
    ) internal pure returns (bytes32) {
        bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));
        return keccak256(abi.encode(key2_, intermediateSlot_));
    }
}

File 13 of 26 : tickMath.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

/// @title library that calculates number "tick" and "ratioX96" from this: ratioX96 = (1.0015^tick) * 2^96
/// @notice this library is used in Fluid Vault protocol for optimiziation.
/// @dev "tick" supports between -32767 and 32767. "ratioX96" supports between 37075072 and 169307877264527972847801929085841449095838922544595
library TickMath {
    /// The minimum tick that can be passed in getRatioAtTick. 1.0015**-32767
    int24 internal constant MIN_TICK = -32767;
    /// The maximum tick that can be passed in getRatioAtTick. 1.0015**32767
    int24 internal constant MAX_TICK = 32767;

    uint256 internal constant FACTOR00 = 0x100000000000000000000000000000000;
    uint256 internal constant FACTOR01 = 0xff9dd7de423466c20352b1246ce4856f; // 2^128/1.0015**1 = 339772707859149738855091969477551883631
    uint256 internal constant FACTOR02 = 0xff3bd55f4488ad277531fa1c725a66d0; // 2^128/1.0015**2 = 339263812140938331358054887146831636176
    uint256 internal constant FACTOR03 = 0xfe78410fd6498b73cb96a6917f853259; // 2^128/1.0015**4 = 338248306163758188337119769319392490073
    uint256 internal constant FACTOR04 = 0xfcf2d9987c9be178ad5bfeffaa123273; // 2^128/1.0015**8 = 336226404141693512316971918999264834163
    uint256 internal constant FACTOR05 = 0xf9ef02c4529258b057769680fc6601b3; // 2^128/1.0015**16 = 332218786018727629051611634067491389875
    uint256 internal constant FACTOR06 = 0xf402d288133a85a17784a411f7aba082; // 2^128/1.0015**32 = 324346285652234375371948336458280706178
    uint256 internal constant FACTOR07 = 0xe895615b5beb6386553757b0352bda90; // 2^128/1.0015**64 = 309156521885964218294057947947195947664
    uint256 internal constant FACTOR08 = 0xd34f17a00ffa00a8309940a15930391a; // 2^128/1.0015**128 = 280877777739312896540849703637713172762 
    uint256 internal constant FACTOR09 = 0xae6b7961714e20548d88ea5123f9a0ff; // 2^128/1.0015**256 = 231843708922198649176471782639349113087
    uint256 internal constant FACTOR10 = 0x76d6461f27082d74e0feed3b388c0ca1; // 2^128/1.0015**512 = 157961477267171621126394973980180876449
    uint256 internal constant FACTOR11 = 0x372a3bfe0745d8b6b19d985d9a8b85bb; // 2^128/1.0015**1024 = 73326833024599564193373530205717235131
    uint256 internal constant FACTOR12 = 0x0be32cbee48979763cf7247dd7bb539d; // 2^128/1.0015**2048 = 15801066890623697521348224657638773661
    uint256 internal constant FACTOR13 = 0x8d4f70c9ff4924dac37612d1e2921e;   // 2^128/1.0015**4096 = 733725103481409245883800626999235102
    uint256 internal constant FACTOR14 = 0x4e009ae5519380809a02ca7aec77;     // 2^128/1.0015**8192 = 1582075887005588088019997442108535
    uint256 internal constant FACTOR15 = 0x17c45e641b6e95dee056ff10;         // 2^128/1.0015**16384 = 7355550435635883087458926352

    /// The minimum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MIN_TICK). ~ Equivalent to `(1 << 96) * (1.0015**-32767)`
    uint256 internal constant MIN_RATIOX96 = 37075072;
    /// The maximum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MAX_TICK).
    /// ~ Equivalent to `(1 << 96) * (1.0015**32767)`, rounding etc. leading to minor difference
    uint256 internal constant MAX_RATIOX96 = 169307877264527972847801929085841449095838922544595;

    uint256 internal constant ZERO_TICK_SCALED_RATIO = 0x1000000000000000000000000; // 1 << 96 // 79228162514264337593543950336
    uint256 internal constant _1E26 = 1e26;

    /// @notice ratioX96 = (1.0015^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the above formula
    /// @return ratioX96 ratio = (debt amount/collateral amount)
    function getRatioAtTick(int tick) internal pure returns (uint256 ratioX96) {
        assembly {
            let absTick_ := sub(xor(tick, sar(255, tick)), sar(255, tick))

            if gt(absTick_, MAX_TICK) {
                revert(0, 0)
            }
            let factor_ := FACTOR00
            if and(absTick_, 0x1) {
                factor_ := FACTOR01
            }
            if and(absTick_, 0x2) {
                factor_ := shr(128, mul(factor_, FACTOR02))
            }
            if and(absTick_, 0x4) {
                factor_ := shr(128, mul(factor_, FACTOR03))
            }
            if and(absTick_, 0x8) {
                factor_ := shr(128, mul(factor_, FACTOR04))
            }
            if and(absTick_, 0x10) {
                factor_ := shr(128, mul(factor_, FACTOR05))
            }
            if and(absTick_, 0x20) {
                factor_ := shr(128, mul(factor_, FACTOR06))
            }
            if and(absTick_, 0x40) {
                factor_ := shr(128, mul(factor_, FACTOR07))
            }
            if and(absTick_, 0x80) {
                factor_ := shr(128, mul(factor_, FACTOR08))
            }
            if and(absTick_, 0x100) {
                factor_ := shr(128, mul(factor_, FACTOR09))
            }
            if and(absTick_, 0x200) {
                factor_ := shr(128, mul(factor_, FACTOR10))
            }
            if and(absTick_, 0x400) {
                factor_ := shr(128, mul(factor_, FACTOR11))
            }
            if and(absTick_, 0x800) {
                factor_ := shr(128, mul(factor_, FACTOR12))
            }
            if and(absTick_, 0x1000) {
                factor_ := shr(128, mul(factor_, FACTOR13))
            }
            if and(absTick_, 0x2000) {
                factor_ := shr(128, mul(factor_, FACTOR14))
            }
            if and(absTick_, 0x4000) {
                factor_ := shr(128, mul(factor_, FACTOR15))
            }

            let precision_ := 0
            if iszero(and(tick, 0x8000000000000000000000000000000000000000000000000000000000000000)) {
                factor_ := div(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, factor_)
                // we round up in the division so getTickAtRatio of the output price is always consistent
                if mod(factor_, 0x100000000) {
                    precision_ := 1
                }
            }
            ratioX96 := add(shr(32, factor_), precision_)
        }
    }

    /// @notice ratioX96 = (1.0015^tick) * 2^96
    /// @dev Throws if ratioX96 > max ratio || ratioX96 < min ratio
    /// @param ratioX96 The input ratio; ratio = (debt amount/collateral amount)
    /// @return tick The output tick for the above formula. Returns in round down form. if tick is 123.23 then 123, if tick is -123.23 then returns -124
    /// @return perfectRatioX96 perfect ratio for the above tick
    function getTickAtRatio(uint256 ratioX96) internal pure returns (int tick, uint perfectRatioX96) {
        assembly {
            if or(gt(ratioX96, MAX_RATIOX96), lt(ratioX96, MIN_RATIOX96)) {
                revert(0, 0)
            }

            let cond := lt(ratioX96, ZERO_TICK_SCALED_RATIO)
            let factor_

            if iszero(cond) {
                // if ratioX96 >= ZERO_TICK_SCALED_RATIO
                factor_ := div(mul(ratioX96, _1E26), ZERO_TICK_SCALED_RATIO)
            }
            if cond {
                // ratioX96 < ZERO_TICK_SCALED_RATIO
                factor_ := div(mul(ZERO_TICK_SCALED_RATIO, _1E26), ratioX96)
            }

            // put in https://www.wolframalpha.com/ whole equation: (1.0015^tick) * 2^96 * 10^26 / 79228162514264337593543950336

            // for tick = 16384
            // ratioX96 = (1.0015^16384) * 2^96 = 3665252098134783297721995888537077351735
            // 3665252098134783297721995888537077351735 * 10^26 / 79228162514264337593543950336 =
            // 4626198540796508716348404308345255985.06131964639489434655721
            if iszero(lt(factor_, 4626198540796508716348404308345255985)) {
                tick := or(tick, 0x4000)
                factor_ := div(mul(factor_, _1E26), 4626198540796508716348404308345255985)
            }
            // for tick = 8192
            // ratioX96 = (1.0015^8192) * 2^96 = 17040868196391020479062776466509865
            // 17040868196391020479062776466509865 * 10^26 / 79228162514264337593543950336 =
            // 21508599537851153911767490449162.3037648642153898377655505172
            if iszero(lt(factor_, 21508599537851153911767490449162)) {
                tick := or(tick, 0x2000)
                factor_ := div(mul(factor_, _1E26), 21508599537851153911767490449162)
            }
            // for tick = 4096
            // ratioX96 = (1.0015^4096) * 2^96 = 36743933851015821532611831851150
            // 36743933851015821532611831851150 * 10^26 / 79228162514264337593543950336 =
            // 46377364670549310883002866648.9777607649742626173648716941385
            if iszero(lt(factor_, 46377364670549310883002866649)) {
                tick := or(tick, 0x1000)
                factor_ := div(mul(factor_, _1E26), 46377364670549310883002866649)
            }
            // for tick = 2048
            // ratioX96 = (1.0015^2048) * 2^96 = 1706210527034005899209104452335
            // 1706210527034005899209104452335 * 10^26 / 79228162514264337593543950336 =
            // 2153540449365864845468344760.06357108484096046743300420319322
            if iszero(lt(factor_, 2153540449365864845468344760)) {
                tick := or(tick, 0x800)
                factor_ := div(mul(factor_, _1E26), 2153540449365864845468344760)
            }
            // for tick = 1024
            // ratioX96 = (1.0015^1024) * 2^96 = 367668226692760093024536487236
            // 367668226692760093024536487236 * 10^26 / 79228162514264337593543950336 =
            // 464062544207767844008185024.950588990554136265212906454481127
            if iszero(lt(factor_, 464062544207767844008185025)) {
                tick := or(tick, 0x400)
                factor_ := div(mul(factor_, _1E26), 464062544207767844008185025)
            }
            // for tick = 512
            // ratioX96 = (1.0015^512) * 2^96 = 170674186729409605620119663668
            // 170674186729409605620119663668 * 10^26 / 79228162514264337593543950336 =
            // 215421109505955298802281577.031879604792139232258508172947569
            if iszero(lt(factor_, 215421109505955298802281577)) {
                tick := or(tick, 0x200)
                factor_ := div(mul(factor_, _1E26), 215421109505955298802281577)
            }
            // for tick = 256
            // ratioX96 = (1.0015^256) * 2^96 = 116285004205991934861656513301
            // 116285004205991934861656513301 * 10^26 / 79228162514264337593543950336 =
            // 146772309890508740607270614.667650899656438875541505058062410
            if iszero(lt(factor_, 146772309890508740607270615)) {
                tick := or(tick, 0x100)
                factor_ := div(mul(factor_, _1E26), 146772309890508740607270615)
            }
            // for tick = 128
            // ratioX96 = (1.0015^128) * 2^96 = 95984619659632141743747099590
            // 95984619659632141743747099590 * 10^26 / 79228162514264337593543950336 =
            // 121149622323187099817270416.157248837742741760456796835775887
            if iszero(lt(factor_, 121149622323187099817270416)) {
                tick := or(tick, 0x80)
                factor_ := div(mul(factor_, _1E26), 121149622323187099817270416)
            }
            // for tick = 64
            // ratioX96 = (1.0015^64) * 2^96 = 87204845308406958006717891124
            // 87204845308406958006717891124 * 10^26 / 79228162514264337593543950336 =
            // 110067989135437147685980801.568068573422377364214113968609839
            if iszero(lt(factor_, 110067989135437147685980801)) {
                tick := or(tick, 0x40)
                factor_ := div(mul(factor_, _1E26), 110067989135437147685980801)
            }
            // for tick = 32
            // ratioX96 = (1.0015^32) * 2^96 = 83120873769022354029916374475
            // 83120873769022354029916374475 * 10^26 / 79228162514264337593543950336 =
            // 104913292358707887270979599.831816586773651266562785765558183
            if iszero(lt(factor_, 104913292358707887270979600)) {
                tick := or(tick, 0x20)
                factor_ := div(mul(factor_, _1E26), 104913292358707887270979600)
            }
            // for tick = 16
            // ratioX96 = (1.0015^16) * 2^96 = 81151180492336368327184716176
            // 81151180492336368327184716176 * 10^26 / 79228162514264337593543950336 =
            // 102427189924701091191840927.762844039579442328381455567932128
            if iszero(lt(factor_, 102427189924701091191840928)) {
                tick := or(tick, 0x10)
                factor_ := div(mul(factor_, _1E26), 102427189924701091191840928)
            }
            // for tick = 8
            // ratioX96 = (1.0015^8) * 2^96 = 80183906840906820640659903620
            // 80183906840906820640659903620 * 10^26 / 79228162514264337593543950336 =
            // 101206318935480056907421312.890625
            if iszero(lt(factor_, 101206318935480056907421313)) {
                tick := or(tick, 0x8)
                factor_ := div(mul(factor_, _1E26), 101206318935480056907421313)
            }
            // for tick = 4
            // ratioX96 = (1.0015^4) * 2^96 = 79704602139525152702959747603
            // 79704602139525152702959747603 * 10^26 / 79228162514264337593543950336 =
            // 100601351350506250000000000
            if iszero(lt(factor_, 100601351350506250000000000)) {
                tick := or(tick, 0x4)
                factor_ := div(mul(factor_, _1E26), 100601351350506250000000000)
            }
            // for tick = 2
            // ratioX96 = (1.0015^2) * 2^96 = 79466025265172787701084167660
            // 79466025265172787701084167660 * 10^26 / 79228162514264337593543950336 =
            // 100300225000000000000000000
            if iszero(lt(factor_, 100300225000000000000000000)) {
                tick := or(tick, 0x2)
                factor_ := div(mul(factor_, _1E26), 100300225000000000000000000)
            }
            // for tick = 1
            // ratioX96 = (1.0015^1) * 2^96 = 79347004758035734099934266261
            // 79347004758035734099934266261 * 10^26 / 79228162514264337593543950336 =
            // 100150000000000000000000000
            if iszero(lt(factor_, 100150000000000000000000000)) {
                tick := or(tick, 0x1)
                factor_ := div(mul(factor_, _1E26), 100150000000000000000000000)
            }
            if iszero(cond) {
                // if ratioX96 >= ZERO_TICK_SCALED_RATIO
                perfectRatioX96 := div(mul(ratioX96, _1E26), factor_)
            }
            if cond {
                // ratioX96 < ZERO_TICK_SCALED_RATIO
                tick := not(tick)
                perfectRatioX96 := div(mul(ratioX96, factor_), 100150000000000000000000000)
            }
            // perfect ratio should always be <= ratioX96
            // not sure if it can ever be bigger but better to have extra checks
            if gt(perfectRatioX96, ratioX96) {
                revert(0, 0)
            }
        }
    }
}

File 14 of 26 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

abstract contract Structs {
    struct AddressBool {
        address addr;
        bool value;
    }

    struct AddressUint256 {
        address addr;
        uint256 value;
    }

    /// @notice struct to set borrow rate data for version 1
    struct RateDataV1Params {
        ///
        /// @param token for rate data
        address token;
        ///
        /// @param kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100
        /// utilization below kink usually means slow increase in rate, once utilization is above kink borrow rate increases fast
        uint256 kink;
        ///
        /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100
        /// i.e. constant minimum borrow rate
        /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)
        uint256 rateAtUtilizationZero;
        ///
        /// @param rateAtUtilizationKink borrow rate when utilization is at kink. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 7% at kink then rateAtUtilizationKink would be 700
        uint256 rateAtUtilizationKink;
        ///
        /// @param rateAtUtilizationMax borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500
        uint256 rateAtUtilizationMax;
    }

    /// @notice struct to set borrow rate data for version 2
    struct RateDataV2Params {
        ///
        /// @param token for rate data
        address token;
        ///
        /// @param kink1 first kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100
        /// utilization below kink 1 usually means slow increase in rate, once utilization is above kink 1 borrow rate increases faster
        uint256 kink1;
        ///
        /// @param kink2 second kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100
        /// utilization below kink 2 usually means slow / medium increase in rate, once utilization is above kink 2 borrow rate increases fast
        uint256 kink2;
        ///
        /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100
        /// i.e. constant minimum borrow rate
        /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)
        uint256 rateAtUtilizationZero;
        ///
        /// @param rateAtUtilizationKink1 desired borrow rate when utilization is at first kink. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 7% at first kink then rateAtUtilizationKink would be 700
        uint256 rateAtUtilizationKink1;
        ///
        /// @param rateAtUtilizationKink2 desired borrow rate when utilization is at second kink. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 7% at second kink then rateAtUtilizationKink would be 1_200
        uint256 rateAtUtilizationKink2;
        ///
        /// @param rateAtUtilizationMax desired borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100
        /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500
        uint256 rateAtUtilizationMax;
    }

    /// @notice struct to set token config
    struct TokenConfig {
        ///
        /// @param token address
        address token;
        ///
        /// @param fee charges on borrower's interest. in 1e2: 100% = 10_000; 1% = 100
        uint256 fee;
        ///
        /// @param threshold on when to update the storage slot. in 1e2: 100% = 10_000; 1% = 100
        uint256 threshold;
        ///
        /// @param maxUtilization maximum allowed utilization. in 1e2: 100% = 10_000; 1% = 100
        ///                       set to 100% to disable and have default limit of 100% (avoiding SLOAD).
        uint256 maxUtilization;
    }

    /// @notice struct to set user supply & withdrawal config
    struct UserSupplyConfig {
        ///
        /// @param user address
        address user;
        ///
        /// @param token address
        address token;
        ///
        /// @param mode: 0 = without interest. 1 = with interest
        uint8 mode;
        ///
        /// @param expandPercent withdrawal limit expand percent. in 1e2: 100% = 10_000; 1% = 100
        /// Also used to calculate rate at which withdrawal limit should decrease (instant).
        uint256 expandPercent;
        ///
        /// @param expandDuration withdrawal limit expand duration in seconds.
        /// used to calculate rate together with expandPercent
        uint256 expandDuration;
        ///
        /// @param baseWithdrawalLimit base limit, below this, user can withdraw the entire amount.
        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:
        /// with interest -> raw, without interest -> normal
        uint256 baseWithdrawalLimit;
    }

    /// @notice struct to set user borrow & payback config
    struct UserBorrowConfig {
        ///
        /// @param user address
        address user;
        ///
        /// @param token address
        address token;
        ///
        /// @param mode: 0 = without interest. 1 = with interest
        uint8 mode;
        ///
        /// @param expandPercent debt limit expand percent. in 1e2: 100% = 10_000; 1% = 100
        /// Also used to calculate rate at which debt limit should decrease (instant).
        uint256 expandPercent;
        ///
        /// @param expandDuration debt limit expand duration in seconds.
        /// used to calculate rate together with expandPercent
        uint256 expandDuration;
        ///
        /// @param baseDebtCeiling base borrow limit. until here, borrow limit remains as baseDebtCeiling
        /// (user can borrow until this point at once without stepped expansion). Above this, automated limit comes in place.
        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:
        /// with interest -> raw, without interest -> normal
        uint256 baseDebtCeiling;
        ///
        /// @param maxDebtCeiling max borrow ceiling, maximum amount the user can borrow.
        /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:
        /// with interest -> raw, without interest -> normal
        uint256 maxDebtCeiling;
    }
}

File 15 of 26 : error.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

contract Error {
    error FluidOracleError(uint256 errorId_);
}

File 16 of 26 : errorTypes.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

library ErrorTypes {
    /***********************************|
    |           FluidOracleL2           | 
    |__________________________________*/

    /// @notice thrown when sequencer on a L2 has an outage and grace period has not yet passed.
    uint256 internal constant FluidOracleL2__SequencerOutage = 60000;

    /***********************************|
    |     UniV3CheckCLRSOracle          | 
    |__________________________________*/

    /// @notice thrown when the delta between main price source and check rate source is exceeding the allowed delta
    uint256 internal constant UniV3CheckCLRSOracle__InvalidPrice = 60001;

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant UniV3CheckCLRSOracle__InvalidParams = 60002;

    /// @notice thrown when the exchange rate is zero, even after all possible fallbacks depending on config
    uint256 internal constant UniV3CheckCLRSOracle__ExchangeRateZero = 60003;

    /***********************************|
    |           FluidOracle             | 
    |__________________________________*/

    /// @notice thrown when an invalid info name is passed into a fluid oracle (e.g. not set or too long)
    uint256 internal constant FluidOracle__InvalidInfoName = 60010;

    /***********************************|
    |            sUSDe Oracle           | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant SUSDeOracle__InvalidParams = 60102;

    /***********************************|
    |           Pendle Oracle           | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant PendleOracle__InvalidParams = 60201;

    /// @notice thrown when the Pendle market Oracle has not been initialized yet
    uint256 internal constant PendleOracle__MarketNotInitialized = 60202;

    /// @notice thrown when the Pendle market does not have 18 decimals
    uint256 internal constant PendleOracle__MarketInvalidDecimals = 60203;

    /// @notice thrown when the Pendle market returns an unexpected price
    uint256 internal constant PendleOracle__InvalidPrice = 60204;

    /***********************************|
    |    CLRS2UniV3CheckCLRSOracleL2    | 
    |__________________________________*/

    /// @notice thrown when the exchange rate is zero, even after all possible fallbacks depending on config
    uint256 internal constant CLRS2UniV3CheckCLRSOracleL2__ExchangeRateZero = 60301;

    /***********************************|
    |    Ratio2xFallbackCLRSOracleL2    | 
    |__________________________________*/

    /// @notice thrown when the exchange rate is zero, even after all possible fallbacks depending on config
    uint256 internal constant Ratio2xFallbackCLRSOracleL2__ExchangeRateZero = 60311;

    /***********************************|
    |            WeETHsOracle           | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant WeETHsOracle__InvalidParams = 60321;

    /***********************************|
    |        DexSmartColOracle          | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant DexSmartColOracle__InvalidParams = 60331;

    /// @notice thrown when smart col is not enabled
    uint256 internal constant DexSmartColOracle__SmartColNotEnabled = 60332;

    /***********************************|
    |        DexSmartDebtOracle         | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant DexSmartDebtOracle__InvalidParams = 60341;

    /// @notice thrown when smart debt is not enabled
    uint256 internal constant DexSmartDebtOracle__SmartDebtNotEnabled = 60342;

    /***********************************|
    |            ContractRate           | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant ContractRate__InvalidParams = 60351;

    /// @notice thrown when caller is not authorized
    uint256 internal constant ContractRate__Unauthorized = 60352;

    /// @notice thrown when minimum diff for triggering update on the stared rate is not reached
    uint256 internal constant ContractRate__MinUpdateDiffNotReached = 60353;

    /***********************************|
    |            sUSDs Oracle           | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant SUSDsOracle__InvalidParams = 60361;

    /***********************************|
    |            Peg Oracle             | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant PegOracle__InvalidParams = 60371;

    /***********************************|
    |          Chainlink Oracle         | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant ChainlinkOracle__InvalidParams = 61001;

    /***********************************|
    |          UniswapV3 Oracle         | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant UniV3Oracle__InvalidParams = 62001;

    /// @notice thrown when constructor is called with invalid ordered seconds agos values
    uint256 internal constant UniV3Oracle__InvalidSecondsAgos = 62002;

    /// @notice thrown when constructor is called with invalid delta values > 100%
    uint256 internal constant UniV3Oracle__InvalidDeltas = 62003;

    /***********************************|
    |            WstETh Oracle          | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant WstETHOracle__InvalidParams = 63001;

    /***********************************|
    |           Redstone Oracle         | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant RedstoneOracle__InvalidParams = 64001;

    /***********************************|
    |          Fallback Oracle          | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant FallbackOracle__InvalidParams = 65001;

    /***********************************|
    |       FallbackCLRSOracle          | 
    |__________________________________*/

    /// @notice thrown when the exchange rate is zero, even for the fallback oracle source (if enabled)
    uint256 internal constant FallbackCLRSOracle__ExchangeRateZero = 66001;

    /***********************************|
    |         WstETHCLRSOracle          | 
    |__________________________________*/

    /// @notice thrown when the exchange rate is zero, even for the fallback oracle source (if enabled)
    uint256 internal constant WstETHCLRSOracle__ExchangeRateZero = 67001;

    /***********************************|
    |        CLFallbackUniV3Oracle      | 
    |__________________________________*/

    /// @notice thrown when the exchange rate is zero, even for the uniV3 rate
    uint256 internal constant CLFallbackUniV3Oracle__ExchangeRateZero = 68001;

    /***********************************|
    |  WstETHCLRS2UniV3CheckCLRSOracle  | 
    |__________________________________*/

    /// @notice thrown when the exchange rate is zero, even for the uniV3 rate
    uint256 internal constant WstETHCLRS2UniV3CheckCLRSOracle__ExchangeRateZero = 69001;

    /***********************************|
    |             WeETh Oracle          | 
    |__________________________________*/

    /// @notice thrown when an invalid parameter is passed to a method
    uint256 internal constant WeETHOracle__InvalidParams = 70001;
}

File 17 of 26 : fluidOracle.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { IFluidOracle } from "./interfaces/iFluidOracle.sol";
import { ErrorTypes } from "./errorTypes.sol";
import { Error as OracleError } from "./error.sol";

/// @title   FluidOracle
/// @notice  Base contract that any Fluid Oracle must implement
abstract contract FluidOracle is IFluidOracle, OracleError {
    /// @dev short helper string to easily identify the oracle. E.g. token symbols
    //
    // using a bytes32 because string can not be immutable.
    bytes32 private immutable _infoName;

    constructor(string memory infoName_) {
        if (bytes(infoName_).length > 32 || bytes(infoName_).length == 0) {
            revert FluidOracleError(ErrorTypes.FluidOracle__InvalidInfoName);
        }

        // convert string to bytes32
        bytes32 infoNameBytes32_;
        assembly {
            infoNameBytes32_ := mload(add(infoName_, 32))
        }
        _infoName = infoNameBytes32_;
    }

    /// @inheritdoc IFluidOracle
    function infoName() external view returns (string memory) {
        // convert bytes32 to string
        uint256 length_;
        while (length_ < 32 && _infoName[length_] != 0) {
            length_++;
        }
        bytes memory infoNameBytes_ = new bytes(length_);
        for (uint256 i; i < length_; i++) {
            infoNameBytes_[i] = _infoName[i];
        }
        return string(infoNameBytes_);
    }

    /// @inheritdoc IFluidOracle
    function getExchangeRate() external view virtual returns (uint256 exchangeRate_);

    /// @inheritdoc IFluidOracle
    function getExchangeRateOperate() external view virtual returns (uint256 exchangeRate_);

    /// @inheritdoc IFluidOracle
    function getExchangeRateLiquidate() external view virtual returns (uint256 exchangeRate_);
}

File 18 of 26 : iFluidOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

interface IFluidOracle {
    /// @dev Deprecated. Use `getExchangeRateOperate()` and `getExchangeRateLiquidate()` instead. Only implemented for
    ///      backwards compatibility.
    function getExchangeRate() external view returns (uint256 exchangeRate_);

    /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27 for operates
    function getExchangeRateOperate() external view returns (uint256 exchangeRate_);

    /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27 for liquidations
    function getExchangeRateLiquidate() external view returns (uint256 exchangeRate_);

    /// @notice helper string to easily identify the oracle. E.g. token symbols
    function infoName() external view returns (string memory);
}

File 19 of 26 : iLiquidityResolver.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import { Structs as LiquidityStructs } from "../../../periphery/resolvers/liquidity/structs.sol";

interface IFluidLiquidityResolver {
    /// @notice gets the `revenueAmount_` for a `token_`.
    function getRevenue(address token_) external view returns (uint256 revenueAmount_);

    /// @notice address of contract that gets sent the revenue. Configurable by governance
    function getRevenueCollector() external view returns (address);

    /// @notice Liquidity contract paused status: status = 1 -> normal. status = 2 -> paused.
    function getStatus() external view returns (uint256);

    /// @notice checks if `auth_` is an allowed auth on Liquidity.
    /// Auths can set most config values. E.g. contracts that automate certain flows like e.g. adding a new fToken.
    /// Governance can add/remove auths. Governance is auth by default.
    function isAuth(address auth_) external view returns (uint256);

    /// @notice checks if `guardian_` is an allowed Guardian on Liquidity.
    /// Guardians can pause lower class users.
    /// Governance can add/remove guardians. Governance is guardian by default.
    function isGuardian(address guardian_) external view returns (uint256);

    /// @notice gets user class for `user_`. Class defines which protocols can be paused by guardians.
    /// Currently there are 2 classes: 0 can be paused by guardians. 1 cannot be paused by guardians.
    /// New protocols are added as class 0 and will be upgraded to 1 over time.
    function getUserClass(address user_) external view returns (uint256);

    /// @notice gets exchangePricesAndConfig packed uint256 storage slot for `token_`.
    function getExchangePricesAndConfig(address token_) external view returns (uint256);

    /// @notice gets rateConfig packed uint256 storage slot for `token_`.
    function getRateConfig(address token_) external view returns (uint256);

    /// @notice gets totalAmounts packed uint256 storage slot for `token_`.
    function getTotalAmounts(address token_) external view returns (uint256);

    /// @notice gets configs2 packed uint256 storage slot for `token_`.
    function getConfigs2(address token_) external view returns (uint256);

    /// @notice gets userSupply data packed uint256 storage slot for `user_` and `token_`.
    function getUserSupply(address user_, address token_) external view returns (uint256);

    /// @notice gets userBorrow data packed uint256 storage slot for `user_` and `token_`.
    function getUserBorrow(address user_, address token_) external view returns (uint256);

    /// @notice returns all `listedTokens_` at the Liquidity contract. Once configured, a token can never be removed.
    function listedTokens() external view returns (address[] memory listedTokens_);

    /// @notice get the Rate config data `rateData_` for a `token_` compiled from the packed uint256 rateConfig storage slot
    function getTokenRateData(address token_) external view returns (LiquidityStructs.RateData memory rateData_);

    /// @notice get the Rate config datas `rateDatas_` for multiple `tokens_` compiled from the packed uint256 rateConfig storage slot
    function getTokensRateData(
        address[] calldata tokens_
    ) external view returns (LiquidityStructs.RateData[] memory rateDatas_);

    /// @notice returns general data for `token_` such as rates, exchange prices, utilization, fee, total amounts etc.
    function getOverallTokenData(
        address token_
    ) external view returns (LiquidityStructs.OverallTokenData memory overallTokenData_);

    /// @notice returns general data for multiple `tokens_` such as rates, exchange prices, utilization, fee, total amounts etc.
    function getOverallTokensData(
        address[] calldata tokens_
    ) external view returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);

    /// @notice returns general data for all `listedTokens()` such as rates, exchange prices, utilization, fee, total amounts etc.
    function getAllOverallTokensData()
        external
        view
        returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);

    /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`
    function getUserSupplyData(
        address user_,
        address token_
    )
        external
        view
        returns (
            LiquidityStructs.UserSupplyData memory userSupplyData_,
            LiquidityStructs.OverallTokenData memory overallTokenData_
        );

    /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`
    function getUserMultipleSupplyData(
        address user_,
        address[] calldata tokens_
    )
        external
        view
        returns (
            LiquidityStructs.UserSupplyData[] memory userSuppliesData_,
            LiquidityStructs.OverallTokenData[] memory overallTokensData_
        );

    /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`
    function getUserBorrowData(
        address user_,
        address token_
    )
        external
        view
        returns (
            LiquidityStructs.UserBorrowData memory userBorrowData_,
            LiquidityStructs.OverallTokenData memory overallTokenData_
        );

    /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`
    function getUserMultipleBorrowData(
        address user_,
        address[] calldata tokens_
    )
        external
        view
        returns (
            LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,
            LiquidityStructs.OverallTokenData[] memory overallTokensData_
        );

    /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `supplyTokens_`
    ///     and returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `borrowTokens_`
    function getUserMultipleBorrowSupplyData(
        address user_,
        address[] calldata supplyTokens_,
        address[] calldata borrowTokens_
    )
        external
        view
        returns (
            LiquidityStructs.UserSupplyData[] memory userSuppliesData_,
            LiquidityStructs.OverallTokenData[] memory overallSupplyTokensData_,
            LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,
            LiquidityStructs.OverallTokenData[] memory overallBorrowTokensData_
        );
}

File 20 of 26 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { Structs as AdminModuleStructs } from "../../../liquidity/adminModule/structs.sol";

abstract contract Structs {
    struct RateData {
        uint256 version;
        AdminModuleStructs.RateDataV1Params rateDataV1;
        AdminModuleStructs.RateDataV2Params rateDataV2;
    }

    struct OverallTokenData {
        uint256 borrowRate;
        uint256 supplyRate;
        uint256 fee; // revenue fee
        uint256 lastStoredUtilization;
        uint256 storageUpdateThreshold;
        uint256 lastUpdateTimestamp;
        uint256 supplyExchangePrice;
        uint256 borrowExchangePrice;
        uint256 supplyRawInterest;
        uint256 supplyInterestFree;
        uint256 borrowRawInterest;
        uint256 borrowInterestFree;
        uint256 totalSupply;
        uint256 totalBorrow;
        uint256 revenue;
        uint256 maxUtilization; // maximum allowed utilization
        RateData rateData;
    }

    // amounts are always in normal (for withInterest already multiplied with exchange price)
    struct UserSupplyData {
        bool modeWithInterest; // true if mode = with interest, false = without interest
        uint256 supply; // user supply amount
        // the withdrawal limit (e.g. if 10% is the limit, and 100M is supplied, it would be 90M)
        uint256 withdrawalLimit;
        uint256 lastUpdateTimestamp;
        uint256 expandPercent; // withdrawal limit expand percent in 1e2
        uint256 expandDuration; // withdrawal limit expand duration in seconds
        uint256 baseWithdrawalLimit;
        // the current actual max withdrawable amount (e.g. if 10% is the limit, and 100M is supplied, it would be 10M)
        uint256 withdrawableUntilLimit;
        uint256 withdrawable; // actual currently withdrawable amount (supply - withdrawal Limit) & considering balance
    }

    // amounts are always in normal (for withInterest already multiplied with exchange price)
    struct UserBorrowData {
        bool modeWithInterest; // true if mode = with interest, false = without interest
        uint256 borrow; // user borrow amount
        uint256 borrowLimit;
        uint256 lastUpdateTimestamp;
        uint256 expandPercent;
        uint256 expandDuration;
        uint256 baseBorrowLimit;
        uint256 maxBorrowLimit;
        uint256 borrowableUntilLimit; // borrowable amount until any borrow limit (incl. max utilization limit)
        uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization
        uint256 borrowLimitUtilization; // borrow limit for `maxUtilization`
    }
}

File 21 of 26 : helpers.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { Variables } from "./variables.sol";
import { Structs } from "./structs.sol";
import { TickMath } from "../../../libraries/tickMath.sol";
import { BigMathMinified } from "../../../libraries/bigMathMinified.sol";

contract Helpers is Variables, Structs {
    function normalSlot(uint256 slot_) public pure returns (bytes32) {
        return bytes32(slot_);
    }

    /// @notice Calculating the slot ID for Liquidity contract for single mapping
    function calculateStorageSlotUintMapping(uint256 slot_, uint key_) public pure returns (bytes32) {
        return keccak256(abi.encode(key_, slot_));
    }

    /// @notice Calculating the slot ID for Liquidity contract for single mapping
    function calculateStorageSlotIntMapping(uint256 slot_, int key_) public pure returns (bytes32) {
        return keccak256(abi.encode(key_, slot_));
    }

    /// @notice Calculating the slot ID for Liquidity contract for double mapping
    function calculateDoubleIntUintMapping(uint256 slot_, int key1_, uint key2_) public pure returns (bytes32) {
        bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));
        return keccak256(abi.encode(key2_, intermediateSlot_));
    }

    function tickHelper(uint tickRaw_) public pure returns (int tick) {
        require(tickRaw_ < X20, "invalid-number");
        if (tickRaw_ > 0) {
            tick = tickRaw_ & 1 == 1 ? int((tickRaw_ >> 1) & X19) : -int((tickRaw_ >> 1) & X19);
        } else {
            tick = type(int).min;
        }
    }

    constructor(address factory_, address liquidityResolver_) Variables(factory_, liquidityResolver_) {}
}

File 22 of 26 : structs.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { IFluidVault } from "../../../protocols/vault/interfaces/iVault.sol";
import { Structs as FluidLiquidityResolverStructs } from "../liquidity/structs.sol";

// @dev Amounts are always in token amount for normal col / normal debt or in
// shares for Dex smart col / smart debt.
contract Structs {
    struct Configs {
        // can be supplyRate instead if Vault Type is smart col. in that case if 1st bit == 1 then positive else negative
        uint16 supplyRateMagnifier;
        // can be borrowRate instead if Vault Type is smart debt. in that case if 1st bit == 1 then positive else negative
        uint16 borrowRateMagnifier;
        uint16 collateralFactor;
        uint16 liquidationThreshold;
        uint16 liquidationMaxLimit;
        uint16 withdrawalGap;
        uint16 liquidationPenalty;
        uint16 borrowFee;
        address oracle;
        // Oracle price is always debt per col, i.e. amount of debt for 1 col.
        // In case of Dex this price can be used to resolve shares values w.r.t. token0 or token1:
        // - T2: debt token per 1 col share
        // - T3: debt shares per 1 col token
        // - T4: debt shares per 1 col share
        uint oraclePriceOperate;
        uint oraclePriceLiquidate;
        address rebalancer;
        uint lastUpdateTimestamp;
    }

    struct ExchangePricesAndRates {
        uint lastStoredLiquiditySupplyExchangePrice; // 0 in case of smart col
        uint lastStoredLiquidityBorrowExchangePrice; // 0 in case of smart debt
        uint lastStoredVaultSupplyExchangePrice;
        uint lastStoredVaultBorrowExchangePrice;
        uint liquiditySupplyExchangePrice; // set to 1e12 in case of smart col
        uint liquidityBorrowExchangePrice; // set to 1e12 in case of smart debt
        uint vaultSupplyExchangePrice;
        uint vaultBorrowExchangePrice;
        uint supplyRateLiquidity; // set to 0 in case of smart col. Must get per token through DexEntireData
        uint borrowRateLiquidity; // set to 0 in case of smart debt. Must get per token through DexEntireData
        // supplyRateVault or borrowRateVault:
        // - when normal col / debt: rate at liquidity + diff rewards or fee through magnifier (rewardsOrFeeRate below)
        // - when smart col / debt: rewards or fee rate at the vault itself. always == rewardsOrFeeRate below.
        // to get the full rates for vault when smart col / debt, combine with data from DexResolver:
        // - rateAtLiquidity for token0 or token1 (DexResolver)
        // - the rewards or fee rate at the vault (VaultResolver)
        // - the Dex APR (currently off-chain compiled through tracking swap events at the DEX)
        int supplyRateVault; // can be negative in case of smart col (meaning pay to supply)
        int borrowRateVault; // can be negative in case of smart debt (meaning get paid to borrow)
        // rewardsOrFeeRateSupply: rewards or fee rate in percent 1e2 precision (1% = 100, 100% = 10000).
        // positive rewards, negative fee.
        // for smart col vaults: supplyRateVault == supplyRateLiquidity.
        // for normal col vaults: relative percent to supplyRateLiquidity, e.g.:
        // when rewards: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = 20%, supplyRateVault = 4.8%.
        // when fee: supplyRateLiquidity = 4%, rewardsOrFeeRateSupply = -30%, supplyRateVault = 2.8%.
        int rewardsOrFeeRateSupply;
        // rewardsOrFeeRateBorrow: rewards or fee rate in percent 1e2 precision (1% = 100, 100% = 10000).
        // negative rewards, positive fee.
        // for smart debt vaults: borrowRateVault == borrowRateLiquidity.
        // for normal debt vaults: relative percent to borrowRateLiquidity, e.g.:
        // when rewards: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = -20%, borrowRateVault = 3.2%.
        // when fee: borrowRateLiquidity = 4%, rewardsOrFeeRateBorrow = 30%, borrowRateVault = 5.2%.
        int rewardsOrFeeRateBorrow;
    }

    struct TotalSupplyAndBorrow {
        uint totalSupplyVault;
        uint totalBorrowVault;
        uint totalSupplyLiquidityOrDex;
        uint totalBorrowLiquidityOrDex;
        uint absorbedSupply;
        uint absorbedBorrow;
    }

    struct LimitsAndAvailability {
        // in case of DEX: withdrawable / borrowable amount of vault at DEX, BUT there could be that DEX can not withdraw
        // that much at Liquidity! So for DEX this must be combined with returned data in DexResolver.
        uint withdrawLimit;
        uint withdrawableUntilLimit;
        uint withdrawable;
        uint borrowLimit;
        uint borrowableUntilLimit; // borrowable amount until any borrow limit (incl. max utilization limit)
        uint borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization
        uint borrowLimitUtilization; // borrow limit for `maxUtilization` config at Liquidity
        uint minimumBorrowing;
    }

    struct CurrentBranchState {
        uint status; // if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed
        int minimaTick;
        uint debtFactor;
        uint partials;
        uint debtLiquidity;
        uint baseBranchId;
        int baseBranchMinima;
    }

    struct VaultState {
        uint totalPositions;
        int topTick;
        uint currentBranch;
        uint totalBranch;
        uint totalBorrow;
        uint totalSupply;
        CurrentBranchState currentBranchState;
    }

    struct VaultEntireData {
        address vault;
        bool isSmartCol; // true if col token is a Fluid Dex
        bool isSmartDebt; // true if debt token is a Fluid Dex
        IFluidVault.ConstantViews constantVariables;
        Configs configs;
        ExchangePricesAndRates exchangePricesAndRates;
        TotalSupplyAndBorrow totalSupplyAndBorrow;
        LimitsAndAvailability limitsAndAvailability;
        VaultState vaultState;
        // liquidity related data such as supply amount, limits, expansion etc.
        // Also set for Dex, limits are in shares and same things apply as noted for LimitsAndAvailability above!
        FluidLiquidityResolverStructs.UserSupplyData liquidityUserSupplyData;
        // liquidity related data such as borrow amount, limits, expansion etc.
        // Also set for Dex, limits are in shares and same things apply as noted for LimitsAndAvailability above!
        FluidLiquidityResolverStructs.UserBorrowData liquidityUserBorrowData;
    }

    struct UserPosition {
        uint nftId;
        address owner;
        bool isLiquidated;
        bool isSupplyPosition; // if true that means borrowing is 0
        int tick;
        uint tickId;
        uint beforeSupply;
        uint beforeBorrow;
        uint beforeDustBorrow;
        uint supply;
        uint borrow;
        uint dustBorrow;
    }

    /// @dev liquidation related data
    /// @param vault address of vault
    /// @param token0In address of token in
    /// @param token0Out address of token out
    /// @param token1In address of token in (if smart debt)
    /// @param token1Out address of token out (if smart col)
    /// @param inAmt (without absorb liquidity) minimum of available liquidation
    /// @param outAmt (without absorb liquidity) expected token out, collateral to withdraw
    /// @param inAmtWithAbsorb (absorb liquidity included) minimum of available liquidation. In most cases it'll be same as inAmt but sometimes can be bigger.
    /// @param outAmtWithAbsorb (absorb liquidity included) expected token out, collateral to withdraw. In most cases it'll be same as outAmt but sometimes can be bigger.
    /// @param absorbAvailable true if absorb is available
    /// @dev Liquidity in with absirb will always be >= without asborb. Sometimes without asborb can provide better swaps,
    ///      sometimes with absirb can provide better swaps. But available in with absirb will always be >= One
    struct LiquidationStruct {
        address vault;
        address token0In;
        address token0Out;
        address token1In;
        address token1Out;
        // amounts in case of smart debt are in shares, otherwise token amounts.
        // smart col can not be liquidated so to exchange inAmt always use DexResolver DexState.tokenPerDebtShare
        // and tokenPerColShare for outAmt when Vault is smart col.
        uint inAmt;
        uint outAmt;
        uint inAmtWithAbsorb;
        uint outAmtWithAbsorb;
        bool absorbAvailable;
    }

    struct AbsorbStruct {
        address vault;
        bool absorbAvailable;
    }
}

File 23 of 26 : variables.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;

import { IFluidLiquidityResolver } from "../liquidity/iLiquidityResolver.sol";
import { IFluidVaultFactory } from "../../../protocols/vault/interfaces/iVaultFactory.sol";

interface IFluidStorageReadable {
    function readFromStorage(bytes32 slot_) external view returns (uint result_);
}

contract Variables {
    IFluidVaultFactory public immutable FACTORY;
    IFluidLiquidityResolver public immutable LIQUIDITY_RESOLVER;

    // 30 bits (used for partials mainly)
    uint internal constant X8 = 0xff;
    uint internal constant X10 = 0x3ff;
    uint internal constant X14 = 0x3fff;
    uint internal constant X15 = 0x7fff;
    uint internal constant X16 = 0xffff;
    uint internal constant X18 = 0x3ffff;
    uint internal constant X19 = 0x7ffff;
    uint internal constant X20 = 0xfffff;
    uint internal constant X24 = 0xffffff;
    uint internal constant X25 = 0x1ffffff;
    uint internal constant X30 = 0x3fffffff;
    uint internal constant X32 = 0xffffffff;
    uint internal constant X33 = 0x1ffffffff;
    uint internal constant X35 = 0x7ffffffff;
    uint internal constant X40 = 0xffffffffff;
    uint internal constant X50 = 0x3ffffffffffff;
    uint internal constant X64 = 0xffffffffffffffff;
    uint internal constant X96 = 0xffffffffffffffffffffffff;
    uint internal constant X128 = 0xffffffffffffffffffffffffffffffff;
    /// @dev address that is mapped to the chain native token
    address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    uint internal constant EXCHANGE_PRICES_PRECISION = 1e12;

    constructor(address factory_, address liquidityResolver_) {
        FACTORY = IFluidVaultFactory(factory_);
        LIQUIDITY_RESOLVER = IFluidLiquidityResolver(liquidityResolver_);
    }
}

File 24 of 26 : iVault.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

/// @notice common Fluid vaults interface, some methods only available for vaults > T1 (type, simulateLiquidate, rebalance is different)
interface IFluidVault {
    /// @notice returns the vault id
    function VAULT_ID() external view returns (uint256);

    /// @notice returns the vault id
    function TYPE() external view returns (uint256);

    /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.
    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);

    struct Tokens {
        address token0;
        address token1;
    }

    struct ConstantViews {
        address liquidity;
        address factory;
        address operateImplementation;
        address adminImplementation;
        address secondaryImplementation;
        address deployer; // address which deploys oracle
        address supply; // either liquidity layer or DEX protocol
        address borrow; // either liquidity layer or DEX protocol
        Tokens supplyToken; // if smart collateral then address of token0 & token1 else just supply token address at token0 and token1 as empty
        Tokens borrowToken; // if smart debt then address of token0 & token1 else just borrow token address at token0 and token1 as empty
        uint256 vaultId;
        uint256 vaultType;
        bytes32 supplyExchangePriceSlot; // if smart collateral then slot is from DEX protocol else from liquidity layer
        bytes32 borrowExchangePriceSlot; // if smart debt then slot is from DEX protocol else from liquidity layer
        bytes32 userSupplySlot; // if smart collateral then slot is from DEX protocol else from liquidity layer
        bytes32 userBorrowSlot; // if smart debt then slot is from DEX protocol else from liquidity layer
    }

    /// @notice returns all Vault constants
    function constantsView() external view returns (ConstantViews memory constantsView_);

    /// @notice fetches the latest user position after a liquidation
    function fetchLatestPosition(
        int256 positionTick_,
        uint256 positionTickId_,
        uint256 positionRawDebt_,
        uint256 tickData_
    )
        external
        view
        returns (
            int256, // tick
            uint256, // raw debt
            uint256, // raw collateral
            uint256, // branchID_
            uint256 // branchData_
        );

    /// @notice calculates the updated vault exchange prices
    function updateExchangePrices(
        uint256 vaultVariables2_
    )
        external
        view
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice calculates the updated vault exchange prices and writes them to storage
    function updateExchangePricesOnStorage()
        external
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice returns the liquidity contract address
    function LIQUIDITY() external view returns (address);

    error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);

    function rebalance(
        int colToken0MinMax_,
        int colToken1MinMax_,
        int debtToken0MinMax_,
        int debtToken1MinMax_
    ) external payable returns (int supplyAmt_, int borrowAmt_);

    /// @notice reverts with FluidLiquidateResult
    function simulateLiquidate(uint debtAmt_, bool absorb_) external;
}

File 25 of 26 : iVaultFactory.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

interface IFluidVaultFactory is IERC721Enumerable {
    /// @notice Minting an NFT Vault for the user
    function mint(uint256 vaultId_, address user_) external returns (uint256 tokenId_);

    /// @notice returns owner of Vault which is also an NFT
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /// @notice Global auth is auth for all vaults
    function isGlobalAuth(address auth_) external view returns (bool);

    /// @notice Vault auth is auth for a specific vault
    function isVaultAuth(address vault_, address auth_) external view returns (bool);

    /// @notice Total vaults deployed.
    function totalVaults() external view returns (uint256);

    /// @notice Compute vaultAddress
    function getVaultAddress(uint256 vaultId) external view returns (address);

    /// @notice read uint256 `result_` for a storage `slot_` key
    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);
}

File 26 of 26 : iVaultT1.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.21;

interface IFluidVaultT1 {
    /// @notice returns the vault id
    function VAULT_ID() external view returns (uint256);

    /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.
    function readFromStorage(bytes32 slot_) external view returns (uint256 result_);

    struct ConstantViews {
        address liquidity;
        address factory;
        address adminImplementation;
        address secondaryImplementation;
        address supplyToken;
        address borrowToken;
        uint8 supplyDecimals;
        uint8 borrowDecimals;
        uint vaultId;
        bytes32 liquiditySupplyExchangePriceSlot;
        bytes32 liquidityBorrowExchangePriceSlot;
        bytes32 liquidityUserSupplySlot;
        bytes32 liquidityUserBorrowSlot;
    }

    /// @notice returns all Vault constants
    function constantsView() external view returns (ConstantViews memory constantsView_);

    /// @notice fetches the latest user position after a liquidation
    function fetchLatestPosition(
        int256 positionTick_,
        uint256 positionTickId_,
        uint256 positionRawDebt_,
        uint256 tickData_
    )
        external
        view
        returns (
            int256, // tick
            uint256, // raw debt
            uint256, // raw collateral
            uint256, // branchID_
            uint256 // branchData_
        );

    /// @notice calculates the updated vault exchange prices
    function updateExchangePrices(
        uint256 vaultVariables2_
    )
        external
        view
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice calculates the updated vault exchange prices and writes them to storage
    function updateExchangePricesOnStorage()
        external
        returns (
            uint256 liqSupplyExPrice_,
            uint256 liqBorrowExPrice_,
            uint256 vaultSupplyExPrice_,
            uint256 vaultBorrowExPrice_
        );

    /// @notice returns the liquidity contract address
    function LIQUIDITY() external view returns (address);

    function operate(
        uint256 nftId_, // if 0 then new position
        int256 newCol_, // if negative then withdraw
        int256 newDebt_, // if negative then payback
        address to_ // address at which the borrow & withdraw amount should go to. If address(0) then it'll go to msg.sender
    )
        external
        payable
        returns (
            uint256, // nftId_
            int256, // final supply amount. if - then withdraw
            int256 // final borrow amount. if - then payback
        );

    function liquidate(
        uint256 debtAmt_,
        uint256 colPerUnitDebt_, // min collateral needed per unit of debt in 1e18
        address to_,
        bool absorb_
    ) external payable returns (uint actualDebtAmt_, uint actualColAmt_);

    function absorb() external;

    function rebalance() external payable returns (int supplyAmt_, int borrowAmt_);

    error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"factory_","type":"address"},{"internalType":"address","name":"liquidityResolver_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FACTORY","outputs":[{"internalType":"contract IFluidVaultFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDITY_RESOLVER","outputs":[{"internalType":"contract IFluidLiquidityResolver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"int256","name":"key1_","type":"int256"},{"internalType":"uint256","name":"key2_","type":"uint256"}],"name":"calculateDoubleIntUintMapping","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"int256","name":"key_","type":"int256"}],"name":"calculateStorageSlotIntMapping","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"},{"internalType":"uint256","name":"key_","type":"uint256"}],"name":"calculateStorageSlotUintMapping","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getAbsorbedDustDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getAbsorbedLiquidityRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllVaultsAddresses","outputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllVaultsLiquidation","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"token0In","type":"address"},{"internalType":"address","name":"token0Out","type":"address"},{"internalType":"address","name":"token1In","type":"address"},{"internalType":"address","name":"token1Out","type":"address"},{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"uint256","name":"inAmtWithAbsorb","type":"uint256"},{"internalType":"uint256","name":"outAmtWithAbsorb","type":"uint256"},{"internalType":"bool","name":"absorbAvailable","type":"bool"}],"internalType":"struct Structs.LiquidationStruct[]","name":"liquidationsData_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"uint256","name":"branch_","type":"uint256"}],"name":"getBranchDataRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"getContractForDeployerIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getDexFromAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"},{"internalType":"uint256[]","name":"tokensInAmt_","type":"uint256[]"}],"name":"getMultipleVaultsLiquidation","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"token0In","type":"address"},{"internalType":"address","name":"token0Out","type":"address"},{"internalType":"address","name":"token1In","type":"address"},{"internalType":"address","name":"token1Out","type":"address"},{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"uint256","name":"inAmtWithAbsorb","type":"uint256"},{"internalType":"uint256","name":"outAmtWithAbsorb","type":"uint256"},{"internalType":"bool","name":"absorbAvailable","type":"bool"}],"internalType":"struct Structs.LiquidationStruct[]","name":"liquidationsData_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"uint256","name":"positionId_","type":"uint256"}],"name":"getPositionDataRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getRateRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getRebalancer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"int256","name":"tick_","type":"int256"}],"name":"getTickDataRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"int256","name":"key_","type":"int256"}],"name":"getTickHasDebtRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"int256","name":"tick_","type":"int256"},{"internalType":"uint256","name":"id_","type":"uint256"}],"name":"getTickIdDataRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"getTokenConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalVaults","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultAbsorb","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"absorbAvailable","type":"bool"}],"internalType":"struct Structs.AbsorbStruct","name":"absorbData_","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId_","type":"uint256"}],"name":"getVaultAddress","outputs":[{"internalType":"address","name":"vault_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultEntireData","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"isSmartCol","type":"bool"},{"internalType":"bool","name":"isSmartDebt","type":"bool"},{"components":[{"internalType":"address","name":"liquidity","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"operateImplementation","type":"address"},{"internalType":"address","name":"adminImplementation","type":"address"},{"internalType":"address","name":"secondaryImplementation","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"supply","type":"address"},{"internalType":"address","name":"borrow","type":"address"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"supplyToken","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"borrowToken","type":"tuple"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"bytes32","name":"supplyExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"borrowExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"userSupplySlot","type":"bytes32"},{"internalType":"bytes32","name":"userBorrowSlot","type":"bytes32"}],"internalType":"struct IFluidVault.ConstantViews","name":"constantVariables","type":"tuple"},{"components":[{"internalType":"uint16","name":"supplyRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"borrowRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationMaxLimit","type":"uint16"},{"internalType":"uint16","name":"withdrawalGap","type":"uint16"},{"internalType":"uint16","name":"liquidationPenalty","type":"uint16"},{"internalType":"uint16","name":"borrowFee","type":"uint16"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"oraclePriceOperate","type":"uint256"},{"internalType":"uint256","name":"oraclePriceLiquidate","type":"uint256"},{"internalType":"address","name":"rebalancer","type":"address"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"}],"internalType":"struct Structs.Configs","name":"configs","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastStoredLiquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredLiquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRateLiquidity","type":"uint256"},{"internalType":"uint256","name":"borrowRateLiquidity","type":"uint256"},{"internalType":"int256","name":"supplyRateVault","type":"int256"},{"internalType":"int256","name":"borrowRateVault","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateSupply","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateBorrow","type":"int256"}],"internalType":"struct Structs.ExchangePricesAndRates","name":"exchangePricesAndRates","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalSupplyVault","type":"uint256"},{"internalType":"uint256","name":"totalBorrowVault","type":"uint256"},{"internalType":"uint256","name":"totalSupplyLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"totalBorrowLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"absorbedSupply","type":"uint256"},{"internalType":"uint256","name":"absorbedBorrow","type":"uint256"}],"internalType":"struct Structs.TotalSupplyAndBorrow","name":"totalSupplyAndBorrow","type":"tuple"},{"components":[{"internalType":"uint256","name":"withdrawLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"},{"internalType":"uint256","name":"minimumBorrowing","type":"uint256"}],"internalType":"struct Structs.LimitsAndAvailability","name":"limitsAndAvailability","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"int256","name":"topTick","type":"int256"},{"internalType":"uint256","name":"currentBranch","type":"uint256"},{"internalType":"uint256","name":"totalBranch","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"components":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"int256","name":"minimaTick","type":"int256"},{"internalType":"uint256","name":"debtFactor","type":"uint256"},{"internalType":"uint256","name":"partials","type":"uint256"},{"internalType":"uint256","name":"debtLiquidity","type":"uint256"},{"internalType":"uint256","name":"baseBranchId","type":"uint256"},{"internalType":"int256","name":"baseBranchMinima","type":"int256"}],"internalType":"struct Structs.CurrentBranchState","name":"currentBranchState","type":"tuple"}],"internalType":"struct Structs.VaultState","name":"vaultState","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"withdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseWithdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"}],"internalType":"struct Structs.UserSupplyData","name":"liquidityUserSupplyData","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"maxBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"}],"internalType":"struct Structs.UserBorrowData","name":"liquidityUserBorrowData","type":"tuple"}],"internalType":"struct Structs.VaultEntireData","name":"vaultData_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultId","outputs":[{"internalType":"uint256","name":"id_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"uint256","name":"tokenInAmt_","type":"uint256"}],"name":"getVaultLiquidation","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"token0In","type":"address"},{"internalType":"address","name":"token0Out","type":"address"},{"internalType":"address","name":"token1In","type":"address"},{"internalType":"address","name":"token1Out","type":"address"},{"internalType":"uint256","name":"inAmt","type":"uint256"},{"internalType":"uint256","name":"outAmt","type":"uint256"},{"internalType":"uint256","name":"inAmtWithAbsorb","type":"uint256"},{"internalType":"uint256","name":"outAmtWithAbsorb","type":"uint256"},{"internalType":"bool","name":"absorbAvailable","type":"bool"}],"internalType":"struct Structs.LiquidationStruct","name":"liquidationData_","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultState","outputs":[{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"int256","name":"topTick","type":"int256"},{"internalType":"uint256","name":"currentBranch","type":"uint256"},{"internalType":"uint256","name":"totalBranch","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"components":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"int256","name":"minimaTick","type":"int256"},{"internalType":"uint256","name":"debtFactor","type":"uint256"},{"internalType":"uint256","name":"partials","type":"uint256"},{"internalType":"uint256","name":"debtLiquidity","type":"uint256"},{"internalType":"uint256","name":"baseBranchId","type":"uint256"},{"internalType":"int256","name":"baseBranchMinima","type":"int256"}],"internalType":"struct Structs.CurrentBranchState","name":"currentBranchState","type":"tuple"}],"internalType":"struct Structs.VaultState","name":"vaultState_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultType","outputs":[{"internalType":"uint256","name":"vaultType_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultVariables2Raw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault_","type":"address"}],"name":"getVaultVariablesRaw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultsAbsorb","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"absorbAvailable","type":"bool"}],"internalType":"struct Structs.AbsorbStruct[]","name":"absorbData_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"}],"name":"getVaultsAbsorb","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"absorbAvailable","type":"bool"}],"internalType":"struct Structs.AbsorbStruct[]","name":"absorbData_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"vaults_","type":"address[]"}],"name":"getVaultsEntireData","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"isSmartCol","type":"bool"},{"internalType":"bool","name":"isSmartDebt","type":"bool"},{"components":[{"internalType":"address","name":"liquidity","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"operateImplementation","type":"address"},{"internalType":"address","name":"adminImplementation","type":"address"},{"internalType":"address","name":"secondaryImplementation","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"supply","type":"address"},{"internalType":"address","name":"borrow","type":"address"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"supplyToken","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"borrowToken","type":"tuple"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"bytes32","name":"supplyExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"borrowExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"userSupplySlot","type":"bytes32"},{"internalType":"bytes32","name":"userBorrowSlot","type":"bytes32"}],"internalType":"struct IFluidVault.ConstantViews","name":"constantVariables","type":"tuple"},{"components":[{"internalType":"uint16","name":"supplyRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"borrowRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationMaxLimit","type":"uint16"},{"internalType":"uint16","name":"withdrawalGap","type":"uint16"},{"internalType":"uint16","name":"liquidationPenalty","type":"uint16"},{"internalType":"uint16","name":"borrowFee","type":"uint16"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"oraclePriceOperate","type":"uint256"},{"internalType":"uint256","name":"oraclePriceLiquidate","type":"uint256"},{"internalType":"address","name":"rebalancer","type":"address"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"}],"internalType":"struct Structs.Configs","name":"configs","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastStoredLiquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredLiquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRateLiquidity","type":"uint256"},{"internalType":"uint256","name":"borrowRateLiquidity","type":"uint256"},{"internalType":"int256","name":"supplyRateVault","type":"int256"},{"internalType":"int256","name":"borrowRateVault","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateSupply","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateBorrow","type":"int256"}],"internalType":"struct Structs.ExchangePricesAndRates","name":"exchangePricesAndRates","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalSupplyVault","type":"uint256"},{"internalType":"uint256","name":"totalBorrowVault","type":"uint256"},{"internalType":"uint256","name":"totalSupplyLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"totalBorrowLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"absorbedSupply","type":"uint256"},{"internalType":"uint256","name":"absorbedBorrow","type":"uint256"}],"internalType":"struct Structs.TotalSupplyAndBorrow","name":"totalSupplyAndBorrow","type":"tuple"},{"components":[{"internalType":"uint256","name":"withdrawLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"},{"internalType":"uint256","name":"minimumBorrowing","type":"uint256"}],"internalType":"struct Structs.LimitsAndAvailability","name":"limitsAndAvailability","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"int256","name":"topTick","type":"int256"},{"internalType":"uint256","name":"currentBranch","type":"uint256"},{"internalType":"uint256","name":"totalBranch","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"components":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"int256","name":"minimaTick","type":"int256"},{"internalType":"uint256","name":"debtFactor","type":"uint256"},{"internalType":"uint256","name":"partials","type":"uint256"},{"internalType":"uint256","name":"debtLiquidity","type":"uint256"},{"internalType":"uint256","name":"baseBranchId","type":"uint256"},{"internalType":"int256","name":"baseBranchMinima","type":"int256"}],"internalType":"struct Structs.CurrentBranchState","name":"currentBranchState","type":"tuple"}],"internalType":"struct Structs.VaultState","name":"vaultState","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"withdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseWithdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"}],"internalType":"struct Structs.UserSupplyData","name":"liquidityUserSupplyData","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"maxBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"}],"internalType":"struct Structs.UserBorrowData","name":"liquidityUserBorrowData","type":"tuple"}],"internalType":"struct Structs.VaultEntireData[]","name":"vaultsData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultsEntireData","outputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"isSmartCol","type":"bool"},{"internalType":"bool","name":"isSmartDebt","type":"bool"},{"components":[{"internalType":"address","name":"liquidity","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"operateImplementation","type":"address"},{"internalType":"address","name":"adminImplementation","type":"address"},{"internalType":"address","name":"secondaryImplementation","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"supply","type":"address"},{"internalType":"address","name":"borrow","type":"address"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"supplyToken","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"borrowToken","type":"tuple"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"bytes32","name":"supplyExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"borrowExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"userSupplySlot","type":"bytes32"},{"internalType":"bytes32","name":"userBorrowSlot","type":"bytes32"}],"internalType":"struct IFluidVault.ConstantViews","name":"constantVariables","type":"tuple"},{"components":[{"internalType":"uint16","name":"supplyRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"borrowRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationMaxLimit","type":"uint16"},{"internalType":"uint16","name":"withdrawalGap","type":"uint16"},{"internalType":"uint16","name":"liquidationPenalty","type":"uint16"},{"internalType":"uint16","name":"borrowFee","type":"uint16"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"oraclePriceOperate","type":"uint256"},{"internalType":"uint256","name":"oraclePriceLiquidate","type":"uint256"},{"internalType":"address","name":"rebalancer","type":"address"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"}],"internalType":"struct Structs.Configs","name":"configs","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastStoredLiquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredLiquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRateLiquidity","type":"uint256"},{"internalType":"uint256","name":"borrowRateLiquidity","type":"uint256"},{"internalType":"int256","name":"supplyRateVault","type":"int256"},{"internalType":"int256","name":"borrowRateVault","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateSupply","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateBorrow","type":"int256"}],"internalType":"struct Structs.ExchangePricesAndRates","name":"exchangePricesAndRates","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalSupplyVault","type":"uint256"},{"internalType":"uint256","name":"totalBorrowVault","type":"uint256"},{"internalType":"uint256","name":"totalSupplyLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"totalBorrowLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"absorbedSupply","type":"uint256"},{"internalType":"uint256","name":"absorbedBorrow","type":"uint256"}],"internalType":"struct Structs.TotalSupplyAndBorrow","name":"totalSupplyAndBorrow","type":"tuple"},{"components":[{"internalType":"uint256","name":"withdrawLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"},{"internalType":"uint256","name":"minimumBorrowing","type":"uint256"}],"internalType":"struct Structs.LimitsAndAvailability","name":"limitsAndAvailability","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"int256","name":"topTick","type":"int256"},{"internalType":"uint256","name":"currentBranch","type":"uint256"},{"internalType":"uint256","name":"totalBranch","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"components":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"int256","name":"minimaTick","type":"int256"},{"internalType":"uint256","name":"debtFactor","type":"uint256"},{"internalType":"uint256","name":"partials","type":"uint256"},{"internalType":"uint256","name":"debtLiquidity","type":"uint256"},{"internalType":"uint256","name":"baseBranchId","type":"uint256"},{"internalType":"int256","name":"baseBranchMinima","type":"int256"}],"internalType":"struct Structs.CurrentBranchState","name":"currentBranchState","type":"tuple"}],"internalType":"struct Structs.VaultState","name":"vaultState","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"withdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseWithdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"}],"internalType":"struct Structs.UserSupplyData","name":"liquidityUserSupplyData","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"maxBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"}],"internalType":"struct Structs.UserBorrowData","name":"liquidityUserBorrowData","type":"tuple"}],"internalType":"struct Structs.VaultEntireData[]","name":"vaultsData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"slot_","type":"uint256"}],"name":"normalSlot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"positionByNftId","outputs":[{"components":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"isLiquidated","type":"bool"},{"internalType":"bool","name":"isSupplyPosition","type":"bool"},{"internalType":"int256","name":"tick","type":"int256"},{"internalType":"uint256","name":"tickId","type":"uint256"},{"internalType":"uint256","name":"beforeSupply","type":"uint256"},{"internalType":"uint256","name":"beforeBorrow","type":"uint256"},{"internalType":"uint256","name":"beforeDustBorrow","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"dustBorrow","type":"uint256"}],"internalType":"struct Structs.UserPosition","name":"userPosition_","type":"tuple"},{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"isSmartCol","type":"bool"},{"internalType":"bool","name":"isSmartDebt","type":"bool"},{"components":[{"internalType":"address","name":"liquidity","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"operateImplementation","type":"address"},{"internalType":"address","name":"adminImplementation","type":"address"},{"internalType":"address","name":"secondaryImplementation","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"supply","type":"address"},{"internalType":"address","name":"borrow","type":"address"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"supplyToken","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"borrowToken","type":"tuple"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"bytes32","name":"supplyExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"borrowExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"userSupplySlot","type":"bytes32"},{"internalType":"bytes32","name":"userBorrowSlot","type":"bytes32"}],"internalType":"struct IFluidVault.ConstantViews","name":"constantVariables","type":"tuple"},{"components":[{"internalType":"uint16","name":"supplyRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"borrowRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationMaxLimit","type":"uint16"},{"internalType":"uint16","name":"withdrawalGap","type":"uint16"},{"internalType":"uint16","name":"liquidationPenalty","type":"uint16"},{"internalType":"uint16","name":"borrowFee","type":"uint16"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"oraclePriceOperate","type":"uint256"},{"internalType":"uint256","name":"oraclePriceLiquidate","type":"uint256"},{"internalType":"address","name":"rebalancer","type":"address"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"}],"internalType":"struct Structs.Configs","name":"configs","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastStoredLiquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredLiquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRateLiquidity","type":"uint256"},{"internalType":"uint256","name":"borrowRateLiquidity","type":"uint256"},{"internalType":"int256","name":"supplyRateVault","type":"int256"},{"internalType":"int256","name":"borrowRateVault","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateSupply","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateBorrow","type":"int256"}],"internalType":"struct Structs.ExchangePricesAndRates","name":"exchangePricesAndRates","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalSupplyVault","type":"uint256"},{"internalType":"uint256","name":"totalBorrowVault","type":"uint256"},{"internalType":"uint256","name":"totalSupplyLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"totalBorrowLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"absorbedSupply","type":"uint256"},{"internalType":"uint256","name":"absorbedBorrow","type":"uint256"}],"internalType":"struct Structs.TotalSupplyAndBorrow","name":"totalSupplyAndBorrow","type":"tuple"},{"components":[{"internalType":"uint256","name":"withdrawLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"},{"internalType":"uint256","name":"minimumBorrowing","type":"uint256"}],"internalType":"struct Structs.LimitsAndAvailability","name":"limitsAndAvailability","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"int256","name":"topTick","type":"int256"},{"internalType":"uint256","name":"currentBranch","type":"uint256"},{"internalType":"uint256","name":"totalBranch","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"components":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"int256","name":"minimaTick","type":"int256"},{"internalType":"uint256","name":"debtFactor","type":"uint256"},{"internalType":"uint256","name":"partials","type":"uint256"},{"internalType":"uint256","name":"debtLiquidity","type":"uint256"},{"internalType":"uint256","name":"baseBranchId","type":"uint256"},{"internalType":"int256","name":"baseBranchMinima","type":"int256"}],"internalType":"struct Structs.CurrentBranchState","name":"currentBranchState","type":"tuple"}],"internalType":"struct Structs.VaultState","name":"vaultState","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"withdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseWithdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"}],"internalType":"struct Structs.UserSupplyData","name":"liquidityUserSupplyData","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"maxBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"}],"internalType":"struct Structs.UserBorrowData","name":"liquidityUserBorrowData","type":"tuple"}],"internalType":"struct Structs.VaultEntireData","name":"vaultData_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"positionsByUser","outputs":[{"components":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"isLiquidated","type":"bool"},{"internalType":"bool","name":"isSupplyPosition","type":"bool"},{"internalType":"int256","name":"tick","type":"int256"},{"internalType":"uint256","name":"tickId","type":"uint256"},{"internalType":"uint256","name":"beforeSupply","type":"uint256"},{"internalType":"uint256","name":"beforeBorrow","type":"uint256"},{"internalType":"uint256","name":"beforeDustBorrow","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"dustBorrow","type":"uint256"}],"internalType":"struct Structs.UserPosition[]","name":"userPositions_","type":"tuple[]"},{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"isSmartCol","type":"bool"},{"internalType":"bool","name":"isSmartDebt","type":"bool"},{"components":[{"internalType":"address","name":"liquidity","type":"address"},{"internalType":"address","name":"factory","type":"address"},{"internalType":"address","name":"operateImplementation","type":"address"},{"internalType":"address","name":"adminImplementation","type":"address"},{"internalType":"address","name":"secondaryImplementation","type":"address"},{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"supply","type":"address"},{"internalType":"address","name":"borrow","type":"address"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"supplyToken","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"internalType":"struct IFluidVault.Tokens","name":"borrowToken","type":"tuple"},{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"bytes32","name":"supplyExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"borrowExchangePriceSlot","type":"bytes32"},{"internalType":"bytes32","name":"userSupplySlot","type":"bytes32"},{"internalType":"bytes32","name":"userBorrowSlot","type":"bytes32"}],"internalType":"struct IFluidVault.ConstantViews","name":"constantVariables","type":"tuple"},{"components":[{"internalType":"uint16","name":"supplyRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"borrowRateMagnifier","type":"uint16"},{"internalType":"uint16","name":"collateralFactor","type":"uint16"},{"internalType":"uint16","name":"liquidationThreshold","type":"uint16"},{"internalType":"uint16","name":"liquidationMaxLimit","type":"uint16"},{"internalType":"uint16","name":"withdrawalGap","type":"uint16"},{"internalType":"uint16","name":"liquidationPenalty","type":"uint16"},{"internalType":"uint16","name":"borrowFee","type":"uint16"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint256","name":"oraclePriceOperate","type":"uint256"},{"internalType":"uint256","name":"oraclePriceLiquidate","type":"uint256"},{"internalType":"address","name":"rebalancer","type":"address"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"}],"internalType":"struct Structs.Configs","name":"configs","type":"tuple"},{"components":[{"internalType":"uint256","name":"lastStoredLiquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredLiquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"lastStoredVaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquiditySupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"liquidityBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultSupplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"vaultBorrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRateLiquidity","type":"uint256"},{"internalType":"uint256","name":"borrowRateLiquidity","type":"uint256"},{"internalType":"int256","name":"supplyRateVault","type":"int256"},{"internalType":"int256","name":"borrowRateVault","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateSupply","type":"int256"},{"internalType":"int256","name":"rewardsOrFeeRateBorrow","type":"int256"}],"internalType":"struct Structs.ExchangePricesAndRates","name":"exchangePricesAndRates","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalSupplyVault","type":"uint256"},{"internalType":"uint256","name":"totalBorrowVault","type":"uint256"},{"internalType":"uint256","name":"totalSupplyLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"totalBorrowLiquidityOrDex","type":"uint256"},{"internalType":"uint256","name":"absorbedSupply","type":"uint256"},{"internalType":"uint256","name":"absorbedBorrow","type":"uint256"}],"internalType":"struct Structs.TotalSupplyAndBorrow","name":"totalSupplyAndBorrow","type":"tuple"},{"components":[{"internalType":"uint256","name":"withdrawLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"},{"internalType":"uint256","name":"minimumBorrowing","type":"uint256"}],"internalType":"struct Structs.LimitsAndAvailability","name":"limitsAndAvailability","type":"tuple"},{"components":[{"internalType":"uint256","name":"totalPositions","type":"uint256"},{"internalType":"int256","name":"topTick","type":"int256"},{"internalType":"uint256","name":"currentBranch","type":"uint256"},{"internalType":"uint256","name":"totalBranch","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"components":[{"internalType":"uint256","name":"status","type":"uint256"},{"internalType":"int256","name":"minimaTick","type":"int256"},{"internalType":"uint256","name":"debtFactor","type":"uint256"},{"internalType":"uint256","name":"partials","type":"uint256"},{"internalType":"uint256","name":"debtLiquidity","type":"uint256"},{"internalType":"uint256","name":"baseBranchId","type":"uint256"},{"internalType":"int256","name":"baseBranchMinima","type":"int256"}],"internalType":"struct Structs.CurrentBranchState","name":"currentBranchState","type":"tuple"}],"internalType":"struct Structs.VaultState","name":"vaultState","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"withdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseWithdrawalLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"withdrawable","type":"uint256"}],"internalType":"struct Structs.UserSupplyData","name":"liquidityUserSupplyData","type":"tuple"},{"components":[{"internalType":"bool","name":"modeWithInterest","type":"bool"},{"internalType":"uint256","name":"borrow","type":"uint256"},{"internalType":"uint256","name":"borrowLimit","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"expandPercent","type":"uint256"},{"internalType":"uint256","name":"expandDuration","type":"uint256"},{"internalType":"uint256","name":"baseBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"maxBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"borrowableUntilLimit","type":"uint256"},{"internalType":"uint256","name":"borrowable","type":"uint256"},{"internalType":"uint256","name":"borrowLimitUtilization","type":"uint256"}],"internalType":"struct Structs.UserBorrowData","name":"liquidityUserBorrowData","type":"tuple"}],"internalType":"struct Structs.VaultEntireData[]","name":"vaultsData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"positionsNftIdOfUser","outputs":[{"internalType":"uint256[]","name":"nftIds_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tickRaw_","type":"uint256"}],"name":"tickHelper","outputs":[{"internalType":"int256","name":"tick","type":"int256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalPositions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"vaultByNftId","outputs":[{"internalType":"address","name":"vault_","type":"address"}],"stateMutability":"view","type":"function"}]

60c06040523480156200001157600080fd5b50604051620060b5380380620060b5833981016040819052620000349162000069565b6001600160a01b039182166080521660a052620000a1565b80516001600160a01b03811681146200006457600080fd5b919050565b600080604083850312156200007d57600080fd5b62000088836200004c565b915062000098602084016200004c565b90509250929050565b60805160a051615fa86200010d6000396000818161050d0152818161081901526108ff01526000818161044a01528181610b320152818161103301528181611ca201528181611fc1015281816122e1015281816123ea015281816126be01526127f40152615fa86000f3fe608060405234801561001057600080fd5b50600436106102d35760003560e01c80637955fffd11610186578063a8d9f493116100e3578063e06a7b7111610097578063eb1db01811610071578063eb1db01814610676578063f70b198c14610689578063fda1fa5f1461069c57600080fd5b8063e06a7b7114610648578063e6bd26a214610650578063ea19ba111461066357600080fd5b8063c67b5093116100c8578063c67b50931461060d578063cbc7be651461062d578063dd19c0fe1461064057600080fd5b8063a8d9f493146105e5578063bf518f5f146105fa57600080fd5b80638a0038881161013a5780638f8b81f01161011f5780638f8b81f0146105ae5780639d7aeeb4146105c1578063a8bc0693146105d257600080fd5b80638a003888146105885780638bfbeda61461059b57600080fd5b8063816022b81161016b578063816022b8146105425780638530330414610555578063890a13911461056857600080fd5b80637955fffd1461052f5780637bbede431461046c57600080fd5b80632404a3f911610234578063347ca8bb116101e85780635486f100116101cd5780635486f100146104ed5780636463e94c146104f55780636902f79f1461050857600080fd5b8063347ca8bb146104b957806351971bf7146104da57600080fd5b80632dd31000116102195780632dd31000146104455780632f2612cf1461046c578063344bd722146104a657600080fd5b80632404a3f9146104105780632c44e1d11461042557600080fd5b80631949138e1161028b5780631f51fd93116102705780631f51fd93146103bd5780631fcd3649146103d057806320ee1e44146103f057600080fd5b80631949138e146103655780631ef8986d1461039d57600080fd5b8063144128e8116102bc578063144128e81461031e5780631579a46c1461033f578063168a11c21461035257600080fd5b806303e883e0146102d857806309c062e2146102fe575b600080fd5b6102eb6102e63660046147c8565b6106a4565b6040519081526020015b60405180910390f35b61031161030c3660046147c8565b610729565b6040516102f59190614dd9565b61033161032c366004614de8565b610a37565b6040516102f5929190614eaa565b6102eb61034d3660046147c8565b610f17565b6102eb610360366004614ec7565b610f3c565b610378610373366004614de8565b610fec565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102f5565b6103b06103ab36600461510b565b6110b3565b6040516102f59190615186565b6102eb6103cb3660046147c8565b611171565b6103e36103de366004614ec7565b611277565b6040516102f59190615297565b6104036103fe3660046147c8565b6117dc565b6040516102f591906152a6565b610418611928565b6040516102f59190615329565b610438610433366004615398565b61193a565b6040516102f5919061545e565b6103787f000000000000000000000000000000000000000000000000000000000000000081565b6102eb61047a3660046154ad565b604080516020808201939093528082019390935280518084038201815260609093019052815191012090565b6102eb6104b43660046147c8565b611a77565b6104cc6104c73660046147c8565b611ac4565b6040516102f59291906154cf565b6102eb6104e83660046147c8565b611c79565b6102eb611c9e565b6103786105033660046147c8565b611d2f565b6103787f000000000000000000000000000000000000000000000000000000000000000081565b61037861053d3660046147c8565b611d54565b610378610550366004614ec7565b611d79565b6102eb610563366004615531565b611ddb565b61057b6105763660046147c8565b611e64565b6040516102f59190615566565b6102eb610596366004614de8565b611f7f565b6102eb6105a9366004615595565b611fed565b6102eb6105bc366004614de8565b612073565b6102eb6105cf366004614de8565b90565b6102eb6105e0366004614ec7565b612140565b6105ed61218e565b6040516102f591906155c1565b6102eb610608366004614ec7565b612248565b61062061061b3660046147c8565b612296565b6040516102f5919061560f565b6102eb61063b366004614ec7565b612484565b6104386124d2565b6103b0612601565b61037861065e366004614de8565b6126b7565b61041861067136600461510b565b6126e3565b6102eb6106843660046147c8565b6127a6565b6102eb6106973660046147c8565b6127cb565b6102eb6127f0565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e4825b6040518263ffffffff1660e01b81526004016106e291815260200190565b602060405180830381865afa1580156106ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107239190615647565b92915050565b610731614433565b73ffffffffffffffffffffffffffffffffffffffff82168152600061075583611171565b90508015610a3157610767838261285d565b6060830181905261010081015160209081015173ffffffffffffffffffffffffffffffffffffffff90811615158286018190526101209093015190910151161515604084015260009081908190819081906108995760608701516101000151516040517fe72ef91b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152918216602482015260009182917f00000000000000000000000000000000000000000000000000000000000000009091169063e72ef91b906044016104c060405180830381865afa158015610863573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088791906158a1565b6101208b019190915260200151935050505b86604001516109955760608701516101200151516040517f967915d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152918216602482015260009182917f00000000000000000000000000000000000000000000000000000000000000009091169063967915d69060440161050060405180830381865afa158015610949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096d9190615947565b610140808c018390529051604083015191830151610100909301519199509197509550925050505b6109a88888606001516101600151612aea565b608088018190526109be90899088908585612e6b565b60a0880181905260608801516109d79350899250613116565b8560c00181905250610a0d8560a001518660600151876080015160a0015161ffff168686868b61012001518c6101400151613417565b61014088015261012087015260e0860152610a27866117dc565b6101008601525050505b50919050565b610ab560405180610180016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b610abd614433565b8282526000610acb84610fec565b905073ffffffffffffffffffffffffffffffffffffffff811615610f11576000610af58286612484565b9050610b0082610729565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018790529093507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690636352211e90602401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb291906159fa565b73ffffffffffffffffffffffffffffffffffffffff1660208501526001808216146060850181905266ffffffffffffff603583901c811660ff602d85901c81169190911b610120880181905260c0880152607584901c909116606d84901c9091161b6101608601819052610100860152610df65780600216600214610c4857610c43600282901c6207ffff16615a46565b610c53565b6207ffff600282901c165b60808501819052601582901c62ffffff1660a0860152610120850151606091610c7e9060020b613bad565b610c889190615a7e565b901c6101408501819052610100850151610ca191615a95565b60e08501526080840151600090610cb9908490610f3c565b90508060011660011480610cd957508460a0015162ffffff600183901c16115b15610db0576001604086810191909152608086015160a087015161014088015192517f22348cc70000000000000000000000000000000000000000000000000000000081526004810192909252602482015260448101919091526064810182905273ffffffffffffffffffffffffffffffffffffffff8416906322348cc79060840160a060405180830381865afa158015610d78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9c9190615aa8565b505061012088015261014087015260808601525b8461016001518561014001511115610de357846101600151856101400151610dd89190615a95565b610140860152610df4565b600061014086018190526101608601525b505b64e8d4a510008360a0015160c001518560c00151610e149190615a7e565b610e1e9190615b17565b60c085015260a083015160e0908101519085015164e8d4a5100091610e4291615a7e565b610e4c9190615b17565b60e08086019190915260a0840151015161010085015164e8d4a5100091610e7291615a7e565b610e7c9190615b17565b61010085015260a083015160c0015161012085015164e8d4a5100091610ea191615a7e565b610eab9190615b17565b61012085015260a083015160e0015161014085015164e8d4a5100091610ed091615a7e565b610eda9190615b17565b61014085015260a083015160e0015161016085015164e8d4a5100091610eff91615a7e565b610f099190615b17565b610160850152505b50915091565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460086106c4565b6040805160208082018490526005828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e4905b6040518263ffffffff1660e01b8152600401610fa491815260200190565b602060405180830381865afa158015610fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe59190615647565b9392505050565b600080610ff883611f7f565b6040517fe6bd26a200000000000000000000000000000000000000000000000000000000815263ffffffff60c083901c1660048201529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e6bd26a290602401602060405180830381865afa15801561108f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe591906159fa565b80516060908067ffffffffffffffff8111156110d1576110d1614ef3565b60405190808252806020026020018201604052801561110a57816020015b6110f7614433565b8152602001906001900390816110ef5790505b50915060005b8181101561116a5761113a84828151811061112d5761112d615b52565b6020026020010151610729565b83828151811061114c5761114c615b52565b6020026020010181905250808061116290615b81565b915050611110565b5050919050565b60008173ffffffffffffffffffffffffffffffffffffffff163b60000361119a57506000919050565b8173ffffffffffffffffffffffffffffffffffffffff1663bb24fe8a6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561121f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261121c91810190615647565b60015b610723578173ffffffffffffffffffffffffffffffffffffffff1661124661065e84611a77565b73ffffffffffffffffffffffffffffffffffffffff161461126957506000919050565b50612710919050565b919050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081019190915281156112d457816112e6565b6fffffffffffffffffffffffffffffffff5b915060006112f384611171565b905080156117d55773ffffffffffffffffffffffffffffffffffffffff841682526000611320858361285d565b9050612710816101600151036115cb576101208101515173ffffffffffffffffffffffffffffffffffffffff9081166020850152610100820151518116604080860191909152517f8433ea220000000000000000000000000000000000000000000000000000000081526004810186905260006024820181905261dead6044830152606482015290861690638433ea229060840160408051808303816000875af192505050801561140c575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261140991810190615bb9565b60015b61148857611418615bdd565b806308c379a00361143d575061142c615bf8565b80611437575061143f565b5061148b565b505b3d808015611469576040519150601f19603f3d011682016040523d82523d6000602084013e61146e565b606091505b5061147881613e0f565b60c086015260a08501525061148b565b50505b6040517f8433ea22000000000000000000000000000000000000000000000000000000008152600481018590526000602482015261dead60448201526001606482015273ffffffffffffffffffffffffffffffffffffffff861690638433ea229060840160408051808303816000875af1925050508015611547575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261154491810190615bb9565b60015b6115c457611553615bdd565b806308c379a0036115785750611567615bf8565b80611572575061157a565b506117ad565b505b3d8080156115a4576040519150601f19603f3d011682016040523d82523d6000602084013e6115a9565b606091505b506115b381613e0f565b61010086015260e0850152506117ad565b50506117ad565b610120810180515173ffffffffffffffffffffffffffffffffffffffff908116602086810191909152610100840180515183166040808901919091529351820151831660608801525101518116608086015290517f3202937e000000000000000000000000000000000000000000000000000000008152600060048201819052602482015290861690633202937e90604401600060405180830381600087803b15801561167757600080fd5b505af1925050508015611688575060015b61170057611694615bdd565b806308c379a0036116b957506116a8615bf8565b806116b357506116bb565b50611700565b505b3d8080156116e5576040519150601f19603f3d011682016040523d82523d6000602084013e6116ea565b606091505b506116f481613e0f565b60c086015260a0850152505b6040517f3202937e000000000000000000000000000000000000000000000000000000008152600060048201526001602482015273ffffffffffffffffffffffffffffffffffffffff861690633202937e90604401600060405180830381600087803b15801561176f57600080fd5b505af1925050508015611780575060015b6117ad5761178c615bdd565b806308c379a00361157857506117a0615bf8565b806117ab575061157a565b505b8260a001518360e0015111806117cb57508260c00151836101000151115b1515610120840152505b5092915050565b6117e461472e565b60006117ef836106a4565b9050611803620fffff600283901c16612073565b6020830152633fffffff601682901c81166040840152603482901c16606083015266ffffffffffffff605a82901c1660ff605283901c161b60a083015266ffffffffffffff609a82901c1660ff609283901c161b608083015260d281901c63ffffffff168252604082015160009061187c908590612248565b60c0840151600382169052905061189b600282901c620fffff16612073565b60c0840180516020019190915280516603ffffffffffff607484901c1660409091015251633fffffff601683901c1660609091015266ffffffffffffff603c82901c1660ff603483901c161b60c084018051608001919091525160a682901c633fffffff1660a09091015261191860c482901c620fffff16612073565b60c0808501510152509092915050565b606061193561067161218e565b905090565b81516060908067ffffffffffffffff81111561195857611958614ef3565b6040519080825280602002602001820160405280156119f557816020015b604080516101408101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816119765790505b50915060005b81811015611a6f57611a3f858281518110611a1857611a18615b52565b6020026020010151858381518110611a3257611a32615b52565b6020026020010151611277565b838281518110611a5157611a51615b52565b60200260200101819052508080611a6790615b81565b9150506119fb565b505092915050565b60008173ffffffffffffffffffffffffffffffffffffffff1663540acabc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ff573d6000803e3d6000fd5b6060806000611ad284612296565b80519091508067ffffffffffffffff811115611af057611af0614ef3565b604051908082528060200260200182016040528015611b9f57816020015b611b8c60405180610180016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611b0e5790505b5093508067ffffffffffffffff811115611bbb57611bbb614ef3565b604051908082528060200260200182016040528015611bf457816020015b611be1614433565b815260200190600190039081611bd95790505b50925060005b81811015611c7157611c24838281518110611c1757611c17615b52565b6020026020010151610a37565b868381518110611c3657611c36615b52565b60200260200101868481518110611c4f57611c4f615b52565b6020026020010182905282905250508080611c6990615b81565b915050611bfa565b505050915091565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e4600a6106c4565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638d6540236040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d0b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119359190615647565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460096106c4565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e4600b6106c4565b600080611d8e84611d8986611171565b61285d565b60a081015190915073ffffffffffffffffffffffffffffffffffffffff161580611db6575082155b15611dc5576000915050610723565b611dd38160a0015184613e7d565b949350505050565b60008373ffffffffffffffffffffffffffffffffffffffff1663b5c736e4611e0560068686611fed565b6040518263ffffffff1660e01b8152600401611e2391815260200190565b602060405180830381865afa158015611e40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dd39190615647565b6040805180820190915260006020820181905273ffffffffffffffffffffffffffffffffffffffff83168252611e99836127cb565b90508273ffffffffffffffffffffffffffffffffffffffff1663ebd93ac66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ee357600080fd5b505af1925050508015611ef4575060015b611f5d57611f00615bdd565b806308c379a003611f255750611f14615bf8565b80611f1f5750611f27565b50610a31565b505b3d808015611f51576040519150601f19603f3d011682016040523d82523d6000602084013e611f56565b606091505b5050610a31565b6000611f68846127cb565b905081811461116a57600160208401525050919050565b6040805160208082018490526003828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e4906106c4565b600080838560405160200161200c929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083018690529082018190529150606001604051602081830303815290604052805190602001209150509392505050565b6000620fffff82106120e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642d6e756d626572000000000000000000000000000000000000604482015260640160405180910390fd5b8115612119578160011660011461210d57612108600183901c6207ffff16615a46565b610723565b5060011c6207ffff1690565b507f8000000000000000000000000000000000000000000000000000000000000000919050565b6040805160208082018490526004828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e490610f86565b6060600061219a611c9e565b90508067ffffffffffffffff8111156121b5576121b5614ef3565b6040519080825280602002602001820160405280156121de578160200160208202803683370190505b50915060005b81811015612243576121fa61065e826001615ca0565b83828151811061220c5761220c615b52565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101528061223b81615b81565b9150506121e4565b505090565b6040805160208082018490526007828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e490610f86565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526060916000917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234c9190615647565b90508067ffffffffffffffff81111561236757612367614ef3565b604051908082528060200260200182016040528015612390578160200160208202803683370190505b50915060005b8181101561116a576040517f2f745c5900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390527f00000000000000000000000000000000000000000000000000000000000000001690632f745c5990604401602060405180830381865afa158015612431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124559190615647565b83828151811061246757612467615b52565b60209081029190910101528061247c81615b81565b915050612396565b6040805160208082018490526003828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e490610f86565b606060006124de61218e565b80519091508067ffffffffffffffff8111156124fc576124fc614ef3565b60405190808252806020026020018201604052801561259957816020015b604080516101408101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161251a5790505b50925060005b818110156125fb576125cb8382815181106125bc576125bc615b52565b60200260200101516000611277565b8482815181106125dd576125dd615b52565b602002602001018190525080806125f390615b81565b91505061259f565b50505090565b6060600061260d61218e565b80519091508067ffffffffffffffff81111561262b5761262b614ef3565b60405190808252806020026020018201604052801561266457816020015b612651614433565b8152602001906001900390816126495790505b50925060005b818110156125fb5761268783828151811061112d5761112d615b52565b84828151811061269957612699615b52565b602002602001018190525080806126af90615b81565b91505061266a565b60006107237f000000000000000000000000000000000000000000000000000000000000000083613e7d565b80516060908067ffffffffffffffff81111561270157612701614ef3565b60405190808252806020026020018201604052801561274657816020015b604080518082019091526000808252602082015281526020019060019003908161271f5790505b50915060005b8181101561116a5761277684828151811061276957612769615b52565b6020026020010151611e64565b83828151811061278857612788615b52565b6020026020010181905250808061279e90615b81565b91505061274c565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460016106c4565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460026106c4565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d0b573d6000803e3d6000fd5b6128fc604080516102008101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905260e0830182905283518085018552828152808201839052610100840152835180850190945281845283015290610120820190815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b6127108203612a7a578273ffffffffffffffffffffffffffffffffffffffff1663b7791bf26040518163ffffffff1660e01b81526004016101a060405180830381865afa92505050801561298b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261298891810190615cc4565b60015b1561072357805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182168185015285821660408086019190915283015182166060808601919091528301518216608080860191909152600060a08087018290528551851660c08801528551851660e0880152918501516101008088018051928716909252905184018290529185015161012080880180519290961690915293519092019190915282015161014080850191909152612710610160808601919091529183015161018080860191909152908301516101a0850152908201516101c084015201516101e0820152610723565b8273ffffffffffffffffffffffffffffffffffffffff1663b7791bf26040518163ffffffff1660e01b815260040161024060405180830381865afa158015612ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe59190615e06565b604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101829052610180810182905290612b5c846127a6565b61ffff8082168452601082901c16602080850191909152909150612b889082901c6103ff16600a615f1e565b61ffff166040830152612ba4602a82901c6103ff16600a615f1e565b61ffff166060830152612bc0603482901c6103ff16600a615f1e565b61ffff166080830152612bdc603e82901c6103ff16600a615f1e565b61ffff1660a08301526103ff604882901c811660c0840152605282901c1660e08301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f08301612c3657606081901c610100830152612c82565b605c81901c633fffffff168015612c6e57612c518582611d79565b73ffffffffffffffffffffffffffffffffffffffff166101008401525b50607a81901c6401ffffffff166101808301525b61010082015173ffffffffffffffffffffffffffffffffffffffff1615612e3f5781610100015173ffffffffffffffffffffffffffffffffffffffff16638e7bfbc06040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612d2d575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612d2a91810190615647565b60015b612db85781610100015173ffffffffffffffffffffffffffffffffffffffff1663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da59190615647565b6101208301819052610140830152612e3f565b808361012001818152505082610100015173ffffffffffffffffffffffffffffffffffffffff1663f3190c896040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e379190615647565b610140840152505b612e4884611d2f565b73ffffffffffffffffffffffffffffffffffffffff166101608301525092915050565b612edd604051806101c0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000612ee887610f17565b67ffffffffffffffff8082168452604082811c82166020860152608083901c9091169084015260c081901c6060840152905073ffffffffffffffffffffffffffffffffffffffff87166309f0d8cb612f3f896127a6565b6040518263ffffffff1660e01b8152600401612f5d91815260200190565b608060405180830381865afa158015612f7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9e9190615f3c565b60e086015260c085015260a0840152608083015261010082018490526101208201839052614e20861480612fd35750619c4086145b1561301a578451600190811c617fff166101408401528551166000036130095781610140015161300290615a46565b6101408301525b61014082015161018083015261305c565b84516127109061ffff16850204610140830152845161ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f0016101808301525b61753086148061306d5750619c4086145b156130b857602085018051600190811c617fff166101608501529051166000036130a7578161016001516130a090615a46565b6101608301525b6101608201516101a083015261310c565b612710856020015161ffff168402816130d3576130d3615ae8565b04610160830152602085015161ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f0016101a08301525b5095945050505050565b61314f6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600061315a856106a4565b90506000613167866127cb565b905060008460c0015173ffffffffffffffffffffffffffffffffffffffff1663b5c736e4866101c001516040518263ffffffff1660e01b81526004016131af91815260200190565b602060405180830381865afa1580156131cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f09190615647565b6101008601516020015190915073ffffffffffffffffffffffffffffffffffffffff166132295760011c67ffffffffffffffff16613237565b60011c67ffffffffffffffff165b60ff8116600882901c901b905060008560e0015173ffffffffffffffffffffffffffffffffffffffff1663b5c736e4876101e001516040518263ffffffff1660e01b815260040161328a91815260200190565b602060405180830381865afa1580156132a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132cb9190615647565b6101208701516020015190915073ffffffffffffffffffffffffffffffffffffffff166133045760011c67ffffffffffffffff16613312565b60011c67ffffffffffffffff165b66ffffffffffffff605a85901c8116605286901c60ff9081169190911b808852609a87901c909216609287901c82161b602088015260408701849052600883901c92169190911b606086018190526fffffffffffffffffffffffffffffffff841660a0870152608084811c9087015260c0880151909164e8d4a51000910204855260e0870151602086015164e8d4a5100091020460208601526080870151604086015164e8d4a51000910204604086015260a0870151606086015164e8d4a51000910204606086015260c0870151608086015164e8d4a51000910204608086015260e087015160a086015164e8d4a5100091020460a086015250929695505050505050565b61345f60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6134b060405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61350f604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60c08a01516101c08b01516040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600481019190915260009173ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015613588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ac9190615647565b9050801561388e576000808c6000015173ffffffffffffffffffffffffffffffffffffffff168d60c0015173ffffffffffffffffffffffffffffffffffffffff160361361c5766ffffffffffffff600984901c1660ff600185901c161b915061361583836142e7565b905061367b565b66ffffffffffffff600984901c1660ff600185901c161b915061363f83836142e7565b6000895260208901839052608184901c6401ffffffff1660608a015260a284901c613fff1660808a015260b084901c62ffffff1660a08a015290505b64e8d4a510008e6080015182028161369557613695615ae8565b0480875282116136a65760006136ab565b855182035b60208701528551600090156136c657612710838e02046136c9565b60005b9050808760200151116136dd5760006136fc565b620f424081886020015103620f423f02816136fa576136fa615ae8565b045b602080890182905260408901919091526101008f0151015173ffffffffffffffffffffffffffffffffffffffff16925061385a91505057600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168c61010001516000015173ffffffffffffffffffffffffffffffffffffffff16036137a457508a5173ffffffffffffffffffffffffffffffffffffffff1631613840565b6101008c0151518c516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529116906370a0823190602401602060405180830381865afa158015613819573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061383d9190615647565b90505b846020015181101561385457604085018190525b5061388e565b835160408701526103ff60d082901c1660ff60c883901c161b60c0870152602084015160e087015260408401516101008701525b60e08b01516101e08c01516040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600481019190915260009173ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015613907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392b9190615647565b90508015613b72576101208c01516020015173ffffffffffffffffffffffffffffffffffffffff16613a9857606085018a905260c08501899052620f4240620f423f89020460808601526101208c01515160009073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff1111111111111111111111111111111111111112016139da57508b5173ffffffffffffffffffffffffffffffffffffffff1631613a76565b6101208d0151518d516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529116906370a0823190602401602060405180830381865afa158015613a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a739190615647565b90505b85608001518111613a875780613a8d565b85608001515b60a087015250613b72565b66ffffffffffffff600982901c1660ff600183901c161b613ab9828261437b565b606087018190528110613acd576000613ad5565b808660600151035b620f4240620f423f90910204608087810182815260a0808a0193845260008b5260208b018590526060808b015160408d015291516101008c015292516101208b0152608185901c6401ffffffff16908a015260a284901c613fff169089015260b083901c62ffffff169088015260d082901c6103ff1660c883901c60ff161b60c08801526103ff60e283901c1660ff60da84901c161b60e0880152505b64e8d4a510008d60e00151612711613b8a9190615a7e565b613b949190615b17565b60e086015250929b949a50929850929650505050505050565b600060ff82901d80831803617fff811115613bc757600080fd5b7001000000000000000000000000000000006001821615613bf557506fff9dd7de423466c20352b1246ce4856f5b6002821615613c14576fff3bd55f4488ad277531fa1c725a66d00260801c5b6004821615613c33576ffe78410fd6498b73cb96a6917f8532590260801c5b6008821615613c52576ffcf2d9987c9be178ad5bfeffaa1232730260801c5b6010821615613c71576ff9ef02c4529258b057769680fc6601b30260801c5b6020821615613c90576ff402d288133a85a17784a411f7aba0820260801c5b6040821615613caf576fe895615b5beb6386553757b0352bda900260801c5b6080821615613cce576fd34f17a00ffa00a8309940a15930391a0260801c5b610100821615613cee576fae6b7961714e20548d88ea5123f9a0ff0260801c5b610200821615613d0e576f76d6461f27082d74e0feed3b388c0ca10260801c5b610400821615613d2e576f372a3bfe0745d8b6b19d985d9a8b85bb0260801c5b610800821615613d4e576f0be32cbee48979763cf7247dd7bb539d0260801c5b611000821615613d6d576e8d4f70c9ff4924dac37612d1e2921e0260801c5b612000821615613d8b576d4e009ae5519380809a02ca7aec770260801c5b614000821615613da7576b17c45e641b6e95dee056ff100260801c5b600091507f80000000000000000000000000000000000000000000000000000000000000008416613e05577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0463ffffffff811615613e0557600191505b60201c0192915050565b6000806044835110613e785760208301517f33c955bc000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f115750505060248101516044820151905b915091565b6000606082600003613e93576000915050610723565b607f8311613f5c576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b16602282015260f884901b7fff000000000000000000000000000000000000000000000000000000000000001660368201526037015b60405160208183030381529060405290506142d8565b60ff8311614039576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f8100000000000000000000000000000000000000000000000000000000000000603682015260f884901b7fff00000000000000000000000000000000000000000000000000000000000000166037820152603801613f46565b61ffff8311614117576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f085901b166037820152603901613f46565b62ffffff83116141f6576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e885901b166037820152603a01613f46565b6040517fda0000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e085901b166037820152603b0160405160208183030381529060405290505b80516020909101209392505050565b600066ffffffffffffff604984901c1660ff604185901c161b808203614311576000915050610723565b612710613fff60a286901c168402046401ffffffff608186901c16420362ffffff60b087901c166143428284615a7e565b61434c9190615b17565b905080831161435c576000614360565b8083035b93505080840383811115614372578093505b50505092915050565b60d082901c6103ff1660c883901c60ff161b613fff60a284901c1661271083820204808401838110156143b057505050610723565b608186901c6401ffffffff164203925066ffffffffffffff604987901c1660ff604188901c161b60b087901c62ffffff166143eb8585615a7e565b6143f59190615b17565b6143ff9190615ca0565b93508084111561440d578093505b6103ff60e287901c1660ff60da88901c161b925082841115614372575090949350505050565b604080516101608101825260008082526020820181905291810191909152606081016144f4604080516102008101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905260e0830182905283518085018552828152808201839052610100840152835180850190945281845283015290610120820190815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b8152604080516101a08101825260008082526020828101829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820181905261018082015291019081526020016145d7604051806101c0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020016146156040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200161466260405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200161466f61472e565b81526020016146c560405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001614729604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b905290565b6040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016147296040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b73ffffffffffffffffffffffffffffffffffffffff811681146147c557600080fd5b50565b6000602082840312156147da57600080fd5b8135610fe5816147a3565b805173ffffffffffffffffffffffffffffffffffffffff1682526020810151614826602084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604081015161484e604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060810151614876606084018273ffffffffffffffffffffffffffffffffffffffff169052565b50608081015161489e608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a08101516148c660a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c08101516148ee60c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e081015161491660e084018273ffffffffffffffffffffffffffffffffffffffff169052565b5061010081810151805173ffffffffffffffffffffffffffffffffffffffff90811685840152602082015116610120850152505061012081015161014061498281850183805173ffffffffffffffffffffffffffffffffffffffff908116835260209182015116910152565b820151610180848101919091526101608301516101a080860191909152908301516101c080860191909152908301516101e08086019190915290830151610200850152909101516102209092019190915250565b805161ffff16825260208101516149f3602084018261ffff169052565b506040810151614a09604084018261ffff169052565b506060810151614a1f606084018261ffff169052565b506080810151614a35608084018261ffff169052565b5060a0810151614a4b60a084018261ffff169052565b5060c0810151614a6160c084018261ffff169052565b5060e0810151614a7760e084018261ffff169052565b506101008181015173ffffffffffffffffffffffffffffffffffffffff8116848301525050610120818101519083015261014080820151908301526101608082015173ffffffffffffffffffffffffffffffffffffffff811682850152505061018090810151910152565b805173ffffffffffffffffffffffffffffffffffffffff1682526020810151614b0f602084018215159052565b506040810151614b23604084018215159052565b506060810151614b3660608401826147e5565b506080810151614b4a6102a08401826149d6565b5060a08181015180516104408501526020808201516104608601526040808301516104808701526060808401516104a08801526080808501516104c0890152848601516104e089015260c0808601516105008a015260e0808701516105208b0152610100808801516105408c0152610120808901516105608d0152610140808a01516105808e01526101608a01516105a08e01526101808a01516105c08e01526101a0909901516105e08d0152838b015180516106008e0152808901516106208e0152808801516106408e0152808701516106608e0152808601516106808e01528a01516106a08d0152828b015180516106c08e0152808901516106e08e0152808801516107008e0152808701516107208e0152808601516107408e0152808b01516107608e0152808501516107808e01528301516107a08d0152818b015180516107c08e0152808901516107e08e0152808801516108008e0152808701516108208e0152808601516108408e0152808b01516108608e015284015180516108808e0152808901516108a08e0152808801516108c08e0152808701516108e08e0152808601516109008e0152808b01516109208e01528401516109408d0152808b0151805115156109608e0152808901516109808e0152808801516109a08e0152808701516109c08e0152808601516109e08e0152808b0151610a008e015280850151610a208e015280840151610a408e0152820151610a608d01529988015180511515610a808d015296870151610aa08c015294860151610ac08b015292850151610ae08a015290840151610b0089015294830151610b2088015293820151610b4087015292810151610b6086015291820151610b8085015291810151610ba08401520151610bc090910152565b610be081016107238284614ae2565b600060208284031215614dfa57600080fd5b5035919050565b805182526020810151614e2c602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151614e40604084018215159052565b506060810151614e54606084018215159052565b506080818101519083015260a0808201519083015260c0808201519083015260e0808201519083015261010080820151908301526101208082015190830152610140808201519083015261016090810151910152565b610d608101614eb98285614e01565b610fe5610180830184614ae2565b60008060408385031215614eda57600080fd5b8235614ee5816147a3565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810181811067ffffffffffffffff82111715614f4257614f42614ef3565b60405250565b60a0810181811067ffffffffffffffff82111715614f4257614f42614ef3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715614fac57614fac614ef3565b6040525050565b604051610220810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b60405290565b604051610120810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b604051610160810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b6040516101a0810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b604051610200810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b600067ffffffffffffffff82111561508757615087614ef3565b5060051b60200190565b600082601f8301126150a257600080fd5b813560206150af8261506d565b6040516150bc8282614f68565b83815260059390931b85018201928281019150868411156150dc57600080fd5b8286015b848110156151005780356150f3816147a3565b83529183019183016150e0565b509695505050505050565b60006020828403121561511d57600080fd5b813567ffffffffffffffff81111561513457600080fd5b611dd384828501615091565b600081518084526020808501945080840160005b8381101561517b57615167878351614ae2565b610be0969096019590820190600101615154565b509495945050505050565b602081526000610fe56020830184615140565b805173ffffffffffffffffffffffffffffffffffffffff16825260208101516151da602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151615202604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015161522a606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151615252608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a081015160a083015260c081015160c083015260e081015160e0830152610100808201518184015250610120808201516152918285018215159052565b50505050565b61014081016107238284615199565b815181526020808301518183015260408084015181840152606080850151818501526080808601518186015260a0808701518187015260c0808801518051828901529586015160e0880152938501516101008701529184015161012086015283015161014085015282015161016084015201516101808201526101a08101610723565b602080825282518282018190526000919060409081850190868401855b8281101561538b5761537b848351805173ffffffffffffffffffffffffffffffffffffffff1682526020908101511515910152565b9284019290850190600101615346565b5091979650505050505050565b600080604083850312156153ab57600080fd5b823567ffffffffffffffff808211156153c357600080fd5b6153cf86838701615091565b93506020915081850135818111156153e657600080fd5b85019050601f810186136153f957600080fd5b80356154048161506d565b6040516154118282614f68565b82815260059290921b830184019184810191508883111561543157600080fd5b928401925b8284101561544f57833582529284019290840190615436565b80955050505050509250929050565b6020808252825182820181905260009190848201906040850190845b818110156154a15761548d838551615199565b92840192610140929092019160010161547a565b50909695505050505050565b600080604083850312156154c057600080fd5b50508035926020909101359150565b604080825283519082018190526000906020906060840190828701845b82811015615513576154ff848351614e01565b6101809390930192908401906001016154ec565b505050838103828501526155278186615140565b9695505050505050565b60008060006060848603121561554657600080fd5b8335615551816147a3565b95602085013595506040909401359392505050565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015115159082015260408101610723565b6000806000606084860312156155aa57600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b818110156154a157835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016155dd565b6020808252825182820181905260009190848201906040850190845b818110156154a15783518352928401929184019160010161562b565b60006020828403121561565957600080fd5b5051919050565b8051801515811461127257600080fd5b8051611272816147a3565b600060e0828403121561568d57600080fd5b60405160e0810181811067ffffffffffffffff821117156156b0576156b0614ef3565b806040525080915082516156c3816147a3565b808252506020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c08201525092915050565b60008183036101a081121561571e57600080fd5b60405161572a81614f22565b8092508351815260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08301121561576157600080fd5b604051915061576f82614f48565b602084015161577d816147a3565b8083525060408401516020830152606084015160408301526080840151606083015260a084015160808301528160208201526157bc8560c0860161567b565b6040820152505092915050565b60006103a082840312156157dc57600080fd5b6157e4614fb3565b825181526020808401519082015260408084015190820152606080840151908201526080808401519082015260a0808401519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e0808401519082015290506102006158978482850161570a565b9082015292915050565b6000808284036104c08112156158b657600080fd5b610120808212156158c657600080fd5b6158ce614fdd565b91506158d985615660565b82526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010080860151818401525081935061593c868287016157c9565b925050509250929050565b60008082840361050081121561595c57600080fd5b6101608082121561596c57600080fd5b615974615001565b915061597f85615660565b82526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010080860151818401525061012080860151818401525061014080860151818401525081935061593c868287016157c9565b600060208284031215615a0c57600080fd5b8151610fe5816147a3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007f80000000000000000000000000000000000000000000000000000000000000008203615a7757615a77615a17565b5060000390565b808202811582820484141761072357610723615a17565b8181038181111561072357610723615a17565b600080600080600060a08688031215615ac057600080fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615b4d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615bb257615bb2615a17565b5060010190565b60008060408385031215615bcc57600080fd5b505080516020909101519092909150565b600060033d11156105cf5760046000803e5060005160e01c90565b600060443d1015615c065790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715615c5457505050505090565b8285019150815181811115615c6c5750505050505090565b843d8701016020828501011115615c865750505050505090565b615c9560208286010187614f68565b509095945050505050565b8082018082111561072357610723615a17565b805160ff8116811461127257600080fd5b60006101a08284031215615cd757600080fd5b615cdf615025565b615ce883615670565b8152615cf660208401615670565b6020820152615d0760408401615670565b6040820152615d1860608401615670565b6060820152615d2960808401615670565b6080820152615d3a60a08401615670565b60a0820152615d4b60c08401615cb3565b60c0820152615d5c60e08401615cb3565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015190820152610180928301519281019290925250919050565b600060408284031215615db357600080fd5b6040516040810181811067ffffffffffffffff82111715615dd657615dd6614ef3565b80604052508091508251615de9816147a3565b81526020830151615df9816147a3565b6020919091015292915050565b60006102408284031215615e1957600080fd5b615e21615049565b615e2a83615670565b8152615e3860208401615670565b6020820152615e4960408401615670565b6040820152615e5a60608401615670565b6060820152615e6b60808401615670565b6080820152615e7c60a08401615670565b60a0820152615e8d60c08401615670565b60c0820152615e9e60e08401615670565b60e0820152610100615eb285828601615da1565b90820152610140615ec585858301615da1565b61012083015261018080850151828401526101a09150818501516101608401526101c080860151828501526101e09150818601518385015261020086015181850152506102208501518184015250508091505092915050565b61ffff818116838216028082169190828114611a6f57611a6f615a17565b60008060008060808587031215615f5257600080fd5b50508251602084015160408501516060909501519196909550909250905056fea2646970667358221220831baa9e285250f6bdcb5e3341ab73dc2730494f9c61998c17ca36baf91a491964736f6c63430008150033000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d00000000000000000000000098d900e25aaf345a4b23f454751ec5083443fa83

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102d35760003560e01c80637955fffd11610186578063a8d9f493116100e3578063e06a7b7111610097578063eb1db01811610071578063eb1db01814610676578063f70b198c14610689578063fda1fa5f1461069c57600080fd5b8063e06a7b7114610648578063e6bd26a214610650578063ea19ba111461066357600080fd5b8063c67b5093116100c8578063c67b50931461060d578063cbc7be651461062d578063dd19c0fe1461064057600080fd5b8063a8d9f493146105e5578063bf518f5f146105fa57600080fd5b80638a0038881161013a5780638f8b81f01161011f5780638f8b81f0146105ae5780639d7aeeb4146105c1578063a8bc0693146105d257600080fd5b80638a003888146105885780638bfbeda61461059b57600080fd5b8063816022b81161016b578063816022b8146105425780638530330414610555578063890a13911461056857600080fd5b80637955fffd1461052f5780637bbede431461046c57600080fd5b80632404a3f911610234578063347ca8bb116101e85780635486f100116101cd5780635486f100146104ed5780636463e94c146104f55780636902f79f1461050857600080fd5b8063347ca8bb146104b957806351971bf7146104da57600080fd5b80632dd31000116102195780632dd31000146104455780632f2612cf1461046c578063344bd722146104a657600080fd5b80632404a3f9146104105780632c44e1d11461042557600080fd5b80631949138e1161028b5780631f51fd93116102705780631f51fd93146103bd5780631fcd3649146103d057806320ee1e44146103f057600080fd5b80631949138e146103655780631ef8986d1461039d57600080fd5b8063144128e8116102bc578063144128e81461031e5780631579a46c1461033f578063168a11c21461035257600080fd5b806303e883e0146102d857806309c062e2146102fe575b600080fd5b6102eb6102e63660046147c8565b6106a4565b6040519081526020015b60405180910390f35b61031161030c3660046147c8565b610729565b6040516102f59190614dd9565b61033161032c366004614de8565b610a37565b6040516102f5929190614eaa565b6102eb61034d3660046147c8565b610f17565b6102eb610360366004614ec7565b610f3c565b610378610373366004614de8565b610fec565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102f5565b6103b06103ab36600461510b565b6110b3565b6040516102f59190615186565b6102eb6103cb3660046147c8565b611171565b6103e36103de366004614ec7565b611277565b6040516102f59190615297565b6104036103fe3660046147c8565b6117dc565b6040516102f591906152a6565b610418611928565b6040516102f59190615329565b610438610433366004615398565b61193a565b6040516102f5919061545e565b6103787f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d81565b6102eb61047a3660046154ad565b604080516020808201939093528082019390935280518084038201815260609093019052815191012090565b6102eb6104b43660046147c8565b611a77565b6104cc6104c73660046147c8565b611ac4565b6040516102f59291906154cf565b6102eb6104e83660046147c8565b611c79565b6102eb611c9e565b6103786105033660046147c8565b611d2f565b6103787f00000000000000000000000098d900e25aaf345a4b23f454751ec5083443fa8381565b61037861053d3660046147c8565b611d54565b610378610550366004614ec7565b611d79565b6102eb610563366004615531565b611ddb565b61057b6105763660046147c8565b611e64565b6040516102f59190615566565b6102eb610596366004614de8565b611f7f565b6102eb6105a9366004615595565b611fed565b6102eb6105bc366004614de8565b612073565b6102eb6105cf366004614de8565b90565b6102eb6105e0366004614ec7565b612140565b6105ed61218e565b6040516102f591906155c1565b6102eb610608366004614ec7565b612248565b61062061061b3660046147c8565b612296565b6040516102f5919061560f565b6102eb61063b366004614ec7565b612484565b6104386124d2565b6103b0612601565b61037861065e366004614de8565b6126b7565b61041861067136600461510b565b6126e3565b6102eb6106843660046147c8565b6127a6565b6102eb6106973660046147c8565b6127cb565b6102eb6127f0565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e4825b6040518263ffffffff1660e01b81526004016106e291815260200190565b602060405180830381865afa1580156106ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107239190615647565b92915050565b610731614433565b73ffffffffffffffffffffffffffffffffffffffff82168152600061075583611171565b90508015610a3157610767838261285d565b6060830181905261010081015160209081015173ffffffffffffffffffffffffffffffffffffffff90811615158286018190526101209093015190910151161515604084015260009081908190819081906108995760608701516101000151516040517fe72ef91b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152918216602482015260009182917f00000000000000000000000098d900e25aaf345a4b23f454751ec5083443fa839091169063e72ef91b906044016104c060405180830381865afa158015610863573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088791906158a1565b6101208b019190915260200151935050505b86604001516109955760608701516101200151516040517f967915d600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152918216602482015260009182917f00000000000000000000000098d900e25aaf345a4b23f454751ec5083443fa839091169063967915d69060440161050060405180830381865afa158015610949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096d9190615947565b610140808c018390529051604083015191830151610100909301519199509197509550925050505b6109a88888606001516101600151612aea565b608088018190526109be90899088908585612e6b565b60a0880181905260608801516109d79350899250613116565b8560c00181905250610a0d8560a001518660600151876080015160a0015161ffff168686868b61012001518c6101400151613417565b61014088015261012087015260e0860152610a27866117dc565b6101008601525050505b50919050565b610ab560405180610180016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b610abd614433565b8282526000610acb84610fec565b905073ffffffffffffffffffffffffffffffffffffffff811615610f11576000610af58286612484565b9050610b0082610729565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018790529093507f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d73ffffffffffffffffffffffffffffffffffffffff1690636352211e90602401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb291906159fa565b73ffffffffffffffffffffffffffffffffffffffff1660208501526001808216146060850181905266ffffffffffffff603583901c811660ff602d85901c81169190911b610120880181905260c0880152607584901c909116606d84901c9091161b6101608601819052610100860152610df65780600216600214610c4857610c43600282901c6207ffff16615a46565b610c53565b6207ffff600282901c165b60808501819052601582901c62ffffff1660a0860152610120850151606091610c7e9060020b613bad565b610c889190615a7e565b901c6101408501819052610100850151610ca191615a95565b60e08501526080840151600090610cb9908490610f3c565b90508060011660011480610cd957508460a0015162ffffff600183901c16115b15610db0576001604086810191909152608086015160a087015161014088015192517f22348cc70000000000000000000000000000000000000000000000000000000081526004810192909252602482015260448101919091526064810182905273ffffffffffffffffffffffffffffffffffffffff8416906322348cc79060840160a060405180830381865afa158015610d78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9c9190615aa8565b505061012088015261014087015260808601525b8461016001518561014001511115610de357846101600151856101400151610dd89190615a95565b610140860152610df4565b600061014086018190526101608601525b505b64e8d4a510008360a0015160c001518560c00151610e149190615a7e565b610e1e9190615b17565b60c085015260a083015160e0908101519085015164e8d4a5100091610e4291615a7e565b610e4c9190615b17565b60e08086019190915260a0840151015161010085015164e8d4a5100091610e7291615a7e565b610e7c9190615b17565b61010085015260a083015160c0015161012085015164e8d4a5100091610ea191615a7e565b610eab9190615b17565b61012085015260a083015160e0015161014085015164e8d4a5100091610ed091615a7e565b610eda9190615b17565b61014085015260a083015160e0015161016085015164e8d4a5100091610eff91615a7e565b610f099190615b17565b610160850152505b50915091565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460086106c4565b6040805160208082018490526005828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e4905b6040518263ffffffff1660e01b8152600401610fa491815260200190565b602060405180830381865afa158015610fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe59190615647565b9392505050565b600080610ff883611f7f565b6040517fe6bd26a200000000000000000000000000000000000000000000000000000000815263ffffffff60c083901c1660048201529091507f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d73ffffffffffffffffffffffffffffffffffffffff169063e6bd26a290602401602060405180830381865afa15801561108f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe591906159fa565b80516060908067ffffffffffffffff8111156110d1576110d1614ef3565b60405190808252806020026020018201604052801561110a57816020015b6110f7614433565b8152602001906001900390816110ef5790505b50915060005b8181101561116a5761113a84828151811061112d5761112d615b52565b6020026020010151610729565b83828151811061114c5761114c615b52565b6020026020010181905250808061116290615b81565b915050611110565b5050919050565b60008173ffffffffffffffffffffffffffffffffffffffff163b60000361119a57506000919050565b8173ffffffffffffffffffffffffffffffffffffffff1663bb24fe8a6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561121f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261121c91810190615647565b60015b610723578173ffffffffffffffffffffffffffffffffffffffff1661124661065e84611a77565b73ffffffffffffffffffffffffffffffffffffffff161461126957506000919050565b50612710919050565b919050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081019190915281156112d457816112e6565b6fffffffffffffffffffffffffffffffff5b915060006112f384611171565b905080156117d55773ffffffffffffffffffffffffffffffffffffffff841682526000611320858361285d565b9050612710816101600151036115cb576101208101515173ffffffffffffffffffffffffffffffffffffffff9081166020850152610100820151518116604080860191909152517f8433ea220000000000000000000000000000000000000000000000000000000081526004810186905260006024820181905261dead6044830152606482015290861690638433ea229060840160408051808303816000875af192505050801561140c575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261140991810190615bb9565b60015b61148857611418615bdd565b806308c379a00361143d575061142c615bf8565b80611437575061143f565b5061148b565b505b3d808015611469576040519150601f19603f3d011682016040523d82523d6000602084013e61146e565b606091505b5061147881613e0f565b60c086015260a08501525061148b565b50505b6040517f8433ea22000000000000000000000000000000000000000000000000000000008152600481018590526000602482015261dead60448201526001606482015273ffffffffffffffffffffffffffffffffffffffff861690638433ea229060840160408051808303816000875af1925050508015611547575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261154491810190615bb9565b60015b6115c457611553615bdd565b806308c379a0036115785750611567615bf8565b80611572575061157a565b506117ad565b505b3d8080156115a4576040519150601f19603f3d011682016040523d82523d6000602084013e6115a9565b606091505b506115b381613e0f565b61010086015260e0850152506117ad565b50506117ad565b610120810180515173ffffffffffffffffffffffffffffffffffffffff908116602086810191909152610100840180515183166040808901919091529351820151831660608801525101518116608086015290517f3202937e000000000000000000000000000000000000000000000000000000008152600060048201819052602482015290861690633202937e90604401600060405180830381600087803b15801561167757600080fd5b505af1925050508015611688575060015b61170057611694615bdd565b806308c379a0036116b957506116a8615bf8565b806116b357506116bb565b50611700565b505b3d8080156116e5576040519150601f19603f3d011682016040523d82523d6000602084013e6116ea565b606091505b506116f481613e0f565b60c086015260a0850152505b6040517f3202937e000000000000000000000000000000000000000000000000000000008152600060048201526001602482015273ffffffffffffffffffffffffffffffffffffffff861690633202937e90604401600060405180830381600087803b15801561176f57600080fd5b505af1925050508015611780575060015b6117ad5761178c615bdd565b806308c379a00361157857506117a0615bf8565b806117ab575061157a565b505b8260a001518360e0015111806117cb57508260c00151836101000151115b1515610120840152505b5092915050565b6117e461472e565b60006117ef836106a4565b9050611803620fffff600283901c16612073565b6020830152633fffffff601682901c81166040840152603482901c16606083015266ffffffffffffff605a82901c1660ff605283901c161b60a083015266ffffffffffffff609a82901c1660ff609283901c161b608083015260d281901c63ffffffff168252604082015160009061187c908590612248565b60c0840151600382169052905061189b600282901c620fffff16612073565b60c0840180516020019190915280516603ffffffffffff607484901c1660409091015251633fffffff601683901c1660609091015266ffffffffffffff603c82901c1660ff603483901c161b60c084018051608001919091525160a682901c633fffffff1660a09091015261191860c482901c620fffff16612073565b60c0808501510152509092915050565b606061193561067161218e565b905090565b81516060908067ffffffffffffffff81111561195857611958614ef3565b6040519080825280602002602001820160405280156119f557816020015b604080516101408101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816119765790505b50915060005b81811015611a6f57611a3f858281518110611a1857611a18615b52565b6020026020010151858381518110611a3257611a32615b52565b6020026020010151611277565b838281518110611a5157611a51615b52565b60200260200101819052508080611a6790615b81565b9150506119fb565b505092915050565b60008173ffffffffffffffffffffffffffffffffffffffff1663540acabc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106ff573d6000803e3d6000fd5b6060806000611ad284612296565b80519091508067ffffffffffffffff811115611af057611af0614ef3565b604051908082528060200260200182016040528015611b9f57816020015b611b8c60405180610180016040528060008152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160001515815260200160001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200190600190039081611b0e5790505b5093508067ffffffffffffffff811115611bbb57611bbb614ef3565b604051908082528060200260200182016040528015611bf457816020015b611be1614433565b815260200190600190039081611bd95790505b50925060005b81811015611c7157611c24838281518110611c1757611c17615b52565b6020026020010151610a37565b868381518110611c3657611c36615b52565b60200260200101868481518110611c4f57611c4f615b52565b6020026020010182905282905250508080611c6990615b81565b915050611bfa565b505050915091565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e4600a6106c4565b60007f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d73ffffffffffffffffffffffffffffffffffffffff16638d6540236040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d0b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119359190615647565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460096106c4565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e4600b6106c4565b600080611d8e84611d8986611171565b61285d565b60a081015190915073ffffffffffffffffffffffffffffffffffffffff161580611db6575082155b15611dc5576000915050610723565b611dd38160a0015184613e7d565b949350505050565b60008373ffffffffffffffffffffffffffffffffffffffff1663b5c736e4611e0560068686611fed565b6040518263ffffffff1660e01b8152600401611e2391815260200190565b602060405180830381865afa158015611e40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dd39190615647565b6040805180820190915260006020820181905273ffffffffffffffffffffffffffffffffffffffff83168252611e99836127cb565b90508273ffffffffffffffffffffffffffffffffffffffff1663ebd93ac66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ee357600080fd5b505af1925050508015611ef4575060015b611f5d57611f00615bdd565b806308c379a003611f255750611f14615bf8565b80611f1f5750611f27565b50610a31565b505b3d808015611f51576040519150601f19603f3d011682016040523d82523d6000602084013e611f56565b606091505b5050610a31565b6000611f68846127cb565b905081811461116a57600160208401525050919050565b6040805160208082018490526003828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d169063b5c736e4906106c4565b600080838560405160200161200c929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083018690529082018190529150606001604051602081830303815290604052805190602001209150509392505050565b6000620fffff82106120e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f696e76616c69642d6e756d626572000000000000000000000000000000000000604482015260640160405180910390fd5b8115612119578160011660011461210d57612108600183901c6207ffff16615a46565b610723565b5060011c6207ffff1690565b507f8000000000000000000000000000000000000000000000000000000000000000919050565b6040805160208082018490526004828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e490610f86565b6060600061219a611c9e565b90508067ffffffffffffffff8111156121b5576121b5614ef3565b6040519080825280602002602001820160405280156121de578160200160208202803683370190505b50915060005b81811015612243576121fa61065e826001615ca0565b83828151811061220c5761220c615b52565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101528061223b81615b81565b9150506121e4565b505090565b6040805160208082018490526007828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e490610f86565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526060916000917f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d16906370a0823190602401602060405180830381865afa158015612328573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234c9190615647565b90508067ffffffffffffffff81111561236757612367614ef3565b604051908082528060200260200182016040528015612390578160200160208202803683370190505b50915060005b8181101561116a576040517f2f745c5900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018390527f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d1690632f745c5990604401602060405180830381865afa158015612431573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124559190615647565b83828151811061246757612467615b52565b60209081029190910101528061247c81615b81565b915050612396565b6040805160208082018490526003828401528251808303840181526060909201909252805191012060009073ffffffffffffffffffffffffffffffffffffffff84169063b5c736e490610f86565b606060006124de61218e565b80519091508067ffffffffffffffff8111156124fc576124fc614ef3565b60405190808252806020026020018201604052801561259957816020015b604080516101408101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161251a5790505b50925060005b818110156125fb576125cb8382815181106125bc576125bc615b52565b60200260200101516000611277565b8482815181106125dd576125dd615b52565b602002602001018190525080806125f390615b81565b91505061259f565b50505090565b6060600061260d61218e565b80519091508067ffffffffffffffff81111561262b5761262b614ef3565b60405190808252806020026020018201604052801561266457816020015b612651614433565b8152602001906001900390816126495790505b50925060005b818110156125fb5761268783828151811061112d5761112d615b52565b84828151811061269957612699615b52565b602002602001018190525080806126af90615b81565b91505061266a565b60006107237f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d83613e7d565b80516060908067ffffffffffffffff81111561270157612701614ef3565b60405190808252806020026020018201604052801561274657816020015b604080518082019091526000808252602082015281526020019060019003908161271f5790505b50915060005b8181101561116a5761277684828151811061276957612769615b52565b6020026020010151611e64565b83828151811061278857612788615b52565b6020026020010181905250808061279e90615b81565b91505061274c565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460016106c4565b600073ffffffffffffffffffffffffffffffffffffffff821663b5c736e460026106c4565b60007f000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d0b573d6000803e3d6000fd5b6128fc604080516102008101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905260e0830182905283518085018552828152808201839052610100840152835180850190945281845283015290610120820190815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b6127108203612a7a578273ffffffffffffffffffffffffffffffffffffffff1663b7791bf26040518163ffffffff1660e01b81526004016101a060405180830381865afa92505050801561298b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261298891810190615cc4565b60015b1561072357805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182168185015285821660408086019190915283015182166060808601919091528301518216608080860191909152600060a08087018290528551851660c08801528551851660e0880152918501516101008088018051928716909252905184018290529185015161012080880180519290961690915293519092019190915282015161014080850191909152612710610160808601919091529183015161018080860191909152908301516101a0850152908201516101c084015201516101e0820152610723565b8273ffffffffffffffffffffffffffffffffffffffff1663b7791bf26040518163ffffffff1660e01b815260040161024060405180830381865afa158015612ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe59190615e06565b604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081018290526101608101829052610180810182905290612b5c846127a6565b61ffff8082168452601082901c16602080850191909152909150612b889082901c6103ff16600a615f1e565b61ffff166040830152612ba4602a82901c6103ff16600a615f1e565b61ffff166060830152612bc0603482901c6103ff16600a615f1e565b61ffff166080830152612bdc603e82901c6103ff16600a615f1e565b61ffff1660a08301526103ff604882901c811660c0840152605282901c1660e08301527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f08301612c3657606081901c610100830152612c82565b605c81901c633fffffff168015612c6e57612c518582611d79565b73ffffffffffffffffffffffffffffffffffffffff166101008401525b50607a81901c6401ffffffff166101808301525b61010082015173ffffffffffffffffffffffffffffffffffffffff1615612e3f5781610100015173ffffffffffffffffffffffffffffffffffffffff16638e7bfbc06040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612d2d575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612d2a91810190615647565b60015b612db85781610100015173ffffffffffffffffffffffffffffffffffffffff1663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da59190615647565b6101208301819052610140830152612e3f565b808361012001818152505082610100015173ffffffffffffffffffffffffffffffffffffffff1663f3190c896040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e379190615647565b610140840152505b612e4884611d2f565b73ffffffffffffffffffffffffffffffffffffffff166101608301525092915050565b612edd604051806101c0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000612ee887610f17565b67ffffffffffffffff8082168452604082811c82166020860152608083901c9091169084015260c081901c6060840152905073ffffffffffffffffffffffffffffffffffffffff87166309f0d8cb612f3f896127a6565b6040518263ffffffff1660e01b8152600401612f5d91815260200190565b608060405180830381865afa158015612f7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f9e9190615f3c565b60e086015260c085015260a0840152608083015261010082018490526101208201839052614e20861480612fd35750619c4086145b1561301a578451600190811c617fff166101408401528551166000036130095781610140015161300290615a46565b6101408301525b61014082015161018083015261305c565b84516127109061ffff16850204610140830152845161ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f0016101808301525b61753086148061306d5750619c4086145b156130b857602085018051600190811c617fff166101608501529051166000036130a7578161016001516130a090615a46565b6101608301525b6101608201516101a083015261310c565b612710856020015161ffff168402816130d3576130d3615ae8565b04610160830152602085015161ffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8f0016101a08301525b5095945050505050565b61314f6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600061315a856106a4565b90506000613167866127cb565b905060008460c0015173ffffffffffffffffffffffffffffffffffffffff1663b5c736e4866101c001516040518263ffffffff1660e01b81526004016131af91815260200190565b602060405180830381865afa1580156131cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131f09190615647565b6101008601516020015190915073ffffffffffffffffffffffffffffffffffffffff166132295760011c67ffffffffffffffff16613237565b60011c67ffffffffffffffff165b60ff8116600882901c901b905060008560e0015173ffffffffffffffffffffffffffffffffffffffff1663b5c736e4876101e001516040518263ffffffff1660e01b815260040161328a91815260200190565b602060405180830381865afa1580156132a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132cb9190615647565b6101208701516020015190915073ffffffffffffffffffffffffffffffffffffffff166133045760011c67ffffffffffffffff16613312565b60011c67ffffffffffffffff165b66ffffffffffffff605a85901c8116605286901c60ff9081169190911b808852609a87901c909216609287901c82161b602088015260408701849052600883901c92169190911b606086018190526fffffffffffffffffffffffffffffffff841660a0870152608084811c9087015260c0880151909164e8d4a51000910204855260e0870151602086015164e8d4a5100091020460208601526080870151604086015164e8d4a51000910204604086015260a0870151606086015164e8d4a51000910204606086015260c0870151608086015164e8d4a51000910204608086015260e087015160a086015164e8d4a5100091020460a086015250929695505050505050565b61345f60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6134b060405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61350f604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60c08a01516101c08b01516040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600481019190915260009173ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015613588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ac9190615647565b9050801561388e576000808c6000015173ffffffffffffffffffffffffffffffffffffffff168d60c0015173ffffffffffffffffffffffffffffffffffffffff160361361c5766ffffffffffffff600984901c1660ff600185901c161b915061361583836142e7565b905061367b565b66ffffffffffffff600984901c1660ff600185901c161b915061363f83836142e7565b6000895260208901839052608184901c6401ffffffff1660608a015260a284901c613fff1660808a015260b084901c62ffffff1660a08a015290505b64e8d4a510008e6080015182028161369557613695615ae8565b0480875282116136a65760006136ab565b855182035b60208701528551600090156136c657612710838e02046136c9565b60005b9050808760200151116136dd5760006136fc565b620f424081886020015103620f423f02816136fa576136fa615ae8565b045b602080890182905260408901919091526101008f0151015173ffffffffffffffffffffffffffffffffffffffff16925061385a91505057600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168c61010001516000015173ffffffffffffffffffffffffffffffffffffffff16036137a457508a5173ffffffffffffffffffffffffffffffffffffffff1631613840565b6101008c0151518c516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529116906370a0823190602401602060405180830381865afa158015613819573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061383d9190615647565b90505b846020015181101561385457604085018190525b5061388e565b835160408701526103ff60d082901c1660ff60c883901c161b60c0870152602084015160e087015260408401516101008701525b60e08b01516101e08c01516040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600481019190915260009173ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015613907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392b9190615647565b90508015613b72576101208c01516020015173ffffffffffffffffffffffffffffffffffffffff16613a9857606085018a905260c08501899052620f4240620f423f89020460808601526101208c01515160009073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff1111111111111111111111111111111111111112016139da57508b5173ffffffffffffffffffffffffffffffffffffffff1631613a76565b6101208d0151518d516040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529116906370a0823190602401602060405180830381865afa158015613a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a739190615647565b90505b85608001518111613a875780613a8d565b85608001515b60a087015250613b72565b66ffffffffffffff600982901c1660ff600183901c161b613ab9828261437b565b606087018190528110613acd576000613ad5565b808660600151035b620f4240620f423f90910204608087810182815260a0808a0193845260008b5260208b018590526060808b015160408d015291516101008c015292516101208b0152608185901c6401ffffffff16908a015260a284901c613fff169089015260b083901c62ffffff169088015260d082901c6103ff1660c883901c60ff161b60c08801526103ff60e283901c1660ff60da84901c161b60e0880152505b64e8d4a510008d60e00151612711613b8a9190615a7e565b613b949190615b17565b60e086015250929b949a50929850929650505050505050565b600060ff82901d80831803617fff811115613bc757600080fd5b7001000000000000000000000000000000006001821615613bf557506fff9dd7de423466c20352b1246ce4856f5b6002821615613c14576fff3bd55f4488ad277531fa1c725a66d00260801c5b6004821615613c33576ffe78410fd6498b73cb96a6917f8532590260801c5b6008821615613c52576ffcf2d9987c9be178ad5bfeffaa1232730260801c5b6010821615613c71576ff9ef02c4529258b057769680fc6601b30260801c5b6020821615613c90576ff402d288133a85a17784a411f7aba0820260801c5b6040821615613caf576fe895615b5beb6386553757b0352bda900260801c5b6080821615613cce576fd34f17a00ffa00a8309940a15930391a0260801c5b610100821615613cee576fae6b7961714e20548d88ea5123f9a0ff0260801c5b610200821615613d0e576f76d6461f27082d74e0feed3b388c0ca10260801c5b610400821615613d2e576f372a3bfe0745d8b6b19d985d9a8b85bb0260801c5b610800821615613d4e576f0be32cbee48979763cf7247dd7bb539d0260801c5b611000821615613d6d576e8d4f70c9ff4924dac37612d1e2921e0260801c5b612000821615613d8b576d4e009ae5519380809a02ca7aec770260801c5b614000821615613da7576b17c45e641b6e95dee056ff100260801c5b600091507f80000000000000000000000000000000000000000000000000000000000000008416613e05577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0463ffffffff811615613e0557600191505b60201c0192915050565b6000806044835110613e785760208301517f33c955bc000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601610f115750505060248101516044820151905b915091565b6000606082600003613e93576000915050610723565b607f8311613f5c576040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b16602282015260f884901b7fff000000000000000000000000000000000000000000000000000000000000001660368201526037015b60405160208183030381529060405290506142d8565b60ff8311614039576040517fd70000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f8100000000000000000000000000000000000000000000000000000000000000603682015260f884901b7fff00000000000000000000000000000000000000000000000000000000000000166037820152603801613f46565b61ffff8311614117576040517fd80000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f820000000000000000000000000000000000000000000000000000000000000060368201527fffff00000000000000000000000000000000000000000000000000000000000060f085901b166037820152603901613f46565b62ffffff83116141f6576040517fd90000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f830000000000000000000000000000000000000000000000000000000000000060368201527fffffff000000000000000000000000000000000000000000000000000000000060e885901b166037820152603a01613f46565b6040517fda0000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b1660228201527f840000000000000000000000000000000000000000000000000000000000000060368201527fffffffff0000000000000000000000000000000000000000000000000000000060e085901b166037820152603b0160405160208183030381529060405290505b80516020909101209392505050565b600066ffffffffffffff604984901c1660ff604185901c161b808203614311576000915050610723565b612710613fff60a286901c168402046401ffffffff608186901c16420362ffffff60b087901c166143428284615a7e565b61434c9190615b17565b905080831161435c576000614360565b8083035b93505080840383811115614372578093505b50505092915050565b60d082901c6103ff1660c883901c60ff161b613fff60a284901c1661271083820204808401838110156143b057505050610723565b608186901c6401ffffffff164203925066ffffffffffffff604987901c1660ff604188901c161b60b087901c62ffffff166143eb8585615a7e565b6143f59190615b17565b6143ff9190615ca0565b93508084111561440d578093505b6103ff60e287901c1660ff60da88901c161b925082841115614372575090949350505050565b604080516101608101825260008082526020820181905291810191909152606081016144f4604080516102008101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905260e0830182905283518085018552828152808201839052610100840152835180850190945281845283015290610120820190815260006020820181905260408201819052606082018190526080820181905260a0820181905260c09091015290565b8152604080516101a08101825260008082526020828101829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820181905261018082015291019081526020016145d7604051806101c0016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020016146156040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200161466260405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815260200161466f61472e565b81526020016146c560405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001614729604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b905290565b6040518060e001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016147296040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b73ffffffffffffffffffffffffffffffffffffffff811681146147c557600080fd5b50565b6000602082840312156147da57600080fd5b8135610fe5816147a3565b805173ffffffffffffffffffffffffffffffffffffffff1682526020810151614826602084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604081015161484e604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060810151614876606084018273ffffffffffffffffffffffffffffffffffffffff169052565b50608081015161489e608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a08101516148c660a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c08101516148ee60c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e081015161491660e084018273ffffffffffffffffffffffffffffffffffffffff169052565b5061010081810151805173ffffffffffffffffffffffffffffffffffffffff90811685840152602082015116610120850152505061012081015161014061498281850183805173ffffffffffffffffffffffffffffffffffffffff908116835260209182015116910152565b820151610180848101919091526101608301516101a080860191909152908301516101c080860191909152908301516101e08086019190915290830151610200850152909101516102209092019190915250565b805161ffff16825260208101516149f3602084018261ffff169052565b506040810151614a09604084018261ffff169052565b506060810151614a1f606084018261ffff169052565b506080810151614a35608084018261ffff169052565b5060a0810151614a4b60a084018261ffff169052565b5060c0810151614a6160c084018261ffff169052565b5060e0810151614a7760e084018261ffff169052565b506101008181015173ffffffffffffffffffffffffffffffffffffffff8116848301525050610120818101519083015261014080820151908301526101608082015173ffffffffffffffffffffffffffffffffffffffff811682850152505061018090810151910152565b805173ffffffffffffffffffffffffffffffffffffffff1682526020810151614b0f602084018215159052565b506040810151614b23604084018215159052565b506060810151614b3660608401826147e5565b506080810151614b4a6102a08401826149d6565b5060a08181015180516104408501526020808201516104608601526040808301516104808701526060808401516104a08801526080808501516104c0890152848601516104e089015260c0808601516105008a015260e0808701516105208b0152610100808801516105408c0152610120808901516105608d0152610140808a01516105808e01526101608a01516105a08e01526101808a01516105c08e01526101a0909901516105e08d0152838b015180516106008e0152808901516106208e0152808801516106408e0152808701516106608e0152808601516106808e01528a01516106a08d0152828b015180516106c08e0152808901516106e08e0152808801516107008e0152808701516107208e0152808601516107408e0152808b01516107608e0152808501516107808e01528301516107a08d0152818b015180516107c08e0152808901516107e08e0152808801516108008e0152808701516108208e0152808601516108408e0152808b01516108608e015284015180516108808e0152808901516108a08e0152808801516108c08e0152808701516108e08e0152808601516109008e0152808b01516109208e01528401516109408d0152808b0151805115156109608e0152808901516109808e0152808801516109a08e0152808701516109c08e0152808601516109e08e0152808b0151610a008e015280850151610a208e015280840151610a408e0152820151610a608d01529988015180511515610a808d015296870151610aa08c015294860151610ac08b015292850151610ae08a015290840151610b0089015294830151610b2088015293820151610b4087015292810151610b6086015291820151610b8085015291810151610ba08401520151610bc090910152565b610be081016107238284614ae2565b600060208284031215614dfa57600080fd5b5035919050565b805182526020810151614e2c602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151614e40604084018215159052565b506060810151614e54606084018215159052565b506080818101519083015260a0808201519083015260c0808201519083015260e0808201519083015261010080820151908301526101208082015190830152610140808201519083015261016090810151910152565b610d608101614eb98285614e01565b610fe5610180830184614ae2565b60008060408385031215614eda57600080fd5b8235614ee5816147a3565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810181811067ffffffffffffffff82111715614f4257614f42614ef3565b60405250565b60a0810181811067ffffffffffffffff82111715614f4257614f42614ef3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116810181811067ffffffffffffffff82111715614fac57614fac614ef3565b6040525050565b604051610220810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b60405290565b604051610120810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b604051610160810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b6040516101a0810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b604051610200810167ffffffffffffffff81118282101715614fd757614fd7614ef3565b600067ffffffffffffffff82111561508757615087614ef3565b5060051b60200190565b600082601f8301126150a257600080fd5b813560206150af8261506d565b6040516150bc8282614f68565b83815260059390931b85018201928281019150868411156150dc57600080fd5b8286015b848110156151005780356150f3816147a3565b83529183019183016150e0565b509695505050505050565b60006020828403121561511d57600080fd5b813567ffffffffffffffff81111561513457600080fd5b611dd384828501615091565b600081518084526020808501945080840160005b8381101561517b57615167878351614ae2565b610be0969096019590820190600101615154565b509495945050505050565b602081526000610fe56020830184615140565b805173ffffffffffffffffffffffffffffffffffffffff16825260208101516151da602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151615202604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606081015161522a606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151615252608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a081015160a083015260c081015160c083015260e081015160e0830152610100808201518184015250610120808201516152918285018215159052565b50505050565b61014081016107238284615199565b815181526020808301518183015260408084015181840152606080850151818501526080808601518186015260a0808701518187015260c0808801518051828901529586015160e0880152938501516101008701529184015161012086015283015161014085015282015161016084015201516101808201526101a08101610723565b602080825282518282018190526000919060409081850190868401855b8281101561538b5761537b848351805173ffffffffffffffffffffffffffffffffffffffff1682526020908101511515910152565b9284019290850190600101615346565b5091979650505050505050565b600080604083850312156153ab57600080fd5b823567ffffffffffffffff808211156153c357600080fd5b6153cf86838701615091565b93506020915081850135818111156153e657600080fd5b85019050601f810186136153f957600080fd5b80356154048161506d565b6040516154118282614f68565b82815260059290921b830184019184810191508883111561543157600080fd5b928401925b8284101561544f57833582529284019290840190615436565b80955050505050509250929050565b6020808252825182820181905260009190848201906040850190845b818110156154a15761548d838551615199565b92840192610140929092019160010161547a565b50909695505050505050565b600080604083850312156154c057600080fd5b50508035926020909101359150565b604080825283519082018190526000906020906060840190828701845b82811015615513576154ff848351614e01565b6101809390930192908401906001016154ec565b505050838103828501526155278186615140565b9695505050505050565b60008060006060848603121561554657600080fd5b8335615551816147a3565b95602085013595506040909401359392505050565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015115159082015260408101610723565b6000806000606084860312156155aa57600080fd5b505081359360208301359350604090920135919050565b6020808252825182820181905260009190848201906040850190845b818110156154a157835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016155dd565b6020808252825182820181905260009190848201906040850190845b818110156154a15783518352928401929184019160010161562b565b60006020828403121561565957600080fd5b5051919050565b8051801515811461127257600080fd5b8051611272816147a3565b600060e0828403121561568d57600080fd5b60405160e0810181811067ffffffffffffffff821117156156b0576156b0614ef3565b806040525080915082516156c3816147a3565b808252506020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c08201525092915050565b60008183036101a081121561571e57600080fd5b60405161572a81614f22565b8092508351815260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08301121561576157600080fd5b604051915061576f82614f48565b602084015161577d816147a3565b8083525060408401516020830152606084015160408301526080840151606083015260a084015160808301528160208201526157bc8560c0860161567b565b6040820152505092915050565b60006103a082840312156157dc57600080fd5b6157e4614fb3565b825181526020808401519082015260408084015190820152606080840151908201526080808401519082015260a0808401519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e0808401519082015290506102006158978482850161570a565b9082015292915050565b6000808284036104c08112156158b657600080fd5b610120808212156158c657600080fd5b6158ce614fdd565b91506158d985615660565b82526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010080860151818401525081935061593c868287016157c9565b925050509250929050565b60008082840361050081121561595c57600080fd5b6101608082121561596c57600080fd5b615974615001565b915061597f85615660565b82526020850151602083015260408501516040830152606085015160608301526080850151608083015260a085015160a083015260c085015160c083015260e085015160e083015261010080860151818401525061012080860151818401525061014080860151818401525081935061593c868287016157c9565b600060208284031215615a0c57600080fd5b8151610fe5816147a3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007f80000000000000000000000000000000000000000000000000000000000000008203615a7757615a77615a17565b5060000390565b808202811582820484141761072357610723615a17565b8181038181111561072357610723615a17565b600080600080600060a08688031215615ac057600080fd5b5050835160208501516040860151606087015160809097015192989197509594509092509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082615b4d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615bb257615bb2615a17565b5060010190565b60008060408385031215615bcc57600080fd5b505080516020909101519092909150565b600060033d11156105cf5760046000803e5060005160e01c90565b600060443d1015615c065790565b6040517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc803d016004833e81513d67ffffffffffffffff8160248401118184111715615c5457505050505090565b8285019150815181811115615c6c5750505050505090565b843d8701016020828501011115615c865750505050505090565b615c9560208286010187614f68565b509095945050505050565b8082018082111561072357610723615a17565b805160ff8116811461127257600080fd5b60006101a08284031215615cd757600080fd5b615cdf615025565b615ce883615670565b8152615cf660208401615670565b6020820152615d0760408401615670565b6040820152615d1860608401615670565b6060820152615d2960808401615670565b6080820152615d3a60a08401615670565b60a0820152615d4b60c08401615cb3565b60c0820152615d5c60e08401615cb3565b60e08201526101008381015190820152610120808401519082015261014080840151908201526101608084015190820152610180928301519281019290925250919050565b600060408284031215615db357600080fd5b6040516040810181811067ffffffffffffffff82111715615dd657615dd6614ef3565b80604052508091508251615de9816147a3565b81526020830151615df9816147a3565b6020919091015292915050565b60006102408284031215615e1957600080fd5b615e21615049565b615e2a83615670565b8152615e3860208401615670565b6020820152615e4960408401615670565b6040820152615e5a60608401615670565b6060820152615e6b60808401615670565b6080820152615e7c60a08401615670565b60a0820152615e8d60c08401615670565b60c0820152615e9e60e08401615670565b60e0820152610100615eb285828601615da1565b90820152610140615ec585858301615da1565b61012083015261018080850151828401526101a09150818501516101608401526101c080860151828501526101e09150818601518385015261020086015181850152506102208501518184015250508091505092915050565b61ffff818116838216028082169190828114611a6f57611a6f615a17565b60008060008060808587031215615f5257600080fd5b50508251602084015160408501516060909501519196909550909250905056fea2646970667358221220831baa9e285250f6bdcb5e3341ab73dc2730494f9c61998c17ca36baf91a491964736f6c63430008150033

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

000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d00000000000000000000000098d900e25aaf345a4b23f454751ec5083443fa83

-----Decoded View---------------
Arg [0] : factory_ (address): 0x324c5Dc1fC42c7a4D43d92df1eBA58a54d13Bf2d
Arg [1] : liquidityResolver_ (address): 0x98d900e25AAf345A4B23f454751EC5083443Fa83

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000324c5dc1fc42c7a4d43d92df1eba58a54d13bf2d
Arg [1] : 00000000000000000000000098d900e25aaf345a4b23f454751ec5083443fa83


Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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