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 | |||
---|---|---|---|---|---|---|
434199 | 15 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Name:
FluidLiquidityResolver
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 { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LiquidityCalcs } from "../../../libraries/liquidityCalcs.sol"; import { BigMathMinified } from "../../../libraries/bigMathMinified.sol"; import { LiquiditySlotsLink } from "../../../libraries/liquiditySlotsLink.sol"; import { IFluidLiquidity } from "../../../liquidity/interfaces/iLiquidity.sol"; import { IFluidLiquidityResolver } from "./iLiquidityResolver.sol"; import { Structs } from "./structs.sol"; import { Variables } from "./variables.sol"; interface TokenInterface { function balanceOf(address) external view returns (uint); } /// @notice Fluid Liquidity resolver /// Implements various view-only methods to give easy access to Liquidity data. contract FluidLiquidityResolver is IFluidLiquidityResolver, Variables, Structs { /// @dev address that is mapped to the chain native token address internal constant _NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @notice thrown if an input param address is zero error FluidLiquidityResolver__AddressZero(); constructor(IFluidLiquidity liquidity_) Variables(liquidity_) { if (address(liquidity_) == address(0)) { revert FluidLiquidityResolver__AddressZero(); } } /// @inheritdoc IFluidLiquidityResolver function getRevenueCollector() public view returns (address) { return address(uint160(LIQUIDITY.readFromStorage(bytes32(0)))); } /// @inheritdoc IFluidLiquidityResolver function getRevenue(address token_) public view returns (uint256 revenueAmount_) { uint256 liquidityTokenBalance_ = token_ == _NATIVE_TOKEN_ADDRESS ? address(LIQUIDITY).balance : IERC20(token_).balanceOf(address(LIQUIDITY)); uint256 exchangePricesAndConfig_ = getExchangePricesAndConfig(token_); if (exchangePricesAndConfig_ == 0) { return 0; } return LiquidityCalcs.calcRevenue(getTotalAmounts(token_), exchangePricesAndConfig_, liquidityTokenBalance_); } /// @inheritdoc IFluidLiquidityResolver function getStatus() public view returns (uint256) { return LIQUIDITY.readFromStorage(bytes32(LiquiditySlotsLink.LIQUIDITY_STATUS_SLOT)); } /// @inheritdoc IFluidLiquidityResolver function isAuth(address auth_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot(LiquiditySlotsLink.LIQUIDITY_AUTHS_MAPPING_SLOT, auth_) ); } /// @inheritdoc IFluidLiquidityResolver function isGuardian(address guardian_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_GUARDIANS_MAPPING_SLOT, guardian_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getUserClass(address user_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_USER_CLASS_MAPPING_SLOT, user_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getExchangePricesAndConfig(address token_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT, token_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getRateConfig(address token_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_RATE_DATA_MAPPING_SLOT, token_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getTotalAmounts(address token_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT, token_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getConfigs2(address token_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_CONFIGS2_MAPPING_SLOT, token_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getUserSupply(address user_, address token_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateDoubleMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT, user_, token_ ) ); } /// @inheritdoc IFluidLiquidityResolver function getUserBorrow(address user_, address token_) public view returns (uint256) { return LIQUIDITY.readFromStorage( LiquiditySlotsLink.calculateDoubleMappingStorageSlot( LiquiditySlotsLink.LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT, user_, token_ ) ); } /// @inheritdoc IFluidLiquidityResolver function listedTokens() public view returns (address[] memory listedTokens_) { uint256 length_ = LIQUIDITY.readFromStorage(bytes32(LiquiditySlotsLink.LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT)); listedTokens_ = new address[](length_); uint256 startingSlotForArrayElements_ = uint256( keccak256(abi.encode(LiquiditySlotsLink.LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT)) ); for (uint256 i; i < length_; i++) { listedTokens_[i] = address(uint160(LIQUIDITY.readFromStorage(bytes32(startingSlotForArrayElements_ + i)))); } } /// @inheritdoc IFluidLiquidityResolver function getTokenRateData(address token_) public view returns (RateData memory rateData_) { uint256 rateConfig_ = getRateConfig(token_); rateData_.version = rateConfig_ & 0xF; if (rateData_.version == 1) { rateData_.rateDataV1.token = token_; rateData_.rateDataV1.rateAtUtilizationZero = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) & X16; rateData_.rateDataV1.kink = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16; rateData_.rateDataV1.rateAtUtilizationKink = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16; rateData_.rateDataV1.rateAtUtilizationMax = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) & X16; } else if (rateData_.version == 2) { rateData_.rateDataV2.token = token_; rateData_.rateDataV2.rateAtUtilizationZero = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) & X16; rateData_.rateDataV2.kink1 = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) & X16; rateData_.rateDataV2.rateAtUtilizationKink1 = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16; rateData_.rateDataV2.kink2 = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) & X16; rateData_.rateDataV2.rateAtUtilizationKink2 = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16; rateData_.rateDataV2.rateAtUtilizationMax = (rateConfig_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) & X16; } else if (rateData_.version > 0) { // when version is 0 -> token not configured yet. do not revert, just return 0 for all values revert("not-valid-rate-version"); } } /// @inheritdoc IFluidLiquidityResolver function getTokensRateData(address[] calldata tokens_) public view returns (RateData[] memory rateDatas_) { uint256 length_ = tokens_.length; rateDatas_ = new RateData[](length_); for (uint256 i; i < length_; i++) { rateDatas_[i] = getTokenRateData(tokens_[i]); } } /// @inheritdoc IFluidLiquidityResolver function getOverallTokenData( address token_ ) public view returns (Structs.OverallTokenData memory overallTokenData_) { overallTokenData_.rateData = getTokenRateData(token_); uint256 exchangePriceAndConfig_ = getExchangePricesAndConfig(token_); if (exchangePriceAndConfig_ > 0) { uint256 totalAmounts_ = getTotalAmounts(token_); (overallTokenData_.supplyExchangePrice, overallTokenData_.borrowExchangePrice) = LiquidityCalcs .calcExchangePrices(exchangePriceAndConfig_); overallTokenData_.borrowRate = exchangePriceAndConfig_ & X16; overallTokenData_.fee = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14; overallTokenData_.lastStoredUtilization = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14; overallTokenData_.storageUpdateThreshold = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD) & X14; overallTokenData_.lastUpdateTimestamp = (exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33; overallTokenData_.maxUtilization = FOUR_DECIMALS; if ((exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_USES_CONFIGS2) & 1 == 1) { overallTokenData_.maxUtilization = getConfigs2(token_) & X14; } // Extract supply & borrow amounts uint256 temp_ = totalAmounts_ & X64; overallTokenData_.supplyRawInterest = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK); temp_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64; overallTokenData_.supplyInterestFree = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK); temp_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64; overallTokenData_.borrowRawInterest = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK); // no & mask needed for borrow interest free as it occupies the last bits in the storage slot temp_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE); overallTokenData_.borrowInterestFree = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK); uint256 supplyWithInterest_; uint256 borrowWithInterest_; if (overallTokenData_.supplyRawInterest > 0) { // use old exchange prices for supply rate to be at same level as borrow rate from storage. // Note the rate here can be a tiny bit with higher precision because we use borrowWithInterest_ / supplyWithInterest_ // which has higher precision than the utilization used from storage in LiquidityCalcs supplyWithInterest_ = (overallTokenData_.supplyRawInterest * ((exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) & X64)) / EXCHANGE_PRICES_PRECISION; // normalized from raw borrowWithInterest_ = (overallTokenData_.borrowRawInterest * ((exchangePriceAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) & X64)) / EXCHANGE_PRICES_PRECISION; // normalized from raw overallTokenData_.supplyRate = supplyWithInterest_ == 0 ? 0 : (overallTokenData_.borrowRate * (FOUR_DECIMALS - overallTokenData_.fee) * borrowWithInterest_) / (supplyWithInterest_ * FOUR_DECIMALS); } supplyWithInterest_ = (overallTokenData_.supplyRawInterest * overallTokenData_.supplyExchangePrice) / EXCHANGE_PRICES_PRECISION; // normalized from raw overallTokenData_.totalSupply = supplyWithInterest_ + overallTokenData_.supplyInterestFree; borrowWithInterest_ = (overallTokenData_.borrowRawInterest * overallTokenData_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION; // normalized from raw overallTokenData_.totalBorrow = borrowWithInterest_ + overallTokenData_.borrowInterestFree; overallTokenData_.revenue = getRevenue(token_); } } /// @inheritdoc IFluidLiquidityResolver function getOverallTokensData( address[] memory tokens_ ) public view returns (Structs.OverallTokenData[] memory overallTokensData_) { uint256 length_ = tokens_.length; overallTokensData_ = new Structs.OverallTokenData[](length_); for (uint256 i; i < length_; i++) { overallTokensData_[i] = getOverallTokenData(tokens_[i]); } } /// @inheritdoc IFluidLiquidityResolver function getAllOverallTokensData() public view returns (Structs.OverallTokenData[] memory overallTokensData_) { return getOverallTokensData(listedTokens()); } /// @inheritdoc IFluidLiquidityResolver function getUserSupplyData( address user_, address token_ ) public view returns (Structs.UserSupplyData memory userSupplyData_, Structs.OverallTokenData memory overallTokenData_) { overallTokenData_ = getOverallTokenData(token_); uint256 userSupply_ = getUserSupply(user_, token_); if (userSupply_ > 0) { // if userSupply_ == 0 -> user not configured yet for token at Liquidity userSupplyData_.modeWithInterest = userSupply_ & 1 == 1; userSupplyData_.supply = BigMathMinified.fromBigNumber( (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); // get updated expanded withdrawal limit userSupplyData_.withdrawalLimit = LiquidityCalcs.calcWithdrawalLimitBeforeOperate( userSupply_, userSupplyData_.supply ); userSupplyData_.lastUpdateTimestamp = (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33; userSupplyData_.expandPercent = (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14; userSupplyData_.expandDuration = (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24; userSupplyData_.baseWithdrawalLimit = BigMathMinified.fromBigNumber( (userSupply_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); if (userSupplyData_.modeWithInterest) { // convert raw amounts to normal for withInterest mode userSupplyData_.supply = (userSupplyData_.supply * overallTokenData_.supplyExchangePrice) / EXCHANGE_PRICES_PRECISION; userSupplyData_.withdrawalLimit = (userSupplyData_.withdrawalLimit * overallTokenData_.supplyExchangePrice) / EXCHANGE_PRICES_PRECISION; userSupplyData_.baseWithdrawalLimit = (userSupplyData_.baseWithdrawalLimit * overallTokenData_.supplyExchangePrice) / EXCHANGE_PRICES_PRECISION; } userSupplyData_.withdrawableUntilLimit = userSupplyData_.supply > userSupplyData_.withdrawalLimit ? userSupplyData_.supply - userSupplyData_.withdrawalLimit : 0; uint balanceOf_ = token_ == _NATIVE_TOKEN_ADDRESS ? address(LIQUIDITY).balance : TokenInterface(token_).balanceOf(address(LIQUIDITY)); userSupplyData_.withdrawable = balanceOf_ > userSupplyData_.withdrawableUntilLimit ? userSupplyData_.withdrawableUntilLimit : balanceOf_; } } /// @inheritdoc IFluidLiquidityResolver function getUserMultipleSupplyData( address user_, address[] calldata tokens_ ) public view returns ( Structs.UserSupplyData[] memory userSuppliesData_, Structs.OverallTokenData[] memory overallTokensData_ ) { uint256 length_ = tokens_.length; userSuppliesData_ = new Structs.UserSupplyData[](length_); overallTokensData_ = new Structs.OverallTokenData[](length_); for (uint256 i; i < length_; i++) { (userSuppliesData_[i], overallTokensData_[i]) = getUserSupplyData(user_, tokens_[i]); } } /// @inheritdoc IFluidLiquidityResolver function getUserBorrowData( address user_, address token_ ) public view returns (Structs.UserBorrowData memory userBorrowData_, Structs.OverallTokenData memory overallTokenData_) { overallTokenData_ = getOverallTokenData(token_); uint256 userBorrow_ = getUserBorrow(user_, token_); if (userBorrow_ > 0) { // if userBorrow_ == 0 -> user not configured yet for token at Liquidity userBorrowData_.modeWithInterest = userBorrow_ & 1 == 1; userBorrowData_.borrow = BigMathMinified.fromBigNumber( (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); // get updated expanded borrow limit userBorrowData_.borrowLimit = LiquidityCalcs.calcBorrowLimitBeforeOperate( userBorrow_, userBorrowData_.borrow ); userBorrowData_.lastUpdateTimestamp = (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33; userBorrowData_.expandPercent = (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; userBorrowData_.expandDuration = (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24; userBorrowData_.baseBorrowLimit = BigMathMinified.fromBigNumber( (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); userBorrowData_.maxBorrowLimit = BigMathMinified.fromBigNumber( (userBorrow_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18, DEFAULT_EXPONENT_SIZE, DEFAULT_EXPONENT_MASK ); if (userBorrowData_.modeWithInterest) { // convert raw amounts to normal for withInterest mode userBorrowData_.borrow = (userBorrowData_.borrow * overallTokenData_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION; userBorrowData_.borrowLimit = (userBorrowData_.borrowLimit * overallTokenData_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION; userBorrowData_.baseBorrowLimit = (userBorrowData_.baseBorrowLimit * overallTokenData_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION; userBorrowData_.maxBorrowLimit = (userBorrowData_.maxBorrowLimit * overallTokenData_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION; } userBorrowData_.borrowLimitUtilization = (overallTokenData_.maxUtilization * overallTokenData_.totalSupply) / 1e4; // uncollected revenue is counting towards available balanceOf. // because of this "borrowable" would be showing an amount that can go above 100% utilization, causing a revert. // need to take into consideration the borrowable amount until the max utilization limit, which depends on the total // borrow amount (not user specific) uint borrowableUntilUtilizationLimit_ = userBorrowData_.borrowLimitUtilization > overallTokenData_.totalBorrow ? userBorrowData_.borrowLimitUtilization - overallTokenData_.totalBorrow : 0; uint borrowableUntilBorrowLimit_ = userBorrowData_.borrowLimit > userBorrowData_.borrow ? userBorrowData_.borrowLimit - userBorrowData_.borrow : 0; userBorrowData_.borrowableUntilLimit = borrowableUntilBorrowLimit_ > borrowableUntilUtilizationLimit_ ? borrowableUntilUtilizationLimit_ : borrowableUntilBorrowLimit_; // if available balance at Liquidity is less than the borrowableUntilLimit amount, then the balance is // the limiting borrowable amount. uint balanceOf_ = token_ == _NATIVE_TOKEN_ADDRESS ? address(LIQUIDITY).balance : TokenInterface(token_).balanceOf(address(LIQUIDITY)); userBorrowData_.borrowable = balanceOf_ > userBorrowData_.borrowableUntilLimit ? userBorrowData_.borrowableUntilLimit : balanceOf_; } } /// @inheritdoc IFluidLiquidityResolver function getUserMultipleBorrowData( address user_, address[] calldata tokens_ ) public view returns ( Structs.UserBorrowData[] memory userBorrowingsData_, Structs.OverallTokenData[] memory overallTokensData_ ) { uint256 length_ = tokens_.length; userBorrowingsData_ = new UserBorrowData[](length_); overallTokensData_ = new Structs.OverallTokenData[](length_); for (uint256 i; i < length_; i++) { (userBorrowingsData_[i], overallTokensData_[i]) = getUserBorrowData(user_, tokens_[i]); } } /// @inheritdoc IFluidLiquidityResolver function getUserMultipleBorrowSupplyData( address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_ ) public view returns ( Structs.UserSupplyData[] memory userSuppliesData_, Structs.OverallTokenData[] memory overallSupplyTokensData_, Structs.UserBorrowData[] memory userBorrowingsData_, Structs.OverallTokenData[] memory overallBorrowTokensData_ ) { uint256 length_ = supplyTokens_.length; userSuppliesData_ = new Structs.UserSupplyData[](length_); overallSupplyTokensData_ = new Structs.OverallTokenData[](length_); for (uint256 i; i < length_; i++) { (userSuppliesData_[i], overallSupplyTokensData_[i]) = getUserSupplyData(user_, supplyTokens_[i]); } length_ = borrowTokens_.length; userBorrowingsData_ = new UserBorrowData[](length_); overallBorrowTokensData_ = new Structs.OverallTokenData[](length_); for (uint256 i; i < length_; i++) { (userBorrowingsData_[i], overallBorrowTokensData_[i]) = getUserBorrowData(user_, borrowTokens_[i]); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.21; interface IProxy { function setAdmin(address newAdmin_) external; function setDummyImplementation(address newDummyImplementation_) external; function addImplementation(address implementation_, bytes4[] calldata sigs_) external; function removeImplementation(address implementation_) external; function getAdmin() external view returns (address); function getDummyImplementation() external view returns (address); function getImplementationSigs(address impl_) external view returns (bytes4[] memory); function getSigsImplementation(bytes4 sig_) external view returns (address); function readFromStorage(bytes32 slot_) external view returns (uint256 result_); }
// 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; 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; 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; 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: MIT pragma solidity 0.8.21; import { IProxy } from "../../infiniteProxy/interfaces/iProxy.sol"; import { Structs as AdminModuleStructs } from "../adminModule/structs.sol"; interface IFluidLiquidityAdmin { /// @notice adds/removes auths. Auths generally could be contracts which can have restricted actions defined on contract. /// auths can be helpful in reducing governance overhead where it's not needed. /// @param authsStatus_ array of structs setting allowed status for an address. /// status true => add auth, false => remove auth function updateAuths(AdminModuleStructs.AddressBool[] calldata authsStatus_) external; /// @notice adds/removes guardians. Only callable by Governance. /// @param guardiansStatus_ array of structs setting allowed status for an address. /// status true => add guardian, false => remove guardian function updateGuardians(AdminModuleStructs.AddressBool[] calldata guardiansStatus_) external; /// @notice changes the revenue collector address (contract that is sent revenue). Only callable by Governance. /// @param revenueCollector_ new revenue collector address function updateRevenueCollector(address revenueCollector_) external; /// @notice changes current status, e.g. for pausing or unpausing all user operations. Only callable by Auths. /// @param newStatus_ new status /// status = 2 -> pause, status = 1 -> resume. function changeStatus(uint256 newStatus_) external; /// @notice update tokens rate data version 1. Only callable by Auths. /// @param tokensRateData_ array of RateDataV1Params with rate data to set for each token function updateRateDataV1s(AdminModuleStructs.RateDataV1Params[] calldata tokensRateData_) external; /// @notice update tokens rate data version 2. Only callable by Auths. /// @param tokensRateData_ array of RateDataV2Params with rate data to set for each token function updateRateDataV2s(AdminModuleStructs.RateDataV2Params[] calldata tokensRateData_) external; /// @notice updates token configs: fee charge on borrowers interest & storage update utilization threshold. /// Only callable by Auths. /// @param tokenConfigs_ contains token address, fee & utilization threshold function updateTokenConfigs(AdminModuleStructs.TokenConfig[] calldata tokenConfigs_) external; /// @notice updates user classes: 0 is for new protocols, 1 is for established protocols. /// Only callable by Auths. /// @param userClasses_ struct array of uint256 value to assign for each user address function updateUserClasses(AdminModuleStructs.AddressUint256[] calldata userClasses_) external; /// @notice sets user supply configs per token basis. Eg: with interest or interest-free and automated limits. /// Only callable by Auths. /// @param userSupplyConfigs_ struct array containing user supply config, see `UserSupplyConfig` struct for more info function updateUserSupplyConfigs(AdminModuleStructs.UserSupplyConfig[] memory userSupplyConfigs_) external; /// @notice sets a new withdrawal limit as the current limit for a certain user /// @param user_ user address for which to update the withdrawal limit /// @param token_ token address for which to update the withdrawal limit /// @param newLimit_ new limit until which user supply can decrease to. /// Important: input in raw. Must account for exchange price in input param calculation. /// Note any limit that is < max expansion or > current user supply will set max expansion limit or /// current user supply as limit respectively. /// - set 0 to make maximum possible withdrawable: instant full expansion, and if that goes /// below base limit then fully down to 0. /// - set type(uint256).max to make current withdrawable 0 (sets current user supply as limit). function updateUserWithdrawalLimit(address user_, address token_, uint256 newLimit_) external; /// @notice setting user borrow configs per token basis. Eg: with interest or interest-free and automated limits. /// Only callable by Auths. /// @param userBorrowConfigs_ struct array containing user borrow config, see `UserBorrowConfig` struct for more info function updateUserBorrowConfigs(AdminModuleStructs.UserBorrowConfig[] memory userBorrowConfigs_) external; /// @notice pause operations for a particular user in class 0 (class 1 users can't be paused by guardians). /// Only callable by Guardians. /// @param user_ address of user to pause operations for /// @param supplyTokens_ token addresses to pause withdrawals for /// @param borrowTokens_ token addresses to pause borrowings for function pauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external; /// @notice unpause operations for a particular user in class 0 (class 1 users can't be paused by guardians). /// Only callable by Guardians. /// @param user_ address of user to unpause operations for /// @param supplyTokens_ token addresses to unpause withdrawals for /// @param borrowTokens_ token addresses to unpause borrowings for function unpauseUser(address user_, address[] calldata supplyTokens_, address[] calldata borrowTokens_) external; /// @notice collects revenue for tokens to configured revenueCollector address. /// @param tokens_ array of tokens to collect revenue for /// @dev Note that this can revert if token balance is < revenueAmount (utilization > 100%) function collectRevenue(address[] calldata tokens_) external; /// @notice gets the current updated exchange prices for n tokens and updates all prices, rates related data in storage. /// @param tokens_ tokens to update exchange prices for /// @return supplyExchangePrices_ new supply rates of overall system for each token /// @return borrowExchangePrices_ new borrow rates of overall system for each token function updateExchangePrices( address[] calldata tokens_ ) external returns (uint256[] memory supplyExchangePrices_, uint256[] memory borrowExchangePrices_); } interface IFluidLiquidityLogic is IFluidLiquidityAdmin { /// @notice Single function which handles supply, withdraw, borrow & payback /// @param token_ address of token (0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE for native) /// @param supplyAmount_ if +ve then supply, if -ve then withdraw, if 0 then nothing /// @param borrowAmount_ if +ve then borrow, if -ve then payback, if 0 then nothing /// @param withdrawTo_ if withdrawal then to which address /// @param borrowTo_ if borrow then to which address /// @param callbackData_ callback data passed to `liquidityCallback` method of protocol /// @return memVar3_ updated supplyExchangePrice /// @return memVar4_ updated borrowExchangePrice /// @dev to trigger skipping in / out transfers (gas optimization): /// - ` callbackData_` MUST be encoded so that "from" address is the last 20 bytes in the last 32 bytes slot, /// also for native token operations where liquidityCallback is not triggered! /// from address must come at last position if there is more data. I.e. encode like: /// abi.encode(otherVar1, otherVar2, FROM_ADDRESS). Note dynamic types used with abi.encode come at the end /// so if dynamic types are needed, you must use abi.encodePacked to ensure the from address is at the end. /// - this "from" address must match withdrawTo_ or borrowTo_ and must be == `msg.sender` /// - `callbackData_` must in addition to the from address as described above include bytes32 SKIP_TRANSFERS /// in the slot before (bytes 32 to 63) /// - `msg.value` must be 0. /// - Amounts must be either: /// - supply(+) == borrow(+), withdraw(-) == payback(-). /// - Liquidity must be on the winning side (deposit < borrow OR payback < withdraw). function operate( address token_, int256 supplyAmount_, int256 borrowAmount_, address withdrawTo_, address borrowTo_, bytes calldata callbackData_ ) external payable returns (uint256 memVar3_, uint256 memVar4_); } interface IFluidLiquidity is IProxy, IFluidLiquidityLogic {}
//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 { IFluidLiquidity } from "../../../liquidity/interfaces/iLiquidity.sol"; contract Variables { /// @dev Storage slot with the admin of the contract. Logic from "proxy.sol". /// This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is /// validated in the constructor. bytes32 internal constant GOVERNANCE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; 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 SMALL_COEFFICIENT_SIZE = 10; uint256 internal constant DEFAULT_COEFFICIENT_SIZE = 56; uint256 internal constant DEFAULT_EXPONENT_SIZE = 8; uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF; uint256 internal constant FOUR_DECIMALS = 10000; uint256 internal constant X8 = 0xff; uint256 internal constant X14 = 0x3fff; 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; /// @notice address of the liquidity contract IFluidLiquidity public immutable LIQUIDITY; constructor(IFluidLiquidity liquidity_) { LIQUIDITY = IFluidLiquidity(liquidity_); } }
{ "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":"contract IFluidLiquidity","name":"liquidity_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"errorId_","type":"uint256"}],"name":"FluidLiquidityCalcsError","type":"error"},{"inputs":[],"name":"FluidLiquidityResolver__AddressZero","type":"error"},{"inputs":[],"name":"LIQUIDITY","outputs":[{"internalType":"contract IFluidLiquidity","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllOverallTokensData","outputs":[{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData[]","name":"overallTokensData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getConfigs2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getExchangePricesAndConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getOverallTokenData","outputs":[{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData","name":"overallTokenData_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens_","type":"address[]"}],"name":"getOverallTokensData","outputs":[{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData[]","name":"overallTokensData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getRateConfig","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getRevenue","outputs":[{"internalType":"uint256","name":"revenueAmount_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRevenueCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStatus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getTokenRateData","outputs":[{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens_","type":"address[]"}],"name":"getTokensRateData","outputs":[{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData[]","name":"rateDatas_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"getTotalAmounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address","name":"token_","type":"address"}],"name":"getUserBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address","name":"token_","type":"address"}],"name":"getUserBorrowData","outputs":[{"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":"userBorrowData_","type":"tuple"},{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData","name":"overallTokenData_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"}],"name":"getUserClass","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address[]","name":"tokens_","type":"address[]"}],"name":"getUserMultipleBorrowData","outputs":[{"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":"userBorrowingsData_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData[]","name":"overallTokensData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address[]","name":"supplyTokens_","type":"address[]"},{"internalType":"address[]","name":"borrowTokens_","type":"address[]"}],"name":"getUserMultipleBorrowSupplyData","outputs":[{"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":"userSuppliesData_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData[]","name":"overallSupplyTokensData_","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":"userBorrowingsData_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData[]","name":"overallBorrowTokensData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address[]","name":"tokens_","type":"address[]"}],"name":"getUserMultipleSupplyData","outputs":[{"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":"userSuppliesData_","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData[]","name":"overallTokensData_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address","name":"token_","type":"address"}],"name":"getUserSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user_","type":"address"},{"internalType":"address","name":"token_","type":"address"}],"name":"getUserSupplyData","outputs":[{"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":"userSupplyData_","type":"tuple"},{"components":[{"internalType":"uint256","name":"borrowRate","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lastStoredUtilization","type":"uint256"},{"internalType":"uint256","name":"storageUpdateThreshold","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTimestamp","type":"uint256"},{"internalType":"uint256","name":"supplyExchangePrice","type":"uint256"},{"internalType":"uint256","name":"borrowExchangePrice","type":"uint256"},{"internalType":"uint256","name":"supplyRawInterest","type":"uint256"},{"internalType":"uint256","name":"supplyInterestFree","type":"uint256"},{"internalType":"uint256","name":"borrowRawInterest","type":"uint256"},{"internalType":"uint256","name":"borrowInterestFree","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"totalBorrow","type":"uint256"},{"internalType":"uint256","name":"revenue","type":"uint256"},{"internalType":"uint256","name":"maxUtilization","type":"uint256"},{"components":[{"internalType":"uint256","name":"version","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV1Params","name":"rateDataV1","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"kink1","type":"uint256"},{"internalType":"uint256","name":"kink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationZero","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink1","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationKink2","type":"uint256"},{"internalType":"uint256","name":"rateAtUtilizationMax","type":"uint256"}],"internalType":"struct Structs.RateDataV2Params","name":"rateDataV2","type":"tuple"}],"internalType":"struct Structs.RateData","name":"rateData","type":"tuple"}],"internalType":"struct Structs.OverallTokenData","name":"overallTokenData_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"auth_","type":"address"}],"name":"isAuth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian_","type":"address"}],"name":"isGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listedTokens","outputs":[{"internalType":"address[]","name":"listedTokens_","type":"address[]"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200359238038062003592833981016040819052620000349162000068565b6001600160a01b03811660808190526200006157604051630dd6e9eb60e41b815260040160405180910390fd5b506200009a565b6000602082840312156200007b57600080fd5b81516001600160a01b03811681146200009357600080fd5b9392505050565b6080516134576200013b6000396000818161022f015281816104560152818161083c015281816108b001528181610b8d01528181610cb001528181610d7401528181610e8e01528181610fb601528181611042015281816110b60152818161112a015281816111c7015281816112410152818161158c0152818161160601528181611c0701528181611eb301528181611f2d0152611ffb01526134576000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c80634e69d560116100e3578063b3fc48bc1161008c578063cdb5964411610066578063cdb59644146103c7578063e72ef91b146103da578063ee9e836d146103fb57600080fd5b8063b3fc48bc14610370578063b505b75014610393578063cd4a7e14146103b457600080fd5b80636e938406116100bd5780636e9384061461032957806385b670951461033c578063967915d61461034f57600080fd5b80634e69d560146102fb57806360fed05f14610303578063672694891461031657600080fd5b806329e04fbf1161014557806334a2e6591161011f57806334a2e659146102c957806336ebf76c146102d15780634a3d6bda146102e657600080fd5b806329e04fbf146102765780632b001833146102965780632b66fc05146102a957600080fd5b80631f735227116101765780631f735227146102045780632520e7ff146102175780632861c7d11461022a57600080fd5b80630c68ba211461019d57806314c0ac36146101c35780631dacf037146101e4575b600080fd5b6101b06101ab3660046125d5565b61040e565b6040519081526020015b60405180910390f35b6101d66101d136600461263c565b6104e3565b6040516101ba9291906128aa565b6101f76101f23660046125d5565b610667565b6040516101ba91906128d8565b6101b06102123660046125d5565b6107f4565b6101b06102253660046125d5565b610868565b6102517f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ba565b6102896102843660046125d5565b6108dc565b6040516101ba9190612988565b6101b06102a43660046125d5565b610b45565b6102bc6102b7366004612ad7565b610bb9565b6040516101ba9190612b19565b610251610c7e565b6102d9610d36565b6040516101ba9190612c09565b6102ee610d3f565b6040516101ba9190612c1c565b6101b0610f84565b6101b06103113660046125d5565b610ffa565b6101b06103243660046125d5565b61106e565b6101b06103373660046125d5565b6110e2565b6101b061034a3660046125d5565b611156565b61036261035d366004612c6a565b6112b4565b6040516101ba929190612c9d565b61038361037e366004612e6c565b61166a565b6040516101ba9493929190612f97565b6103a66103a136600461263c565b611967565b6040516101ba929190612fef565b6102d96103c2366004613031565b611ada565b6101b06103d5366004612c6a565b611b98565b6103ed6103e8366004612c6a565b611c95565b6040516101ba929190613114565b6101b0610409366004612c6a565b611f8c565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526003838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e4905b6040518263ffffffff1660e01b815260040161049c91815260200190565b602060405180830381865afa1580156104b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104dd91906132cb565b92915050565b606080828067ffffffffffffffff81111561050057610500613002565b60405190808252806020026020018201604052801561058257816020015b61056f60405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020019060019003908161051e5790505b5092508067ffffffffffffffff81111561059e5761059e613002565b6040519080825280602002602001820160405280156105d757816020015b6105c461246e565b8152602001906001900390816105bc5790505b50915060005b8181101561065d57610610878787848181106105fb576105fb6132e4565b90506020020160208101906103e891906125d5565b858381518110610622576106226132e4565b6020026020010185848151811061063b5761063b6132e4565b602002602001018290528290525050808061065590613342565b9150506105dd565b5050935093915050565b61066f6124f7565b600061067a83610ffa565b600f81168084529091506001036106f2576020828101805173ffffffffffffffffffffffffffffffffffffffff86169052805161ffff600485901c81166040909201919091528151601485901c82169301929092528051602484901c831660609091015251603483901c9091166080909101526107ee565b8151600203610780576040828101805173ffffffffffffffffffffffffffffffffffffffff86169052805161ffff600485901c81166060909201919091528151601485901c82166020909101528151602485901c82166080909101528151603485901c82169301929092528051604484901c831660a09091015251605483901c90911660c0909101526107ee565b8151156107ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e6f742d76616c69642d726174652d76657273696f6e0000000000000000000060448201526064015b60405180910390fd5b50919050565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526004838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e49061047e565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526002838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e49061047e565b6108e461246e565b6108ed82610667565b61020082015260006108fe83610b45565b905080156107ee576000610911846110e2565b905061091c82612027565b60e085015260c084015261ffff82168352601082901c613fff9081166040850152601e83901c81166060850152602c83901c166080840152603a82901c6401ffffffff1660a08401526127106101e0840152600160f983901c8116900361099157613fff6109898561106e565b166101e08401525b66ffffffffffffff600882901c811660ff8084169190911b6101008601819052604884901c8316604085901c83161b610120870152608884901c909216608084901c82161b61014086015260c883901c60c084901c9182161b61016086015290600090819015610ab05764e8d4a5100067ffffffffffffffff605b87901c16876101000151610a20919061337a565b610a2a91906133c0565b915064e8d4a5100067ffffffffffffffff609b87901c16876101400151610a51919061337a565b610a5b91906133c0565b90508115610aa757610a6f6127108361337a565b818760400151612710610a8291906133fb565b8851610a8e919061337a565b610a98919061337a565b610aa291906133c0565b610aaa565b60005b60208701525b64e8d4a510008660c00151876101000151610acb919061337a565b610ad591906133c0565b915085610120015182610ae8919061340e565b61018087015260e086015161014087015164e8d4a5100091610b099161337a565b610b1391906133c0565b905085610160015181610b26919061340e565b6101a0870152610b3587611156565b6101c08701525050505050919050565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526005838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e49061047e565b6060818067ffffffffffffffff811115610bd557610bd5613002565b604051908082528060200260200182016040528015610c0e57816020015b610bfb6124f7565b815260200190600190039081610bf35790505b50915060005b81811015610c7657610c46858583818110610c3157610c316132e4565b90506020020160208101906101f291906125d5565b838281518110610c5857610c586132e4565b60200260200101819052508080610c6e90613342565b915050610c14565b505092915050565b6040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600060048201819052907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063b5c736e4906024015b602060405180830381865afa158015610d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3191906132cb565b905090565b6060610d316103c25b6040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600a60048201526060906000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015610dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906132cb565b90508067ffffffffffffffff811115610e0f57610e0f613002565b604051908082528060200260200182016040528015610e38578160200160208202803683370190505b5091506000600a604051602001610e5191815260200190565b6040516020818303038152906040528051906020012060001c905060005b82811015610f7e5773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663b5c736e4610ebd838561340e565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526004810191909152602401602060405180830381865afa158015610f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3591906132cb565b848281518110610f4757610f476132e4565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015280610f7681613342565b915050610e6f565b50505090565b6040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600160048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401610cf0565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526006838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e49061047e565b6040805173ffffffffffffffffffffffffffffffffffffffff838116602080840191909152600b838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e49061047e565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526007838501528351808403850181526060909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e49061047e565b60008073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461123f576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301528416906370a0823190602401602060405180830381865afa158015611216573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123a91906132cb565b611278565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16315b9050600061128584610b45565b905080600003611299575060009392505050565b6112ac6112a5856110e2565b8284612235565b949350505050565b611313604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61131b61246e565b611324836108dc565b905060006113328585611b98565b90508015611662576001808216811484526113629082901c67ffffffffffffffff16600860ff9082901c91161b90565b6020840181905261137490829061229e565b60408401526401ffffffff608182901c166060840152613fff60a282901c16608084015262ffffff60b082901c1660a08401526103ff60d082901c1660ff60c883901c161b60c08401526103ff60e282901c1660ff60da83901c161b60e08401528251156114815764e8d4a510008260e0015184602001516113f6919061337a565b61140091906133c0565b602084015260e0820151604084015164e8d4a510009161141f9161337a565b61142991906133c0565b604084015260e082015160c084015164e8d4a51000916114489161337a565b61145291906133c0565b60c084015260e0808301519084015164e8d4a51000916114719161337a565b61147b91906133c0565b60e08401525b612710826101800151836101e0015161149a919061337a565b6114a491906133c0565b61014084018190526101a0830151600091116114c15760006114d7565b826101a001518461014001516114d791906133fb565b9050600084602001518560400151116114f1576000611505565b8460200151856040015161150591906133fb565b90508181116115145780611516565b815b610100860152600073ffffffffffffffffffffffffffffffffffffffff871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611604576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301528816906370a0823190602401602060405180830381865afa1580156115db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ff91906132cb565b61163d565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16315b905085610100015181116116515780611658565b8561010001515b6101208701525050505b509250929050565b6060808080868067ffffffffffffffff81111561168957611689613002565b60405190808252806020026020018201604052801561170b57816020015b6116f860405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816116a75790505b5094508067ffffffffffffffff81111561172757611727613002565b60405190808252806020026020018201604052801561176057816020015b61174d61246e565b8152602001906001900390816117455790505b50935060005b818110156117d1576117848b8b8b848181106105fb576105fb6132e4565b878381518110611796576117966132e4565b602002602001018784815181106117af576117af6132e4565b60200260200101829052829052505080806117c990613342565b915050611766565b508590508067ffffffffffffffff8111156117ee576117ee613002565b60405190808252806020026020018201604052801561187e57816020015b61186b604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020019060019003908161180c5790505b5092508067ffffffffffffffff81111561189a5761189a613002565b6040519080825280602002602001820160405280156118d357816020015b6118c061246e565b8152602001906001900390816118b85790505b50915060005b818110156119595761190c8b8989848181106118f7576118f76132e4565b905060200201602081019061035d91906125d5565b85838151811061191e5761191e6132e4565b60200260200101858481518110611937576119376132e4565b602002602001018290528290525050808061195190613342565b9150506118d9565b505095509550955095915050565b606080828067ffffffffffffffff81111561198457611984613002565b604051908082528060200260200182016040528015611a1457816020015b611a01604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816119a25790505b5092508067ffffffffffffffff811115611a3057611a30613002565b604051908082528060200260200182016040528015611a6957816020015b611a5661246e565b815260200190600190039081611a4e5790505b50915060005b8181101561065d57611a8d878787848181106118f7576118f76132e4565b858381518110611a9f57611a9f6132e4565b60200260200101858481518110611ab857611ab86132e4565b6020026020010182905282905250508080611ad290613342565b915050611a6f565b80516060908067ffffffffffffffff811115611af857611af8613002565b604051908082528060200260200182016040528015611b3157816020015b611b1e61246e565b815260200190600190039081611b165790505b50915060005b81811015611b9157611b61848281518110611b5457611b546132e4565b60200260200101516108dc565b838281518110611b7357611b736132e4565b60200260200101819052508080611b8990613342565b915050611b37565b5050919050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602080840191909152600983850152835180840385018152606084018552805190820120858316608085015260a0808501919091528451808503909101815260c0909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e4905b6040518263ffffffff1660e01b8152600401611c4d91815260200190565b602060405180830381865afa158015611c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8e91906132cb565b9392505050565b611ce660405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b611cee61246e565b611cf7836108dc565b90506000611d058585611f8c565b9050801561166257600180821681148452611d359082901c67ffffffffffffffff16600860ff9082901c91161b90565b60208401819052611d47908290612359565b60408401526401ffffffff608182901c166060840152613fff60a282901c16608084015262ffffff60b082901c1660a08401526103ff60d082901c1660ff60c883901c161b60c0840152825115611e145764e8d4a510008260c001518460200151611db2919061337a565b611dbc91906133c0565b602084015260c0820151604084015164e8d4a5100091611ddb9161337a565b611de591906133c0565b604084015260c0808301519084015164e8d4a5100091611e049161337a565b611e0e91906133c0565b60c08401525b8260400151836020015111611e2a576000611e3e565b82604001518360200151611e3e91906133fb565b60e0840152600073ffffffffffffffffffffffffffffffffffffffff851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611f2b576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301528616906370a0823190602401602060405180830381865afa158015611f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2691906132cb565b611f64565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16315b90508360e001518111611f775780611f7d565b8360e001515b61010085015250509250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602080840191909152600883850152835180840385018152606084018552805190820120858316608085015260a0808501919091528451808503909101815260c0909301909352815191909201206000917f0000000000000000000000000000000000000000000000000000000000000000169063b5c736e490611c2f565b67ffffffffffffffff605b82901c811690609b83901c16811580612049575080155b15612085576040517fd50d75120000000000000000000000000000000000000000000000000000000081526201117160048201526024016107e5565b61ffff8316603a84901c6401ffffffff16428181039160ea87901c617fff169114806120af575082155b806120ba5750806001145b156120c757505050915091565b64496cebb80084840283020484019350617fff60db87901c169250826001036120f257505050915091565b826001166001036121475760019290921c91826c7e37be2022c0914b26800000008161212057612120613391565b049250612710601e87901c613fff166b033b2e3c9fd0803ce8000000850102049250612174565b60019290921c916305f5e100601e87901c613fff166127108501026b033b2e3c9fd0803ce8000000020492505b806001166001036121ab5760011c61271081016b033b2e3c9fd0803ce80000008202816121a3576121a3613391565b0490506121e1565b60011c61271081016b033b2e3c9fd0803ce80000008202816121cf576121cf613391565b046b033b2e3c9fd0803ce80000000390505b760a70c3c40a64e6c51999090b65f67d92400000000000008382026127100261ffff881691900402601087901c613fff16612710030292506801b5a660ea44b8000085840283020485019450505050915091565b600080600061224385612027565b91509150600061225387846123e9565b90508015612290576122658783612434565b61226f908661340e565b935080841161227f576000612289565b61228981856133fb565b9350612294565b8493505b5050509392505050565b60d082901c6103ff1660c883901c60ff161b613fff60a284901c1661271083820204808401838110156122d3575050506104dd565b608186901c6401ffffffff164203925066ffffffffffffff604987901c1660ff604188901c161b60b087901c62ffffff1661230e858561337a565b61231891906133c0565b612322919061340e565b935080841115612330578093505b6103ff60e287901c1660ff60da88901c161b925082841115612350578293505b50505092915050565b600066ffffffffffffff604984901c1660ff604185901c161b8082036123835760009150506104dd565b612710613fff60a286901c168402046401ffffffff608186901c16420362ffffff60b087901c166123b4828461337a565b6123be91906133c0565b90508083116123ce5760006123d2565b8083035b935050808403838111156123505795945050505050565b66ffffffffffffff604883901c811660ff604085901c81169190911b91600885901c169084161b64e8d4a51000612420848361337a565b61242a91906133c0565b6112ac908361340e565b60c882901c60ff60c084901c81169190911b9066ffffffffffffff608885901c16608085901c9091161b64e8d4a51000612420848361337a565b604051806102200160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016124f26124f7565b905290565b6040518060600160405280600081526020016125516040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b81526020016124f26040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b803573ffffffffffffffffffffffffffffffffffffffff811681146125d057600080fd5b919050565b6000602082840312156125e757600080fd5b611c8e826125ac565b60008083601f84011261260257600080fd5b50813567ffffffffffffffff81111561261a57600080fd5b6020830191508360208260051b850101111561263557600080fd5b9250929050565b60008060006040848603121561265157600080fd5b61265a846125ac565b9250602084013567ffffffffffffffff81111561267657600080fd5b612682868287016125f0565b9497909650939450505050565b600081518084526020808501945080840160005b838110156127215761270d8783518051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b6101209690960195908201906001016126a3565b509495945050505050565b600081518084526020808501945080840160005b8381101561272157612896878351805182526020808201518184015260408083015181850152606080840151818601526080808501518187015260a0808601518188015260c0808701518189015260e08088015190890152610100808801519089015261012080880151908901526101408088015190890152610160808801519089015261018080880151908901526101a080880151908901526101c080880151908901526101e080880151908901526102009687015180519789019790975286860151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818801516102408b0152818701516102608b0152818601516102808b0152908401516102a08a01529685015180519097166102c0890152948601516102e08801529285015161030087015290840151610320860152830151610340850152820151610360840152015161038090910152565b6103a0969096019590820190600101612740565b6040815260006128bd604083018561268f565b82810360208401526128cf818561272c565b95945050505050565b6101a081016104dd828480518252602081015173ffffffffffffffffffffffffffffffffffffffff808251166020850152602082015160408501526040820151606085015260608201516080850152608082015160a0850152604083015191508082511660c085015250602081015160e084015260408101516101008401526060810151610120840152608081015161014084015260a081015161016084015260c0810151610180840152505050565b815181526020808301518183015260408084015181840152606080850151818501526080808601518186015260a0808701518187015260c0808801518188015260e08089015190880152610100808901519088015261012080890151908801526101408089015190880152610160808901519088015261018080890151908801526101a080890151908801526101c080890151908801526101e080890151908801526102008089015180519189019190915280870151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818901516102408b0152818801516102608b0152818701516102808b0152908501516102a08a01529086015180519091166102c0890152958601516102e0880152938501516103008701529184015161032086015283015161034085015282015161036084015201516103808201526103a081016104dd565b60008060208385031215612aea57600080fd5b823567ffffffffffffffff811115612b0157600080fd5b612b0d858286016125f0565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015612bfd57612be983855180518252602081015173ffffffffffffffffffffffffffffffffffffffff808251166020850152602082015160408501526040820151606085015260608201516080850152608082015160a0850152604083015191508082511660c085015250602081015160e084015260408101516101008401526060810151610120840152608081015161014084015260a081015161016084015260c0810151610180840152505050565b928401926101a09290920191600101612b35565b50909695505050505050565b602081526000611c8e602083018461272c565b6020808252825182820181905260009190848201906040850190845b81811015612bfd57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612c38565b60008060408385031215612c7d57600080fd5b612c86836125ac565b9150612c94602084016125ac565b90509250929050565b6105008101612d1b82858051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152506101208082015181840152506101408082015181840152505050565b611c8e610160830184805182526020808201518184015260408083015181850152606080840151818601526080808501518187015260a0808601518188015260c0808701518189015260e08088015190890152610100808801519089015261012080880151908901526101408088015190890152610160808801519089015261018080880151908901526101a080880151908901526101c080880151908901526101e080880151908901526102009687015180519789019790975286860151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818801516102408b0152818701516102608b0152818601516102808b0152908401516102a08a01529685015180519097166102c0890152948601516102e08801529285015161030087015290840151610320860152830151610340850152820151610360840152015161038090910152565b600080600080600060608688031215612e8457600080fd5b612e8d866125ac565b9450602086013567ffffffffffffffff80821115612eaa57600080fd5b612eb689838a016125f0565b90965094506040880135915080821115612ecf57600080fd5b50612edc888289016125f0565b969995985093965092949392505050565b600081518084526020808501945080840160005b8381101561272157612f838783518051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152506101208082015181840152506101408082015181840152505050565b610160969096019590820190600101612f01565b608081526000612faa608083018761268f565b8281036020840152612fbc818761272c565b90508281036040840152612fd08186612eed565b90508281036060840152612fe4818561272c565b979650505050505050565b6040815260006128bd6040830185612eed565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602080838503121561304457600080fd5b823567ffffffffffffffff8082111561305c57600080fd5b818501915085601f83011261307057600080fd5b81358181111561308257613082613002565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156130c5576130c5613002565b6040529182528482019250838101850191888311156130e357600080fd5b938501935b82851015613108576130f9856125ac565b845293850193928501926130e8565b98975050505050505050565b6104c0810161317a82858051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b611c8e610120830184805182526020808201518184015260408083015181850152606080840151818601526080808501518187015260a0808601518188015260c0808701518189015260e08088015190890152610100808801519089015261012080880151908901526101408088015190890152610160808801519089015261018080880151908901526101a080880151908901526101c080880151908901526101e080880151908901526102009687015180519789019790975286860151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818801516102408b0152818701516102608b0152818601516102808b0152908401516102a08a01529685015180519097166102c0890152948601516102e08801529285015161030087015290840151610320860152830151610340850152820151610360840152015161038090910152565b6000602082840312156132dd57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361337357613373613313565b5060010190565b80820281158282048414176104dd576104dd613313565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826133f6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156104dd576104dd613313565b808201808211156104dd576104dd61331356fea2646970667358221220ce08f70b83b7f25bce27d82ca99a8628f1f89bc6847415a352e4945fb7703f4c64736f6c6343000815003300000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101985760003560e01c80634e69d560116100e3578063b3fc48bc1161008c578063cdb5964411610066578063cdb59644146103c7578063e72ef91b146103da578063ee9e836d146103fb57600080fd5b8063b3fc48bc14610370578063b505b75014610393578063cd4a7e14146103b457600080fd5b80636e938406116100bd5780636e9384061461032957806385b670951461033c578063967915d61461034f57600080fd5b80634e69d560146102fb57806360fed05f14610303578063672694891461031657600080fd5b806329e04fbf1161014557806334a2e6591161011f57806334a2e659146102c957806336ebf76c146102d15780634a3d6bda146102e657600080fd5b806329e04fbf146102765780632b001833146102965780632b66fc05146102a957600080fd5b80631f735227116101765780631f735227146102045780632520e7ff146102175780632861c7d11461022a57600080fd5b80630c68ba211461019d57806314c0ac36146101c35780631dacf037146101e4575b600080fd5b6101b06101ab3660046125d5565b61040e565b6040519081526020015b60405180910390f35b6101d66101d136600461263c565b6104e3565b6040516101ba9291906128aa565b6101f76101f23660046125d5565b610667565b6040516101ba91906128d8565b6101b06102123660046125d5565b6107f4565b6101b06102253660046125d5565b610868565b6102517f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49781565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ba565b6102896102843660046125d5565b6108dc565b6040516101ba9190612988565b6101b06102a43660046125d5565b610b45565b6102bc6102b7366004612ad7565b610bb9565b6040516101ba9190612b19565b610251610c7e565b6102d9610d36565b6040516101ba9190612c09565b6102ee610d3f565b6040516101ba9190612c1c565b6101b0610f84565b6101b06103113660046125d5565b610ffa565b6101b06103243660046125d5565b61106e565b6101b06103373660046125d5565b6110e2565b6101b061034a3660046125d5565b611156565b61036261035d366004612c6a565b6112b4565b6040516101ba929190612c9d565b61038361037e366004612e6c565b61166a565b6040516101ba9493929190612f97565b6103a66103a136600461263c565b611967565b6040516101ba929190612fef565b6102d96103c2366004613031565b611ada565b6101b06103d5366004612c6a565b611b98565b6103ed6103e8366004612c6a565b611c95565b6040516101ba929190613114565b6101b0610409366004612c6a565b611f8c565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526003838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e4905b6040518263ffffffff1660e01b815260040161049c91815260200190565b602060405180830381865afa1580156104b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104dd91906132cb565b92915050565b606080828067ffffffffffffffff81111561050057610500613002565b60405190808252806020026020018201604052801561058257816020015b61056f60405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020019060019003908161051e5790505b5092508067ffffffffffffffff81111561059e5761059e613002565b6040519080825280602002602001820160405280156105d757816020015b6105c461246e565b8152602001906001900390816105bc5790505b50915060005b8181101561065d57610610878787848181106105fb576105fb6132e4565b90506020020160208101906103e891906125d5565b858381518110610622576106226132e4565b6020026020010185848151811061063b5761063b6132e4565b602002602001018290528290525050808061065590613342565b9150506105dd565b5050935093915050565b61066f6124f7565b600061067a83610ffa565b600f81168084529091506001036106f2576020828101805173ffffffffffffffffffffffffffffffffffffffff86169052805161ffff600485901c81166040909201919091528151601485901c82169301929092528051602484901c831660609091015251603483901c9091166080909101526107ee565b8151600203610780576040828101805173ffffffffffffffffffffffffffffffffffffffff86169052805161ffff600485901c81166060909201919091528151601485901c82166020909101528151602485901c82166080909101528151603485901c82169301929092528051604484901c831660a09091015251605483901c90911660c0909101526107ee565b8151156107ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6e6f742d76616c69642d726174652d76657273696f6e0000000000000000000060448201526064015b60405180910390fd5b50919050565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526004838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e49061047e565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526002838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e49061047e565b6108e461246e565b6108ed82610667565b61020082015260006108fe83610b45565b905080156107ee576000610911846110e2565b905061091c82612027565b60e085015260c084015261ffff82168352601082901c613fff9081166040850152601e83901c81166060850152602c83901c166080840152603a82901c6401ffffffff1660a08401526127106101e0840152600160f983901c8116900361099157613fff6109898561106e565b166101e08401525b66ffffffffffffff600882901c811660ff8084169190911b6101008601819052604884901c8316604085901c83161b610120870152608884901c909216608084901c82161b61014086015260c883901c60c084901c9182161b61016086015290600090819015610ab05764e8d4a5100067ffffffffffffffff605b87901c16876101000151610a20919061337a565b610a2a91906133c0565b915064e8d4a5100067ffffffffffffffff609b87901c16876101400151610a51919061337a565b610a5b91906133c0565b90508115610aa757610a6f6127108361337a565b818760400151612710610a8291906133fb565b8851610a8e919061337a565b610a98919061337a565b610aa291906133c0565b610aaa565b60005b60208701525b64e8d4a510008660c00151876101000151610acb919061337a565b610ad591906133c0565b915085610120015182610ae8919061340e565b61018087015260e086015161014087015164e8d4a5100091610b099161337a565b610b1391906133c0565b905085610160015181610b26919061340e565b6101a0870152610b3587611156565b6101c08701525050505050919050565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526005838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e49061047e565b6060818067ffffffffffffffff811115610bd557610bd5613002565b604051908082528060200260200182016040528015610c0e57816020015b610bfb6124f7565b815260200190600190039081610bf35790505b50915060005b81811015610c7657610c46858583818110610c3157610c316132e4565b90506020020160208101906101f291906125d5565b838281518110610c5857610c586132e4565b60200260200101819052508080610c6e90613342565b915050610c14565b505092915050565b6040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600060048201819052907f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff169063b5c736e4906024015b602060405180830381865afa158015610d0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3191906132cb565b905090565b6060610d316103c25b6040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600a60048201526060906000907f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401602060405180830381865afa158015610dd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df491906132cb565b90508067ffffffffffffffff811115610e0f57610e0f613002565b604051908082528060200260200182016040528015610e38578160200160208202803683370190505b5091506000600a604051602001610e5191815260200190565b6040516020818303038152906040528051906020012060001c905060005b82811015610f7e5773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e4971663b5c736e4610ebd838561340e565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526004810191909152602401602060405180830381865afa158015610f11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3591906132cb565b848281518110610f4757610f476132e4565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015280610f7681613342565b915050610e6f565b50505090565b6040517fb5c736e4000000000000000000000000000000000000000000000000000000008152600160048201526000907f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff169063b5c736e490602401610cf0565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526006838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e49061047e565b6040805173ffffffffffffffffffffffffffffffffffffffff838116602080840191909152600b838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e49061047e565b6040805173ffffffffffffffffffffffffffffffffffffffff8381166020808401919091526007838501528351808403850181526060909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e49061047e565b60008073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461123f576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497811660048301528416906370a0823190602401602060405180830381865afa158015611216573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123a91906132cb565b611278565b7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff16315b9050600061128584610b45565b905080600003611299575060009392505050565b6112ac6112a5856110e2565b8284612235565b949350505050565b611313604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b61131b61246e565b611324836108dc565b905060006113328585611b98565b90508015611662576001808216811484526113629082901c67ffffffffffffffff16600860ff9082901c91161b90565b6020840181905261137490829061229e565b60408401526401ffffffff608182901c166060840152613fff60a282901c16608084015262ffffff60b082901c1660a08401526103ff60d082901c1660ff60c883901c161b60c08401526103ff60e282901c1660ff60da83901c161b60e08401528251156114815764e8d4a510008260e0015184602001516113f6919061337a565b61140091906133c0565b602084015260e0820151604084015164e8d4a510009161141f9161337a565b61142991906133c0565b604084015260e082015160c084015164e8d4a51000916114489161337a565b61145291906133c0565b60c084015260e0808301519084015164e8d4a51000916114719161337a565b61147b91906133c0565b60e08401525b612710826101800151836101e0015161149a919061337a565b6114a491906133c0565b61014084018190526101a0830151600091116114c15760006114d7565b826101a001518461014001516114d791906133fb565b9050600084602001518560400151116114f1576000611505565b8460200151856040015161150591906133fb565b90508181116115145780611516565b815b610100860152600073ffffffffffffffffffffffffffffffffffffffff871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611604576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497811660048301528816906370a0823190602401602060405180830381865afa1580156115db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ff91906132cb565b61163d565b7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff16315b905085610100015181116116515780611658565b8561010001515b6101208701525050505b509250929050565b6060808080868067ffffffffffffffff81111561168957611689613002565b60405190808252806020026020018201604052801561170b57816020015b6116f860405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816116a75790505b5094508067ffffffffffffffff81111561172757611727613002565b60405190808252806020026020018201604052801561176057816020015b61174d61246e565b8152602001906001900390816117455790505b50935060005b818110156117d1576117848b8b8b848181106105fb576105fb6132e4565b878381518110611796576117966132e4565b602002602001018784815181106117af576117af6132e4565b60200260200101829052829052505080806117c990613342565b915050611766565b508590508067ffffffffffffffff8111156117ee576117ee613002565b60405190808252806020026020018201604052801561187e57816020015b61186b604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b81526020019060019003908161180c5790505b5092508067ffffffffffffffff81111561189a5761189a613002565b6040519080825280602002602001820160405280156118d357816020015b6118c061246e565b8152602001906001900390816118b85790505b50915060005b818110156119595761190c8b8989848181106118f7576118f76132e4565b905060200201602081019061035d91906125d5565b85838151811061191e5761191e6132e4565b60200260200101858481518110611937576119376132e4565b602002602001018290528290525050808061195190613342565b9150506118d9565b505095509550955095915050565b606080828067ffffffffffffffff81111561198457611984613002565b604051908082528060200260200182016040528015611a1457816020015b611a01604051806101600160405280600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816119a25790505b5092508067ffffffffffffffff811115611a3057611a30613002565b604051908082528060200260200182016040528015611a6957816020015b611a5661246e565b815260200190600190039081611a4e5790505b50915060005b8181101561065d57611a8d878787848181106118f7576118f76132e4565b858381518110611a9f57611a9f6132e4565b60200260200101858481518110611ab857611ab86132e4565b6020026020010182905282905250508080611ad290613342565b915050611a6f565b80516060908067ffffffffffffffff811115611af857611af8613002565b604051908082528060200260200182016040528015611b3157816020015b611b1e61246e565b815260200190600190039081611b165790505b50915060005b81811015611b9157611b61848281518110611b5457611b546132e4565b60200260200101516108dc565b838281518110611b7357611b736132e4565b60200260200101819052508080611b8990613342565b915050611b37565b5050919050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602080840191909152600983850152835180840385018152606084018552805190820120858316608085015260a0808501919091528451808503909101815260c0909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e4905b6040518263ffffffff1660e01b8152600401611c4d91815260200190565b602060405180830381865afa158015611c6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8e91906132cb565b9392505050565b611ce660405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b611cee61246e565b611cf7836108dc565b90506000611d058585611f8c565b9050801561166257600180821681148452611d359082901c67ffffffffffffffff16600860ff9082901c91161b90565b60208401819052611d47908290612359565b60408401526401ffffffff608182901c166060840152613fff60a282901c16608084015262ffffff60b082901c1660a08401526103ff60d082901c1660ff60c883901c161b60c0840152825115611e145764e8d4a510008260c001518460200151611db2919061337a565b611dbc91906133c0565b602084015260c0820151604084015164e8d4a5100091611ddb9161337a565b611de591906133c0565b604084015260c0808301519084015164e8d4a5100091611e049161337a565b611e0e91906133c0565b60c08401525b8260400151836020015111611e2a576000611e3e565b82604001518360200151611e3e91906133fb565b60e0840152600073ffffffffffffffffffffffffffffffffffffffff851673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611f2b576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497811660048301528616906370a0823190602401602060405180830381865afa158015611f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f2691906132cb565b611f64565b7f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e49773ffffffffffffffffffffffffffffffffffffffff16315b90508360e001518111611f775780611f7d565b8360e001515b61010085015250509250929050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602080840191909152600883850152835180840385018152606084018552805190820120858316608085015260a0808501919091528451808503909101815260c0909301909352815191909201206000917f00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497169063b5c736e490611c2f565b67ffffffffffffffff605b82901c811690609b83901c16811580612049575080155b15612085576040517fd50d75120000000000000000000000000000000000000000000000000000000081526201117160048201526024016107e5565b61ffff8316603a84901c6401ffffffff16428181039160ea87901c617fff169114806120af575082155b806120ba5750806001145b156120c757505050915091565b64496cebb80084840283020484019350617fff60db87901c169250826001036120f257505050915091565b826001166001036121475760019290921c91826c7e37be2022c0914b26800000008161212057612120613391565b049250612710601e87901c613fff166b033b2e3c9fd0803ce8000000850102049250612174565b60019290921c916305f5e100601e87901c613fff166127108501026b033b2e3c9fd0803ce8000000020492505b806001166001036121ab5760011c61271081016b033b2e3c9fd0803ce80000008202816121a3576121a3613391565b0490506121e1565b60011c61271081016b033b2e3c9fd0803ce80000008202816121cf576121cf613391565b046b033b2e3c9fd0803ce80000000390505b760a70c3c40a64e6c51999090b65f67d92400000000000008382026127100261ffff881691900402601087901c613fff16612710030292506801b5a660ea44b8000085840283020485019450505050915091565b600080600061224385612027565b91509150600061225387846123e9565b90508015612290576122658783612434565b61226f908661340e565b935080841161227f576000612289565b61228981856133fb565b9350612294565b8493505b5050509392505050565b60d082901c6103ff1660c883901c60ff161b613fff60a284901c1661271083820204808401838110156122d3575050506104dd565b608186901c6401ffffffff164203925066ffffffffffffff604987901c1660ff604188901c161b60b087901c62ffffff1661230e858561337a565b61231891906133c0565b612322919061340e565b935080841115612330578093505b6103ff60e287901c1660ff60da88901c161b925082841115612350578293505b50505092915050565b600066ffffffffffffff604984901c1660ff604185901c161b8082036123835760009150506104dd565b612710613fff60a286901c168402046401ffffffff608186901c16420362ffffff60b087901c166123b4828461337a565b6123be91906133c0565b90508083116123ce5760006123d2565b8083035b935050808403838111156123505795945050505050565b66ffffffffffffff604883901c811660ff604085901c81169190911b91600885901c169084161b64e8d4a51000612420848361337a565b61242a91906133c0565b6112ac908361340e565b60c882901c60ff60c084901c81169190911b9066ffffffffffffff608885901c16608085901c9091161b64e8d4a51000612420848361337a565b604051806102200160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016124f26124f7565b905290565b6040518060600160405280600081526020016125516040518060a00160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081526020016000815260200160008152602001600081525090565b81526020016124f26040518060e00160405280600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b803573ffffffffffffffffffffffffffffffffffffffff811681146125d057600080fd5b919050565b6000602082840312156125e757600080fd5b611c8e826125ac565b60008083601f84011261260257600080fd5b50813567ffffffffffffffff81111561261a57600080fd5b6020830191508360208260051b850101111561263557600080fd5b9250929050565b60008060006040848603121561265157600080fd5b61265a846125ac565b9250602084013567ffffffffffffffff81111561267657600080fd5b612682868287016125f0565b9497909650939450505050565b600081518084526020808501945080840160005b838110156127215761270d8783518051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b6101209690960195908201906001016126a3565b509495945050505050565b600081518084526020808501945080840160005b8381101561272157612896878351805182526020808201518184015260408083015181850152606080840151818601526080808501518187015260a0808601518188015260c0808701518189015260e08088015190890152610100808801519089015261012080880151908901526101408088015190890152610160808801519089015261018080880151908901526101a080880151908901526101c080880151908901526101e080880151908901526102009687015180519789019790975286860151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818801516102408b0152818701516102608b0152818601516102808b0152908401516102a08a01529685015180519097166102c0890152948601516102e08801529285015161030087015290840151610320860152830151610340850152820151610360840152015161038090910152565b6103a0969096019590820190600101612740565b6040815260006128bd604083018561268f565b82810360208401526128cf818561272c565b95945050505050565b6101a081016104dd828480518252602081015173ffffffffffffffffffffffffffffffffffffffff808251166020850152602082015160408501526040820151606085015260608201516080850152608082015160a0850152604083015191508082511660c085015250602081015160e084015260408101516101008401526060810151610120840152608081015161014084015260a081015161016084015260c0810151610180840152505050565b815181526020808301518183015260408084015181840152606080850151818501526080808601518186015260a0808701518187015260c0808801518188015260e08089015190880152610100808901519088015261012080890151908801526101408089015190880152610160808901519088015261018080890151908801526101a080890151908801526101c080890151908801526101e080890151908801526102008089015180519189019190915280870151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818901516102408b0152818801516102608b0152818701516102808b0152908501516102a08a01529086015180519091166102c0890152958601516102e0880152938501516103008701529184015161032086015283015161034085015282015161036084015201516103808201526103a081016104dd565b60008060208385031215612aea57600080fd5b823567ffffffffffffffff811115612b0157600080fd5b612b0d858286016125f0565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015612bfd57612be983855180518252602081015173ffffffffffffffffffffffffffffffffffffffff808251166020850152602082015160408501526040820151606085015260608201516080850152608082015160a0850152604083015191508082511660c085015250602081015160e084015260408101516101008401526060810151610120840152608081015161014084015260a081015161016084015260c0810151610180840152505050565b928401926101a09290920191600101612b35565b50909695505050505050565b602081526000611c8e602083018461272c565b6020808252825182820181905260009190848201906040850190845b81811015612bfd57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612c38565b60008060408385031215612c7d57600080fd5b612c86836125ac565b9150612c94602084016125ac565b90509250929050565b6105008101612d1b82858051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152506101208082015181840152506101408082015181840152505050565b611c8e610160830184805182526020808201518184015260408083015181850152606080840151818601526080808501518187015260a0808601518188015260c0808701518189015260e08088015190890152610100808801519089015261012080880151908901526101408088015190890152610160808801519089015261018080880151908901526101a080880151908901526101c080880151908901526101e080880151908901526102009687015180519789019790975286860151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818801516102408b0152818701516102608b0152818601516102808b0152908401516102a08a01529685015180519097166102c0890152948601516102e08801529285015161030087015290840151610320860152830151610340850152820151610360840152015161038090910152565b600080600080600060608688031215612e8457600080fd5b612e8d866125ac565b9450602086013567ffffffffffffffff80821115612eaa57600080fd5b612eb689838a016125f0565b90965094506040880135915080821115612ecf57600080fd5b50612edc888289016125f0565b969995985093965092949392505050565b600081518084526020808501945080840160005b8381101561272157612f838783518051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152506101208082015181840152506101408082015181840152505050565b610160969096019590820190600101612f01565b608081526000612faa608083018761268f565b8281036020840152612fbc818761272c565b90508281036040840152612fd08186612eed565b90508281036060840152612fe4818561272c565b979650505050505050565b6040815260006128bd6040830185612eed565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602080838503121561304457600080fd5b823567ffffffffffffffff8082111561305c57600080fd5b818501915085601f83011261307057600080fd5b81358181111561308257613082613002565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156130c5576130c5613002565b6040529182528482019250838101850191888311156130e357600080fd5b938501935b82851015613108576130f9856125ac565b845293850193928501926130e8565b98975050505050505050565b6104c0810161317a82858051151582526020810151602083015260408101516040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b611c8e610120830184805182526020808201518184015260408083015181850152606080840151818601526080808501518187015260a0808601518188015260c0808701518189015260e08088015190890152610100808801519089015261012080880151908901526101408088015190890152610160808801519089015261018080880151908901526101a080880151908901526101c080880151908901526101e080880151908901526102009687015180519789019790975286860151805173ffffffffffffffffffffffffffffffffffffffff9081166102208b0152818801516102408b0152818701516102608b0152818601516102808b0152908401516102a08a01529685015180519097166102c0890152948601516102e08801529285015161030087015290840151610320860152830151610340850152820151610360840152015161038090910152565b6000602082840312156132dd57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361337357613373613313565b5060010190565b80820281158282048414176104dd576104dd613313565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826133f6577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156104dd576104dd613313565b808201808211156104dd576104dd61331356fea2646970667358221220ce08f70b83b7f25bce27d82ca99a8628f1f89bc6847415a352e4945fb7703f4c64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497
-----Decoded View---------------
Arg [0] : liquidity_ (address): 0x52Aa899454998Be5b000Ad077a46Bbe360F4e497
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000052aa899454998be5b000ad077a46bbe360f4e497
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.