Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
434322 | 18 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Name:
FluidVaultResolver
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 10000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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()); } }
// 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); }
// 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); }
// 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); }
// 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)))); } }
// 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) } } } }
// 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_; } }
// 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_)); } }
// 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; }
// 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; } } } }
// 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); } }
// 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_)); } }
// 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) } } } }
// 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; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.21; contract Error { error FluidOracleError(uint256 errorId_); }
// 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; }
// 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_); }
// 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); }
//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_ ); }
// 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` } }
// 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_) {} }
// 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; } }
// 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_); } }
//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; }
//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_); }
//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); }
{ "optimizer": { "enabled": true, "runs": 10000000 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.