mirror of
https://github.com/Instadapp/fluid-contracts-public.git
synced 2024-07-29 21:57:37 +00:00
d7a58e88ff
ARB: deploy protocols
111 lines
156 KiB
JSON
111 lines
156 KiB
JSON
{
|
|
"language": "Solidity",
|
|
"sources": {
|
|
"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol": {
|
|
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Enumerable is IERC721 {\n /**\n * @dev Returns the total amount of tokens stored by the contract.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns a token ID owned by `owner` at a given `index` of its token list.\n * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.\n */\n function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);\n\n /**\n * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.\n * Use along with {totalSupply} to enumerate all tokens.\n */\n function tokenByIndex(uint256 index) external view returns (uint256);\n}\n"
|
|
},
|
|
"@openzeppelin/contracts/token/ERC721/IERC721.sol": {
|
|
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n * understand this adds an external call which potentially creates a reentrancy vulnerability.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
|
|
},
|
|
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
|
|
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
|
|
},
|
|
"contracts/libraries/bigMathMinified.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that represents a number in BigNumber(coefficient and exponent) format to store in smaller bits.\n/// @notice the number is divided into two parts: a coefficient and an exponent. This comes at a cost of losing some precision\n/// at the end of the number because the exponent simply fills it with zeroes. This precision is oftentimes negligible and can\n/// result in significant gas cost reduction due to storage space reduction.\n/// 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.\n/// @dev roundUp is more like a increase 1, which happens everytime for the same number.\n/// roundDown simply sets trailing digits after coefficientSize to zero (floor), only once for the same number.\nlibrary BigMathMinified {\n /// @dev constants to use for `roundUp` input param to increase readability\n bool internal constant ROUND_DOWN = false;\n bool internal constant ROUND_UP = true;\n\n /// @dev converts `normal` number to BigNumber with `exponent` and `coefficient` (or precision).\n /// e.g.:\n /// 5035703444687813576399599 (normal) = (coefficient[32bits], exponent[8bits])[40bits]\n /// 5035703444687813576399599 (decimal) => 10000101010010110100000011111011110010100110100000000011100101001101001101011101111 (binary)\n /// => 10000101010010110100000011111011000000000000000000000000000000000000000000000000000\n /// ^-------------------- 51(exponent) -------------- ^\n /// coefficient = 1000,0101,0100,1011,0100,0000,1111,1011 (2236301563)\n /// exponent = 0011,0011 (51)\n /// bigNumber = 1000,0101,0100,1011,0100,0000,1111,1011,0011,0011 (572493200179)\n ///\n /// @param normal number which needs to be converted into Big Number\n /// @param coefficientSize at max how many bits of precision there should be (64 = uint64 (64 bits precision))\n /// @param exponentSize at max how many bits of exponent there should be (8 = uint8 (8 bits exponent))\n /// @param roundUp signals if result should be rounded down or up\n /// @return bigNumber converted bigNumber (coefficient << exponent)\n function toBigNumber(\n uint256 normal,\n uint256 coefficientSize,\n uint256 exponentSize,\n bool roundUp\n ) internal pure returns (uint256 bigNumber) {\n assembly {\n let lastBit_\n let number_ := normal\n if gt(number_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit_ := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit_ := add(lastBit_, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit_ := add(lastBit_, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit_ := add(lastBit_, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit_ := add(lastBit_, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit_ := add(lastBit_, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit_ := add(lastBit_, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit_ := add(lastBit_, 1)\n }\n if gt(number_, 0) {\n lastBit_ := add(lastBit_, 1)\n }\n if lt(lastBit_, coefficientSize) {\n // for throw exception\n lastBit_ := coefficientSize\n }\n let exponent := sub(lastBit_, coefficientSize)\n let coefficient := shr(exponent, normal)\n if and(roundUp, gt(exponent, 0)) {\n // rounding up is only needed if exponent is > 0, as otherwise the coefficient fully holds the original number\n coefficient := add(coefficient, 1)\n if eq(shl(coefficientSize, 1), coefficient) {\n // case were coefficient was e.g. 111, with adding 1 it became 1000 (in binary) and coefficientSize 3 bits\n // final coefficient would exceed it's size. -> reduce coefficent to 100 and increase exponent by 1.\n coefficient := shl(sub(coefficientSize, 1), 1)\n exponent := add(exponent, 1)\n }\n }\n if iszero(lt(exponent, shl(exponentSize, 1))) {\n // if exponent is >= exponentSize, the normal number is too big to fit within\n // BigNumber with too small sizes for coefficient and exponent\n revert(0, 0)\n }\n bigNumber := shl(exponentSize, coefficient)\n bigNumber := add(bigNumber, exponent)\n }\n }\n\n /// @dev get `normal` number from `bigNumber`, `exponentSize` and `exponentMask`\n function fromBigNumber(\n uint256 bigNumber,\n uint256 exponentSize,\n uint256 exponentMask\n ) internal pure returns (uint256 normal) {\n assembly {\n let coefficient := shr(exponentSize, bigNumber)\n let exponent := and(bigNumber, exponentMask)\n normal := shl(exponent, coefficient)\n }\n }\n\n /// @dev gets the most significant bit `lastBit` of a `normal` number (length of given number of binary format).\n /// e.g.\n /// 5035703444687813576399599 = 10000101010010110100000011111011110010100110100000000011100101001101001101011101111\n /// lastBit = ^--------------------------------- 83 ----------------------------------------^\n function mostSignificantBit(uint256 normal) internal pure returns (uint lastBit) {\n assembly {\n let number_ := normal\n if gt(normal, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {\n number_ := shr(0x80, number_)\n lastBit := 0x80\n }\n if gt(number_, 0xFFFFFFFFFFFFFFFF) {\n number_ := shr(0x40, number_)\n lastBit := add(lastBit, 0x40)\n }\n if gt(number_, 0xFFFFFFFF) {\n number_ := shr(0x20, number_)\n lastBit := add(lastBit, 0x20)\n }\n if gt(number_, 0xFFFF) {\n number_ := shr(0x10, number_)\n lastBit := add(lastBit, 0x10)\n }\n if gt(number_, 0xFF) {\n number_ := shr(0x8, number_)\n lastBit := add(lastBit, 0x8)\n }\n if gt(number_, 0xF) {\n number_ := shr(0x4, number_)\n lastBit := add(lastBit, 0x4)\n }\n if gt(number_, 0x3) {\n number_ := shr(0x2, number_)\n lastBit := add(lastBit, 0x2)\n }\n if gt(number_, 0x1) {\n lastBit := add(lastBit, 1)\n }\n if gt(number_, 0) {\n lastBit := add(lastBit, 1)\n }\n }\n }\n}\n"
|
|
},
|
|
"contracts/libraries/errorTypes.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary LibsErrorTypes {\n /***********************************|\n | LiquidityCalcs | \n |__________________________________*/\n\n /// @notice thrown when supply or borrow exchange price is zero at calc token data (token not configured yet)\n uint256 internal constant LiquidityCalcs__ExchangePriceZero = 70001;\n\n /// @notice thrown when rate data is set to a version that is not implemented\n uint256 internal constant LiquidityCalcs__UnsupportedRateVersion = 70002;\n\n /***********************************|\n | SafeTransfer | \n |__________________________________*/\n\n /// @notice thrown when safe transfer from for an ERC20 fails\n uint256 internal constant SafeTransfer__TransferFromFailed = 71001;\n\n /// @notice thrown when safe transfer for an ERC20 fails\n uint256 internal constant SafeTransfer__TransferFailed = 71002;\n}\n"
|
|
},
|
|
"contracts/libraries/liquidityCalcs.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { LibsErrorTypes as ErrorTypes } from \"./errorTypes.sol\";\nimport { LiquiditySlotsLink } from \"./liquiditySlotsLink.sol\";\nimport { BigMathMinified } from \"./bigMathMinified.sol\";\n\n/// @notice implements calculation methods used for Fluid liquidity such as updated exchange prices,\n/// borrow rate, withdrawal / borrow limits, revenue amount.\nlibrary LiquidityCalcs {\n error FluidLiquidityCalcsError(uint256 errorId_);\n\n /// @notice emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535\n event BorrowRateMaxCap();\n\n /// @dev constants as from Liquidity variables.sol\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\n\n /// @dev Ignoring leap years\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\n // constants used for BigMath conversion from and to storage\n uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\n uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;\n\n uint256 internal constant FOUR_DECIMALS = 1e4;\n uint256 internal constant TWELVE_DECIMALS = 1e12;\n uint256 internal constant X14 = 0x3fff;\n uint256 internal constant X15 = 0x7fff;\n uint256 internal constant X16 = 0xffff;\n uint256 internal constant X18 = 0x3ffff;\n uint256 internal constant X24 = 0xffffff;\n uint256 internal constant X33 = 0x1ffffffff;\n uint256 internal constant X64 = 0xffffffffffffffff;\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC EXCHANGE PRICES /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev calculates interest (exchange prices) for a token given its' exchangePricesAndConfig from storage.\n /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n /// @return supplyExchangePrice_ updated supplyExchangePrice\n /// @return borrowExchangePrice_ updated borrowExchangePrice\n function calcExchangePrices(\n uint256 exchangePricesAndConfig_\n ) internal view returns (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) {\n // Extracting exchange prices\n supplyExchangePrice_ =\n (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) &\n X64;\n borrowExchangePrice_ =\n (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) &\n X64;\n\n if (supplyExchangePrice_ == 0 || borrowExchangePrice_ == 0) {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__ExchangePriceZero);\n }\n\n uint256 temp_ = exchangePricesAndConfig_ & X16; // temp_ = borrowRate\n\n unchecked {\n // last timestamp can not be > current timestamp\n uint256 secondsSinceLastUpdate_ = block.timestamp -\n ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33);\n\n uint256 borrowRatio_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &\n X15;\n if (secondsSinceLastUpdate_ == 0 || temp_ == 0 || borrowRatio_ == 1) {\n // if no time passed, borrow rate is 0, or no raw borrowings: no exchange price update needed\n // (if borrowRatio_ == 1 means there is only borrowInterestFree, as first bit is 1 and rest is 0)\n return (supplyExchangePrice_, borrowExchangePrice_);\n }\n\n // calculate new borrow exchange price.\n // formula borrowExchangePriceIncrease: previous price * borrow rate * secondsSinceLastUpdate_.\n // nominator is max uint112 (uint64 * uint16 * uint32). Divisor can not be 0.\n borrowExchangePrice_ +=\n (borrowExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n (SECONDS_PER_YEAR * FOUR_DECIMALS);\n\n // FOR SUPPLY EXCHANGE PRICE:\n // all yield paid by borrowers (in mode with interest) goes to suppliers in mode with interest.\n // formula: previous price * supply rate * secondsSinceLastUpdate_.\n // where supply rate = (borrow rate - revenueFee%) * ratioSupplyYield. And\n // ratioSupplyYield = utilization * supplyRatio * borrowRatio\n //\n // Example:\n // supplyRawInterest is 80, supplyInterestFree is 20. totalSupply is 100. BorrowedRawInterest is 50.\n // BorrowInterestFree is 10. TotalBorrow is 60. borrow rate 40%, revenueFee 10%.\n // yield is 10 (so half a year must have passed).\n // supplyRawInterest must become worth 89. totalSupply must become 109. BorrowedRawInterest must become 60.\n // borrowInterestFree must still be 10. supplyInterestFree still 20. totalBorrow 70.\n // supplyExchangePrice would have to go from 1 to 1,125 (+ 0.125). borrowExchangePrice from 1 to 1,2 (+0.2).\n // utilization is 60%. supplyRatio = 20 / 80 = 25% (only 80% of lenders receiving yield).\n // borrowRatio = 10 / 50 = 20% (only 83,333% of borrowers paying yield):\n // x of borrowers paying yield = 100% - (20 / (100 + 20)) = 100% - 16.6666666% = 83,333%.\n // ratioSupplyYield = 60% * 83,33333% * (100% + 20%) = 62,5%\n // supplyRate = (40% * (100% - 10%)) * = 36% * 62,5% = 22.5%\n // increase in supplyExchangePrice, assuming 100 as previous price.\n // 100 * 22,5% * 1/2 (half a year) = 0,1125.\n // cross-check supplyRawInterest worth = 80 * 1.1125 = 89. totalSupply worth = 89 + 20.\n\n // -------------- 1. calculate ratioSupplyYield --------------------------------\n // step1: utilization * supplyRatio (or actually part of lenders receiving yield)\n\n // temp_ => supplyRatio (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\n // if first bit 0 then ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n // else ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n temp_ = (exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) & X15;\n\n if (temp_ == 1) {\n // if no raw supply: no exchange price update needed\n // (if supplyRatio_ == 1 means there is only supplyInterestFree, as first bit is 1 and rest is 0)\n return (supplyExchangePrice_, borrowExchangePrice_);\n }\n\n // ratioSupplyYield precision is 1e27 as 100% for increased precision when supplyInterestFree > supplyWithInterest\n if (temp_ & 1 == 1) {\n // ratio is supplyWithInterest / supplyInterestFree (supplyInterestFree is bigger)\n temp_ = temp_ >> 1;\n\n // Note: case where temp_ == 0 (only supplyInterestFree, no yield) already covered by early return\n // in the if statement a little above.\n\n // based on above example but supplyRawInterest is 20, supplyInterestFree is 80. no fee.\n // supplyRawInterest must become worth 30. totalSupply must become 110.\n // supplyExchangePrice would have to go from 1 to 1,5. borrowExchangePrice from 1 to 1,2.\n // so ratioSupplyYield must come out as 2.5 (250%).\n // supplyRatio would be (20 * 10_000 / 80) = 2500. but must be inverted.\n temp_ = (1e27 * FOUR_DECIMALS) / temp_; // e.g. 1e31 / 2500 = 4e27. (* 1e27 for precision)\n // e.g. 5_000 * (1e27 + 4e27) / 1e27 = 25_000 (=250%).\n temp_ =\n // utilization * (100% + 100% / supplyRatio)\n (((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) *\n (1e27 + temp_)) / // extract utilization (max 16_383 so there is no way this can overflow).\n (FOUR_DECIMALS);\n // max possible value of temp_ here is 16383 * (1e27 + 1e31) / 1e4 = ~1.64e31\n } else {\n // ratio is supplyInterestFree / supplyWithInterest (supplyWithInterest is bigger)\n temp_ = temp_ >> 1;\n // if temp_ == 0 then only supplyWithInterest => full yield. temp_ is already 0\n\n // e.g. 5_000 * 10_000 + (20 * 10_000 / 80) / 10_000 = 5000 * 12500 / 10000 = 6250 (=62.5%).\n temp_ =\n // 1e27 * utilization * (100% + supplyRatio) / 100%\n (1e27 *\n ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14) * // extract utilization (max 16_383 so there is no way this can overflow).\n (FOUR_DECIMALS + temp_)) /\n (FOUR_DECIMALS * FOUR_DECIMALS);\n // max possible temp_ value: 1e27 * 16383 * 2e4 / 1e8 = 3.2766e27\n }\n // from here temp_ => ratioSupplyYield (utilization * supplyRatio part) scaled by 1e27. max possible value ~1.64e31\n\n // step2 of ratioSupplyYield: add borrowRatio (only x% of borrowers paying yield)\n if (borrowRatio_ & 1 == 1) {\n // ratio is borrowWithInterest / borrowInterestFree (borrowInterestFree is bigger)\n borrowRatio_ = borrowRatio_ >> 1;\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n\n // Note: case where borrowRatio_ == 0 (only borrowInterestFree, no yield) already covered\n // at the beginning of the method by early return if `borrowRatio_ == 1`.\n\n // based on above example but borrowRawInterest is 10, borrowInterestFree is 50. no fee. borrowRatio = 20%.\n // so only 16.66% of borrowers are paying yield. so the 100% - part of the formula is not needed.\n // x of borrowers paying yield = (borrowRatio / (100 + borrowRatio)) = 16.6666666%\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n borrowRatio_ = (borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_);\n // max value here for borrowRatio_ is (1e31 / (1e4 + 1e4))= 5e26 (= 50% of borrowers paying yield).\n } else {\n // ratio is borrowInterestFree / borrowWithInterest (borrowWithInterest is bigger)\n borrowRatio_ = borrowRatio_ >> 1;\n\n // borrowRatio_ => x of total bororwers paying yield. scale to 1e27.\n // x of borrowers paying yield = 100% - (borrowRatio / (100 + borrowRatio)) = 100% - 16.6666666% = 83,333%.\n borrowRatio_ = (1e27 - ((borrowRatio_ * 1e27) / (FOUR_DECIMALS + borrowRatio_)));\n // borrowRatio can never be > 100%. so max subtraction can be 100% - 100% / 200%.\n // or if borrowRatio_ is 0 -> 100% - 0. or if borrowRatio_ is 1 -> 100% - 1 / 101.\n // max value here for borrowRatio_ is 1e27 - 0 = 1e27 (= 100% of borrowers paying yield).\n }\n\n // temp_ => ratioSupplyYield. scaled down from 1e25 = 1% each to normal percent precision 1e2 = 1%.\n // max nominator value is ~1.64e31 * 1e27 = 1.64e58. max result = 1.64e8\n temp_ = (FOUR_DECIMALS * temp_ * borrowRatio_) / 1e54;\n\n // 2. calculate supply rate\n // temp_ => supply rate (borrow rate - revenueFee%) * ratioSupplyYield.\n // division part is done in next step to increase precision. (divided by 2x FOUR_DECIMALS, fee + borrowRate)\n // Note that all calculation divisions for supplyExchangePrice are rounded down.\n // Note supply rate can be bigger than the borrowRate, e.g. if there are only few lenders with interest\n // but more suppliers not earning interest.\n temp_ = ((exchangePricesAndConfig_ & X16) * // borrow rate\n temp_ * // ratioSupplyYield\n (FOUR_DECIMALS - ((exchangePricesAndConfig_ >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_FEE) & X14))); // revenueFee\n // fee can not be > 100%. max possible = 65535 * ~1.64e8 * 1e4 =~1.074774e17.\n\n // 3. calculate increase in supply exchange price\n supplyExchangePrice_ += ((supplyExchangePrice_ * temp_ * secondsSinceLastUpdate_) /\n (SECONDS_PER_YEAR * FOUR_DECIMALS * FOUR_DECIMALS * FOUR_DECIMALS));\n // max possible nominator = max uint 64 * 1.074774e17 * max uint32 = ~8.52e45. Denominator can not be 0.\n }\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC REVENUE /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev gets the `revenueAmount_` for a token given its' totalAmounts and exchangePricesAndConfig from storage\n /// and the current balance of the Fluid liquidity contract for the token.\n /// @param totalAmounts_ total amounts packed uint256 read from storage\n /// @param exchangePricesAndConfig_ exchange prices and config packed uint256 read from storage\n /// @param liquidityTokenBalance_ current balance of Liquidity contract (IERC20(token_).balanceOf(address(this)))\n /// @return revenueAmount_ collectable revenue amount\n function calcRevenue(\n uint256 totalAmounts_,\n uint256 exchangePricesAndConfig_,\n uint256 liquidityTokenBalance_\n ) internal view returns (uint256 revenueAmount_) {\n // @dev no need to super-optimize this method as it is only used by admin\n\n // calculate the new exchange prices based on earned interest\n (uint256 supplyExchangePrice_, uint256 borrowExchangePrice_) = calcExchangePrices(exchangePricesAndConfig_);\n\n // total supply = interest free + with interest converted from raw\n uint256 totalSupply_ = getTotalSupply(totalAmounts_, supplyExchangePrice_);\n\n if (totalSupply_ > 0) {\n // available revenue: balanceOf(token) + totalBorrowings - totalLendings.\n revenueAmount_ = liquidityTokenBalance_ + getTotalBorrow(totalAmounts_, borrowExchangePrice_);\n // ensure there is no possible case because of rounding etc. where this would revert,\n // explicitly check if >\n revenueAmount_ = revenueAmount_ > totalSupply_ ? revenueAmount_ - totalSupply_ : 0;\n // Note: if utilization > 100% (totalSupply < totalBorrow), then all the amount above 100% utilization\n // can only be revenue.\n } else {\n // if supply is 0, then rest of balance can be withdrawn as revenue so that no amounts get stuck\n revenueAmount_ = liquidityTokenBalance_;\n }\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC LIMITS /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev calculates withdrawal limit before an operate execution:\n /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n /// @param userSupplyData_ user supply data packed uint256 from storage\n /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and converted from BigMath\n /// @return currentWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction.\n /// returned value is in raw for with interest mode, normal amount for interest free mode!\n function calcWithdrawalLimitBeforeOperate(\n uint256 userSupplyData_,\n uint256 userSupply_\n ) internal view returns (uint256 currentWithdrawalLimit_) {\n // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet).\n // first tx where timestamp is 0 will enter `if (lastWithdrawalLimit_ == 0)` because lastWithdrawalLimit_ is not set yet.\n // returning max withdrawal allowed, which is not exactly right but doesn't matter because the first interaction must be\n // a deposit anyway. Important is that it would not revert.\n\n // Note the first time a deposit brings the user supply amount to above the base withdrawal limit, the active limit\n // is the fully expanded limit immediately.\n\n // extract last set withdrawal limit\n uint256 lastWithdrawalLimit_ = (userSupplyData_ >>\n LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) & X64;\n lastWithdrawalLimit_ =\n (lastWithdrawalLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n (lastWithdrawalLimit_ & DEFAULT_EXPONENT_MASK);\n if (lastWithdrawalLimit_ == 0) {\n // withdrawal limit is not activated. Max withdrawal allowed\n return 0;\n }\n\n uint256 maxWithdrawableLimit_;\n uint256 temp_;\n unchecked {\n // extract max withdrawable percent of user supply and\n // calculate maximum withdrawable amount expandPercentage of user supply at full expansion duration elapsed\n // e.g.: if 10% expandPercentage, meaning 10% is withdrawable after full expandDuration has elapsed.\n\n // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n maxWithdrawableLimit_ =\n (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14) * userSupply_) /\n FOUR_DECIMALS;\n\n // time elapsed since last withdrawal limit was set (in seconds)\n // @dev last process timestamp is guaranteed to exist for withdrawal, as a supply must have happened before.\n // last timestamp can not be > current timestamp\n temp_ =\n block.timestamp -\n ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP) & X33);\n }\n // calculate withdrawable amount of expandPercent that is elapsed of expandDuration.\n // e.g. if 60% of expandDuration has elapsed, then user should be able to withdraw 6% of user supply, down to 94%.\n // Note: no explicit check for this needed, it is covered by setting minWithdrawalLimit_ if needed.\n temp_ =\n (maxWithdrawableLimit_ * temp_) /\n // extract expand duration: After this, decrement won't happen (user can withdraw 100% of withdraw limit)\n ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_DURATION) & X24); // expand duration can never be 0\n // calculate expanded withdrawal limit: last withdrawal limit - withdrawable amount.\n // Note: withdrawable amount here can grow bigger than userSupply if timeElapsed is a lot bigger than expandDuration,\n // which would cause the subtraction `lastWithdrawalLimit_ - withdrawableAmount_` to revert. In that case, set 0\n // which will cause minimum (fully expanded) withdrawal limit to be set in lines below.\n unchecked {\n // underflow explicitly checked & handled\n currentWithdrawalLimit_ = lastWithdrawalLimit_ > temp_ ? lastWithdrawalLimit_ - temp_ : 0;\n // calculate minimum withdrawal limit: minimum amount of user supply that must stay supplied at full expansion.\n // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n temp_ = userSupply_ - maxWithdrawableLimit_;\n }\n // if withdrawal limit is decreased below minimum then set minimum\n // (e.g. when more than expandDuration time has elapsed)\n if (temp_ > currentWithdrawalLimit_) {\n currentWithdrawalLimit_ = temp_;\n }\n }\n\n /// @dev calculates withdrawal limit after an operate execution:\n /// amount of user supply that must stay supplied (not amount that can be withdrawn).\n /// i.e. if user has supplied 100m and can withdraw 5M, this method returns the 95M, not the withdrawable amount 5M\n /// @param userSupplyData_ user supply data packed uint256 from storage\n /// @param userSupply_ current user supply amount already extracted from `userSupplyData_` and added / subtracted with the executed operate amount\n /// @param newWithdrawalLimit_ current withdrawal limit updated for expansion since last interaction, result from `calcWithdrawalLimitBeforeOperate`\n /// @return withdrawalLimit_ updated withdrawal limit that should be written to storage. returned value is in\n /// raw for with interest mode, normal amount for interest free mode!\n function calcWithdrawalLimitAfterOperate(\n uint256 userSupplyData_,\n uint256 userSupply_,\n uint256 newWithdrawalLimit_\n ) internal pure returns (uint256) {\n // temp_ => base withdrawal limit. below this, maximum withdrawals are allowed\n uint256 temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n // if user supply is below base limit then max withdrawals are allowed\n if (userSupply_ < temp_) {\n return 0;\n }\n // temp_ => withdrawal limit expandPercent (is in 1e2 decimals)\n temp_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_EXPAND_PERCENT) & X14;\n unchecked {\n // temp_ => minimum withdrawal limit: userSupply - max withdrawable limit (userSupply * expandPercent))\n // userSupply_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n // subtraction can not underflow as maxWithdrawableLimit_ is a percentage amount (<=100%) of userSupply_\n temp_ = userSupply_ - ((userSupply_ * temp_) / FOUR_DECIMALS);\n }\n // if new (before operation) withdrawal limit is less than minimum limit then set minimum limit.\n // e.g. can happen on new deposits. withdrawal limit is instantly fully expanded in a scenario where\n // increased deposit amount outpaces withrawals.\n if (temp_ > newWithdrawalLimit_) {\n return temp_;\n }\n return newWithdrawalLimit_;\n }\n\n /// @dev calculates borrow limit before an operate execution:\n /// total amount user borrow can reach (not borrowable amount in current operation).\n /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n /// @param userBorrowData_ user borrow data packed uint256 from storage\n /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_`\n /// @return currentBorrowLimit_ current borrow limit updated for expansion since last interaction. returned value is in\n /// raw for with interest mode, normal amount for interest free mode!\n function calcBorrowLimitBeforeOperate(\n uint256 userBorrowData_,\n uint256 userBorrow_\n ) internal view returns (uint256 currentBorrowLimit_) {\n // @dev must support handling the case where timestamp is 0 (config is set but no interactions yet) -> base limit.\n // first tx where timestamp is 0 will enter `if (maxExpandedBorrowLimit_ < baseBorrowLimit_)` because `userBorrow_` and thus\n // `maxExpansionLimit_` and thus `maxExpandedBorrowLimit_` is 0 and `baseBorrowLimit_` can not be 0.\n\n // temp_ = extract borrow expand percent (is in 1e2 decimals)\n uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14;\n\n uint256 maxExpansionLimit_;\n uint256 maxExpandedBorrowLimit_;\n unchecked {\n // calculate max expansion limit: Max amount limit can expand to since last interaction\n // userBorrow_ needs to be atleast 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n maxExpansionLimit_ = ((userBorrow_ * temp_) / FOUR_DECIMALS);\n\n // calculate max borrow limit: Max point limit can increase to since last interaction\n maxExpandedBorrowLimit_ = userBorrow_ + maxExpansionLimit_;\n }\n\n // currentBorrowLimit_ = extract base borrow limit\n currentBorrowLimit_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n currentBorrowLimit_ =\n (currentBorrowLimit_ >> DEFAULT_EXPONENT_SIZE) <<\n (currentBorrowLimit_ & DEFAULT_EXPONENT_MASK);\n\n if (maxExpandedBorrowLimit_ < currentBorrowLimit_) {\n return currentBorrowLimit_;\n }\n // time elapsed since last borrow limit was set (in seconds)\n unchecked {\n // temp_ = timeElapsed_ (last timestamp can not be > current timestamp)\n temp_ =\n block.timestamp -\n ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP) & X33); // extract last udpate timestamp\n }\n\n // currentBorrowLimit_ = expandedBorrowableAmount + extract last set borrow limit\n currentBorrowLimit_ =\n // calculate borrow limit expansion since last interaction for `expandPercent` that is elapsed of `expandDuration`.\n // divisor is extract expand duration (after this, full expansion to expandPercentage happened).\n ((maxExpansionLimit_ * temp_) /\n ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_DURATION) & X24)) + // expand duration can never be 0\n // extract last set borrow limit\n BigMathMinified.fromBigNumber(\n (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) & X64,\n DEFAULT_EXPONENT_SIZE,\n DEFAULT_EXPONENT_MASK\n );\n\n // if timeElapsed is bigger than expandDuration, new borrow limit would be > max expansion,\n // so set to `maxExpandedBorrowLimit_` in that case.\n // also covers the case where last process timestamp = 0 (timeElapsed would simply be very big)\n if (currentBorrowLimit_ > maxExpandedBorrowLimit_) {\n currentBorrowLimit_ = maxExpandedBorrowLimit_;\n }\n // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n if (currentBorrowLimit_ > temp_) {\n currentBorrowLimit_ = temp_;\n }\n }\n\n /// @dev calculates borrow limit after an operate execution:\n /// total amount user borrow can reach (not borrowable amount in current operation).\n /// i.e. if user has borrowed 50M and can still borrow 5M, this method returns the total 55M, not the borrowable amount 5M\n /// @param userBorrowData_ user borrow data packed uint256 from storage\n /// @param userBorrow_ current user borrow amount already extracted from `userBorrowData_` and added / subtracted with the executed operate amount\n /// @param newBorrowLimit_ current borrow limit updated for expansion since last interaction, result from `calcBorrowLimitBeforeOperate`\n /// @return borrowLimit_ updated borrow limit that should be written to storage.\n /// returned value is in raw for with interest mode, normal amount for interest free mode!\n function calcBorrowLimitAfterOperate(\n uint256 userBorrowData_,\n uint256 userBorrow_,\n uint256 newBorrowLimit_\n ) internal pure returns (uint256 borrowLimit_) {\n // temp_ = extract borrow expand percent\n uint256 temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_EXPAND_PERCENT) & X14; // (is in 1e2 decimals)\n\n unchecked {\n // borrowLimit_ = calculate maximum borrow limit at full expansion.\n // userBorrow_ needs to be at least 1e73 to overflow max limit of ~1e77 in uint256 (no token in existence where this is possible).\n borrowLimit_ = userBorrow_ + ((userBorrow_ * temp_) / FOUR_DECIMALS);\n }\n\n // temp_ = extract base borrow limit\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_BASE_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n if (borrowLimit_ < temp_) {\n // below base limit, borrow limit is always base limit\n return temp_;\n }\n // temp_ = extract hard max borrow limit. Above this user can never borrow (not expandable above)\n temp_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_MAX_BORROW_LIMIT) & X18;\n temp_ = (temp_ >> DEFAULT_EXPONENT_SIZE) << (temp_ & DEFAULT_EXPONENT_MASK);\n\n // make sure fully expanded borrow limit is not above hard max borrow limit\n if (borrowLimit_ > temp_) {\n borrowLimit_ = temp_;\n }\n // if new borrow limit (from before operate) is > max borrow limit, set max borrow limit.\n // (e.g. on a repay shrinking instantly to fully expanded borrow limit from new borrow amount. shrinking is instant)\n if (newBorrowLimit_ > borrowLimit_) {\n return borrowLimit_;\n }\n return newBorrowLimit_;\n }\n\n ///////////////////////////////////////////////////////////////////////////\n ////////// CALC RATES /////////\n ///////////////////////////////////////////////////////////////////////////\n\n /// @dev Calculates new borrow rate from utilization for a token\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ totalBorrow / totalSupply. 1e4 = 100% utilization\n /// @return rate_ rate for that particular token in 1e2 precision (e.g. 5% rate = 500)\n function calcBorrowRateFromUtilization(uint256 rateData_, uint256 utilization_) internal returns (uint256 rate_) {\n // extract rate version: 4 bits (0xF) starting from bit 0\n uint256 rateVersion_ = (rateData_ & 0xF);\n\n if (rateVersion_ == 1) {\n rate_ = calcRateV1(rateData_, utilization_);\n } else if (rateVersion_ == 2) {\n rate_ = calcRateV2(rateData_, utilization_);\n } else {\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__UnsupportedRateVersion);\n }\n\n if (rate_ > X16) {\n // hard cap for borrow rate at maximum value 16 bits (65535) to make sure it does not overflow storage space.\n // this is unlikely to ever happen if configs stay within expected levels.\n rate_ = X16;\n // emit event to more easily become aware\n emit BorrowRateMaxCap();\n }\n }\n\n /// @dev calculates the borrow rate based on utilization for rate data version 1 (with one kink) in 1e2 precision\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ in 1e2 (100% = 1e4)\n /// @return rate_ rate in 1e2 precision\n function calcRateV1(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n /// For rate v1 (one kink) ------------------------------------------------------\n /// Next 16 bits => 4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 52- 67 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Last 188 bits => 68-255 => blank, might come in use in future\n\n // y = mx + c.\n // y is borrow rate\n // x is utilization\n // m = slope (m can be 0 but never negative)\n // c is constant (c can be negative)\n\n uint256 y1_;\n uint256 y2_;\n uint256 x1_;\n uint256 x2_;\n\n // extract kink1: 16 bits (0xFFFF) starting from bit 20\n // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_UTILIZATION_AT_KINK) & X16;\n if (utilization_ < kink1_) {\n // if utilization is less than kink\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n x1_ = 0; // 0%\n x2_ = kink1_;\n } else {\n // else utilization is greater than kink\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX) & X16;\n x1_ = kink1_;\n x2_ = FOUR_DECIMALS; // 100%\n }\n\n int256 constant_;\n uint256 slope_;\n unchecked {\n // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor) and rate at y2 can not be < rate at y1\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n slope_ = ((y2_ - y1_) * TWELVE_DECIMALS) / (x2_ - x1_);\n\n // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n // subtraction most extreme case would be 0 - max value slope_ * x1_ => can not underflow int256\n constant_ = int256(y1_ * TWELVE_DECIMALS) - int256(slope_ * x1_);\n\n // calculating new borrow rate\n // - slope_ max value is 65535 * 1e12,\n // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n // - constant max value is 65535 * 1e12\n // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n // divisor TWELVE_DECIMALS can not be 0\n rate_ = (uint256(int256(slope_ * utilization_) + constant_)) / TWELVE_DECIMALS;\n }\n }\n\n /// @dev calculates the borrow rate based on utilization for rate data version 2 (with two kinks) in 1e4 precision\n /// @param rateData_ rate data packed uint256 from storage for the token\n /// @param utilization_ in 1e2 (100% = 1e4)\n /// @return rate_ rate in 1e4 precision\n function calcRateV2(uint256 rateData_, uint256 utilization_) internal pure returns (uint256 rate_) {\n /// For rate v2 (two kinks) -----------------------------------------------------\n /// Next 16 bits => 4 - 19 => Rate at utilization 0% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 20- 35 => Utilization at kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 36- 51 => Rate at utilization kink1 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 52- 67 => Utilization at kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 68- 83 => Rate at utilization kink2 (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Next 16 bits => 84- 99 => Rate at utilization 100% (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\n /// Last 156 bits => 100-255 => blank, might come in use in future\n\n // y = mx + c.\n // y is borrow rate\n // x is utilization\n // m = slope (m can be 0 but never negative)\n // c is constant (c can be negative)\n\n uint256 y1_;\n uint256 y2_;\n uint256 x1_;\n uint256 x2_;\n\n // extract kink1: 16 bits (0xFFFF) starting from bit 20\n // kink is in 1e2, same as utilization, so no conversion needed for direct comparison of the two\n uint256 kink1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1) & X16;\n if (utilization_ < kink1_) {\n // if utilization is less than kink1\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n x1_ = 0; // 0%\n x2_ = kink1_;\n } else {\n // extract kink2: 16 bits (0xFFFF) starting from bit 52\n uint256 kink2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2) & X16;\n if (utilization_ < kink2_) {\n // if utilization is less than kink2\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n x1_ = kink1_;\n x2_ = kink2_;\n } else {\n // else utilization is greater than kink2\n y1_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2) & X16;\n y2_ = (rateData_ >> LiquiditySlotsLink.BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX) & X16;\n x1_ = kink2_;\n x2_ = FOUR_DECIMALS;\n }\n }\n\n int256 constant_;\n uint256 slope_;\n unchecked {\n // calculating slope with twelve decimal precision. m = (y2 - y1) / (x2 - x1).\n // utilization of x2 can not be <= utilization of x1 (so no underflow or 0 divisor) and rate at y2 can not be < rate at y1\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\n slope_ = ((y2_ - y1_) * TWELVE_DECIMALS) / (x2_ - x1_);\n\n // calculating constant at 12 decimal precision. slope is already in 12 decimal hence only multiple with y1. c = y - mx.\n // maximum y1_ value is 65535. 65535 * 1e12 can not overflow int256\n // maximum slope is 65535 - 0 * TWELVE_DECIMALS / 1 = 65535 * 1e12;\n // maximum x1_ is 100% (9_999 actually) => slope_ * x1_ can not overflow int256\n // subtraction most extreme case would be 0 - max value slope_ * x1_ => can not underflow int256\n constant_ = int256(y1_ * TWELVE_DECIMALS) - int256(slope_ * x1_);\n\n // calculating new borrow rate\n // - slope_ max value is 65535 * 1e12,\n // - utilization max value is let's say 500% (extreme case where borrow rate increases borrow amount without new supply)\n // - constant max value is 65535 * 1e12\n // so max values are 65535 * 1e12 * 50_000 + 65535 * 1e12 -> 3.2768*10^21, which easily fits int256\n // divisor TWELVE_DECIMALS can not be 0\n rate_ = (uint256(int256(slope_ * utilization_) + constant_)) / TWELVE_DECIMALS;\n }\n }\n\n /// @dev reads the total supply out of Liquidity packed storage `totalAmounts_` for `supplyExchangePrice_`\n function getTotalSupply(\n uint256 totalAmounts_,\n uint256 supplyExchangePrice_\n ) internal pure returns (uint256 totalSupply_) {\n // totalSupply_ => supplyInterestFree\n totalSupply_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\n totalSupply_ = (totalSupply_ >> DEFAULT_EXPONENT_SIZE) << (totalSupply_ & DEFAULT_EXPONENT_MASK);\n\n uint256 totalSupplyRaw_ = totalAmounts_ & X64; // no shifting as supplyRaw is first 64 bits\n totalSupplyRaw_ = (totalSupplyRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalSupplyRaw_ & DEFAULT_EXPONENT_MASK);\n\n // totalSupply = supplyInterestFree + supplyRawInterest normalized from raw\n totalSupply_ += ((totalSupplyRaw_ * supplyExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n }\n\n /// @dev reads the total borrow out of Liquidity packed storage `totalAmounts_` for `borrowExchangePrice_`\n function getTotalBorrow(\n uint256 totalAmounts_,\n uint256 borrowExchangePrice_\n ) internal pure returns (uint256 totalBorrow_) {\n // totalBorrow_ => borrowInterestFree\n // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\n totalBorrow_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\n totalBorrow_ = (totalBorrow_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrow_ & DEFAULT_EXPONENT_MASK);\n\n uint256 totalBorrowRaw_ = (totalAmounts_ >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\n totalBorrowRaw_ = (totalBorrowRaw_ >> DEFAULT_EXPONENT_SIZE) << (totalBorrowRaw_ & DEFAULT_EXPONENT_MASK);\n\n // totalBorrow = borrowInterestFree + borrowRawInterest normalized from raw\n totalBorrow_ += ((totalBorrowRaw_ * borrowExchangePrice_) / EXCHANGE_PRICES_PRECISION);\n }\n}\n"
|
|
},
|
|
"contracts/libraries/liquiditySlotsLink.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @notice library that helps in reading / working with storage slot data of Fluid Liquidity.\n/// @dev as all data for Fluid Liquidity is internal, any data must be fetched directly through manual\n/// slot reading through this library or, if gas usage is less important, through the FluidLiquidityResolver.\nlibrary LiquiditySlotsLink {\n /// @dev storage slot for status at Liquidity\n uint256 internal constant LIQUIDITY_STATUS_SLOT = 1;\n /// @dev storage slot for auths mapping at Liquidity\n uint256 internal constant LIQUIDITY_AUTHS_MAPPING_SLOT = 2;\n /// @dev storage slot for guardians mapping at Liquidity\n uint256 internal constant LIQUIDITY_GUARDIANS_MAPPING_SLOT = 3;\n /// @dev storage slot for user class mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_CLASS_MAPPING_SLOT = 4;\n /// @dev storage slot for exchangePricesAndConfig mapping at Liquidity\n uint256 internal constant LIQUIDITY_EXCHANGE_PRICES_MAPPING_SLOT = 5;\n /// @dev storage slot for rateData mapping at Liquidity\n uint256 internal constant LIQUIDITY_RATE_DATA_MAPPING_SLOT = 6;\n /// @dev storage slot for totalAmounts mapping at Liquidity\n uint256 internal constant LIQUIDITY_TOTAL_AMOUNTS_MAPPING_SLOT = 7;\n /// @dev storage slot for user supply double mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_SUPPLY_DOUBLE_MAPPING_SLOT = 8;\n /// @dev storage slot for user borrow double mapping at Liquidity\n uint256 internal constant LIQUIDITY_USER_BORROW_DOUBLE_MAPPING_SLOT = 9;\n /// @dev storage slot for listed tokens array at Liquidity\n uint256 internal constant LIQUIDITY_LISTED_TOKENS_ARRAY_SLOT = 10;\n\n // --------------------------------\n // @dev stacked uint256 storage slots bits position data for each:\n\n // ExchangePricesAndConfig\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATE = 0;\n uint256 internal constant BITS_EXCHANGE_PRICES_FEE = 16;\n uint256 internal constant BITS_EXCHANGE_PRICES_UTILIZATION = 30;\n uint256 internal constant BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD = 44;\n uint256 internal constant BITS_EXCHANGE_PRICES_LAST_TIMESTAMP = 58;\n uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE = 91;\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE = 155;\n uint256 internal constant BITS_EXCHANGE_PRICES_SUPPLY_RATIO = 219;\n uint256 internal constant BITS_EXCHANGE_PRICES_BORROW_RATIO = 234;\n\n // RateData:\n uint256 internal constant BITS_RATE_DATA_VERSION = 0;\n // RateData: V1\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_ZERO = 4;\n uint256 internal constant BITS_RATE_DATA_V1_UTILIZATION_AT_KINK = 20;\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_KINK = 36;\n uint256 internal constant BITS_RATE_DATA_V1_RATE_AT_UTILIZATION_MAX = 52;\n // RateData: V2\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_ZERO = 4;\n uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK1 = 20;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK1 = 36;\n uint256 internal constant BITS_RATE_DATA_V2_UTILIZATION_AT_KINK2 = 52;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_KINK2 = 68;\n uint256 internal constant BITS_RATE_DATA_V2_RATE_AT_UTILIZATION_MAX = 84;\n\n // TotalAmounts\n uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_WITH_INTEREST = 0;\n uint256 internal constant BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE = 64;\n uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST = 128;\n uint256 internal constant BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE = 192;\n\n // UserSupplyData\n uint256 internal constant BITS_USER_SUPPLY_MODE = 0;\n uint256 internal constant BITS_USER_SUPPLY_AMOUNT = 1;\n uint256 internal constant BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT = 65;\n uint256 internal constant BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP = 129;\n uint256 internal constant BITS_USER_SUPPLY_EXPAND_PERCENT = 162;\n uint256 internal constant BITS_USER_SUPPLY_EXPAND_DURATION = 176;\n uint256 internal constant BITS_USER_SUPPLY_BASE_WITHDRAWAL_LIMIT = 200;\n uint256 internal constant BITS_USER_SUPPLY_IS_PAUSED = 255;\n\n // UserBorrowData\n uint256 internal constant BITS_USER_BORROW_MODE = 0;\n uint256 internal constant BITS_USER_BORROW_AMOUNT = 1;\n uint256 internal constant BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT = 65;\n uint256 internal constant BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP = 129;\n uint256 internal constant BITS_USER_BORROW_EXPAND_PERCENT = 162;\n uint256 internal constant BITS_USER_BORROW_EXPAND_DURATION = 176;\n uint256 internal constant BITS_USER_BORROW_BASE_BORROW_LIMIT = 200;\n uint256 internal constant BITS_USER_BORROW_MAX_BORROW_LIMIT = 218;\n uint256 internal constant BITS_USER_BORROW_IS_PAUSED = 255;\n\n // --------------------------------\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping at `slot_` for `key_`\n function calculateMappingStorageSlot(uint256 slot_, address key_) internal pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for double mapping at `slot_` for `key1_` and `key2_`\n function calculateDoubleMappingStorageSlot(\n uint256 slot_,\n address key1_,\n address key2_\n ) internal pure returns (bytes32) {\n bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));\n return keccak256(abi.encode(key2_, intermediateSlot_));\n }\n}\n"
|
|
},
|
|
"contracts/libraries/tickMath.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title library that calculates number \"tick\" and \"ratioX96\" from this: ratioX96 = (1.0015^tick) * 2^96\n/// @notice this library is used in Fluid Vault protocol for optimiziation.\n/// @dev \"tick\" supports between -32767 and 32767. \"ratioX96\" supports between 37075072 and 169307877264527972847801929085841449095838922544595\nlibrary TickMath {\n /// The minimum tick that can be passed in getRatioAtTick. 1.0015**-32767\n int24 internal constant MIN_TICK = -32767;\n /// The maximum tick that can be passed in getRatioAtTick. 1.0015**32767\n int24 internal constant MAX_TICK = 32767;\n\n uint256 internal constant FACTOR00 = 0x100000000000000000000000000000000;\n uint256 internal constant FACTOR01 = 0xff9dd7de423466c20352b1246ce4856f; // 2^128/1.0015**1 = 339772707859149738855091969477551883631\n uint256 internal constant FACTOR02 = 0xff3bd55f4488ad277531fa1c725a66d0; // 2^128/1.0015**2 = 339263812140938331358054887146831636176\n uint256 internal constant FACTOR03 = 0xfe78410fd6498b73cb96a6917f853259; // 2^128/1.0015**4 = 338248306163758188337119769319392490073\n uint256 internal constant FACTOR04 = 0xfcf2d9987c9be178ad5bfeffaa123273; // 2^128/1.0015**8 = 336226404141693512316971918999264834163\n uint256 internal constant FACTOR05 = 0xf9ef02c4529258b057769680fc6601b3; // 2^128/1.0015**16 = 332218786018727629051611634067491389875\n uint256 internal constant FACTOR06 = 0xf402d288133a85a17784a411f7aba082; // 2^128/1.0015**32 = 324346285652234375371948336458280706178\n uint256 internal constant FACTOR07 = 0xe895615b5beb6386553757b0352bda90; // 2^128/1.0015**64 = 309156521885964218294057947947195947664\n uint256 internal constant FACTOR08 = 0xd34f17a00ffa00a8309940a15930391a; // 2^128/1.0015**128 = 280877777739312896540849703637713172762 \n uint256 internal constant FACTOR09 = 0xae6b7961714e20548d88ea5123f9a0ff; // 2^128/1.0015**256 = 231843708922198649176471782639349113087\n uint256 internal constant FACTOR10 = 0x76d6461f27082d74e0feed3b388c0ca1; // 2^128/1.0015**512 = 157961477267171621126394973980180876449\n uint256 internal constant FACTOR11 = 0x372a3bfe0745d8b6b19d985d9a8b85bb; // 2^128/1.0015**1024 = 73326833024599564193373530205717235131\n uint256 internal constant FACTOR12 = 0x0be32cbee48979763cf7247dd7bb539d; // 2^128/1.0015**2048 = 15801066890623697521348224657638773661\n uint256 internal constant FACTOR13 = 0x8d4f70c9ff4924dac37612d1e2921e; // 2^128/1.0015**4096 = 733725103481409245883800626999235102\n uint256 internal constant FACTOR14 = 0x4e009ae5519380809a02ca7aec77; // 2^128/1.0015**8192 = 1582075887005588088019997442108535\n uint256 internal constant FACTOR15 = 0x17c45e641b6e95dee056ff10; // 2^128/1.0015**16384 = 7355550435635883087458926352\n\n /// The minimum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MIN_TICK). ~ Equivalent to `(1 << 96) * (1.0015**-32767)`\n uint256 internal constant MIN_RATIOX96 = 37075072;\n /// The maximum value that can be returned from getRatioAtTick. Equivalent to getRatioAtTick(MAX_TICK).\n /// ~ Equivalent to `(1 << 96) * (1.0015**32767)`, rounding etc. leading to minor difference\n uint256 internal constant MAX_RATIOX96 = 169307877264527972847801929085841449095838922544595;\n\n uint256 internal constant ZERO_TICK_SCALED_RATIO = 0x1000000000000000000000000; // 1 << 96 // 79228162514264337593543950336\n uint256 internal constant _1E26 = 1e26;\n\n /// @notice ratioX96 = (1.0015^tick) * 2^96\n /// @dev Throws if |tick| > max tick\n /// @param tick The input tick for the above formula\n /// @return ratioX96 ratio = (debt amount/collateral amount)\n function getRatioAtTick(int tick) internal pure returns (uint256 ratioX96) {\n assembly {\n let absTick_ := sub(xor(tick, sar(255, tick)), sar(255, tick))\n\n if gt(absTick_, MAX_TICK) {\n revert(0, 0)\n }\n let factor_ := FACTOR00\n if and(absTick_, 0x1) {\n factor_ := FACTOR01\n }\n if and(absTick_, 0x2) {\n factor_ := shr(128, mul(factor_, FACTOR02))\n }\n if and(absTick_, 0x4) {\n factor_ := shr(128, mul(factor_, FACTOR03))\n }\n if and(absTick_, 0x8) {\n factor_ := shr(128, mul(factor_, FACTOR04))\n }\n if and(absTick_, 0x10) {\n factor_ := shr(128, mul(factor_, FACTOR05))\n }\n if and(absTick_, 0x20) {\n factor_ := shr(128, mul(factor_, FACTOR06))\n }\n if and(absTick_, 0x40) {\n factor_ := shr(128, mul(factor_, FACTOR07))\n }\n if and(absTick_, 0x80) {\n factor_ := shr(128, mul(factor_, FACTOR08))\n }\n if and(absTick_, 0x100) {\n factor_ := shr(128, mul(factor_, FACTOR09))\n }\n if and(absTick_, 0x200) {\n factor_ := shr(128, mul(factor_, FACTOR10))\n }\n if and(absTick_, 0x400) {\n factor_ := shr(128, mul(factor_, FACTOR11))\n }\n if and(absTick_, 0x800) {\n factor_ := shr(128, mul(factor_, FACTOR12))\n }\n if and(absTick_, 0x1000) {\n factor_ := shr(128, mul(factor_, FACTOR13))\n }\n if and(absTick_, 0x2000) {\n factor_ := shr(128, mul(factor_, FACTOR14))\n }\n if and(absTick_, 0x4000) {\n factor_ := shr(128, mul(factor_, FACTOR15))\n }\n\n let precision_ := 0\n if iszero(and(tick, 0x8000000000000000000000000000000000000000000000000000000000000000)) {\n factor_ := div(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, factor_)\n // we round up in the division so getTickAtRatio of the output price is always consistent\n if mod(factor_, 0x100000000) {\n precision_ := 1\n }\n }\n ratioX96 := add(shr(32, factor_), precision_)\n }\n }\n\n /// @notice ratioX96 = (1.0015^tick) * 2^96\n /// @dev Throws if ratioX96 > max ratio || ratioX96 < min ratio\n /// @param ratioX96 The input ratio; ratio = (debt amount/collateral amount)\n /// @return tick The output tick for the above formula. Returns in round down form. if tick is 123.23 then 123, if tick is -123.23 then returns -124\n /// @return perfectRatioX96 perfect ratio for the above tick\n function getTickAtRatio(uint256 ratioX96) internal pure returns (int tick, uint perfectRatioX96) {\n assembly {\n if or(gt(ratioX96, MAX_RATIOX96), lt(ratioX96, MIN_RATIOX96)) {\n revert(0, 0)\n }\n\n let cond := lt(ratioX96, ZERO_TICK_SCALED_RATIO)\n let factor_\n\n if iszero(cond) {\n // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n factor_ := div(mul(ratioX96, _1E26), ZERO_TICK_SCALED_RATIO)\n }\n if cond {\n // ratioX96 < ZERO_TICK_SCALED_RATIO\n factor_ := div(mul(ZERO_TICK_SCALED_RATIO, _1E26), ratioX96)\n }\n\n // put in https://www.wolframalpha.com/ whole equation: (1.0015^tick) * 2^96 * 10^26 / 79228162514264337593543950336\n\n // for tick = 16384\n // ratioX96 = (1.0015^16384) * 2^96 = 3665252098134783297721995888537077351735\n // 3665252098134783297721995888537077351735 * 10^26 / 79228162514264337593543950336 =\n // 4626198540796508716348404308345255985.06131964639489434655721\n if iszero(lt(factor_, 4626198540796508716348404308345255985)) {\n tick := or(tick, 0x4000)\n factor_ := div(mul(factor_, _1E26), 4626198540796508716348404308345255985)\n }\n // for tick = 8192\n // ratioX96 = (1.0015^8192) * 2^96 = 17040868196391020479062776466509865\n // 17040868196391020479062776466509865 * 10^26 / 79228162514264337593543950336 =\n // 21508599537851153911767490449162.3037648642153898377655505172\n if iszero(lt(factor_, 21508599537851153911767490449162)) {\n tick := or(tick, 0x2000)\n factor_ := div(mul(factor_, _1E26), 21508599537851153911767490449162)\n }\n // for tick = 4096\n // ratioX96 = (1.0015^4096) * 2^96 = 36743933851015821532611831851150\n // 36743933851015821532611831851150 * 10^26 / 79228162514264337593543950336 =\n // 46377364670549310883002866648.9777607649742626173648716941385\n if iszero(lt(factor_, 46377364670549310883002866649)) {\n tick := or(tick, 0x1000)\n factor_ := div(mul(factor_, _1E26), 46377364670549310883002866649)\n }\n // for tick = 2048\n // ratioX96 = (1.0015^2048) * 2^96 = 1706210527034005899209104452335\n // 1706210527034005899209104452335 * 10^26 / 79228162514264337593543950336 =\n // 2153540449365864845468344760.06357108484096046743300420319322\n if iszero(lt(factor_, 2153540449365864845468344760)) {\n tick := or(tick, 0x800)\n factor_ := div(mul(factor_, _1E26), 2153540449365864845468344760)\n }\n // for tick = 1024\n // ratioX96 = (1.0015^1024) * 2^96 = 367668226692760093024536487236\n // 367668226692760093024536487236 * 10^26 / 79228162514264337593543950336 =\n // 464062544207767844008185024.950588990554136265212906454481127\n if iszero(lt(factor_, 464062544207767844008185025)) {\n tick := or(tick, 0x400)\n factor_ := div(mul(factor_, _1E26), 464062544207767844008185025)\n }\n // for tick = 512\n // ratioX96 = (1.0015^512) * 2^96 = 170674186729409605620119663668\n // 170674186729409605620119663668 * 10^26 / 79228162514264337593543950336 =\n // 215421109505955298802281577.031879604792139232258508172947569\n if iszero(lt(factor_, 215421109505955298802281577)) {\n tick := or(tick, 0x200)\n factor_ := div(mul(factor_, _1E26), 215421109505955298802281577)\n }\n // for tick = 256\n // ratioX96 = (1.0015^256) * 2^96 = 116285004205991934861656513301\n // 116285004205991934861656513301 * 10^26 / 79228162514264337593543950336 =\n // 146772309890508740607270614.667650899656438875541505058062410\n if iszero(lt(factor_, 146772309890508740607270615)) {\n tick := or(tick, 0x100)\n factor_ := div(mul(factor_, _1E26), 146772309890508740607270615)\n }\n // for tick = 128\n // ratioX96 = (1.0015^128) * 2^96 = 95984619659632141743747099590\n // 95984619659632141743747099590 * 10^26 / 79228162514264337593543950336 =\n // 121149622323187099817270416.157248837742741760456796835775887\n if iszero(lt(factor_, 121149622323187099817270416)) {\n tick := or(tick, 0x80)\n factor_ := div(mul(factor_, _1E26), 121149622323187099817270416)\n }\n // for tick = 64\n // ratioX96 = (1.0015^64) * 2^96 = 87204845308406958006717891124\n // 87204845308406958006717891124 * 10^26 / 79228162514264337593543950336 =\n // 110067989135437147685980801.568068573422377364214113968609839\n if iszero(lt(factor_, 110067989135437147685980801)) {\n tick := or(tick, 0x40)\n factor_ := div(mul(factor_, _1E26), 110067989135437147685980801)\n }\n // for tick = 32\n // ratioX96 = (1.0015^32) * 2^96 = 83120873769022354029916374475\n // 83120873769022354029916374475 * 10^26 / 79228162514264337593543950336 =\n // 104913292358707887270979599.831816586773651266562785765558183\n if iszero(lt(factor_, 104913292358707887270979600)) {\n tick := or(tick, 0x20)\n factor_ := div(mul(factor_, _1E26), 104913292358707887270979600)\n }\n // for tick = 16\n // ratioX96 = (1.0015^16) * 2^96 = 81151180492336368327184716176\n // 81151180492336368327184716176 * 10^26 / 79228162514264337593543950336 =\n // 102427189924701091191840927.762844039579442328381455567932128\n if iszero(lt(factor_, 102427189924701091191840928)) {\n tick := or(tick, 0x10)\n factor_ := div(mul(factor_, _1E26), 102427189924701091191840928)\n }\n // for tick = 8\n // ratioX96 = (1.0015^8) * 2^96 = 80183906840906820640659903620\n // 80183906840906820640659903620 * 10^26 / 79228162514264337593543950336 =\n // 101206318935480056907421312.890625\n if iszero(lt(factor_, 101206318935480056907421313)) {\n tick := or(tick, 0x8)\n factor_ := div(mul(factor_, _1E26), 101206318935480056907421313)\n }\n // for tick = 4\n // ratioX96 = (1.0015^4) * 2^96 = 79704602139525152702959747603\n // 79704602139525152702959747603 * 10^26 / 79228162514264337593543950336 =\n // 100601351350506250000000000\n if iszero(lt(factor_, 100601351350506250000000000)) {\n tick := or(tick, 0x4)\n factor_ := div(mul(factor_, _1E26), 100601351350506250000000000)\n }\n // for tick = 2\n // ratioX96 = (1.0015^2) * 2^96 = 79466025265172787701084167660\n // 79466025265172787701084167660 * 10^26 / 79228162514264337593543950336 =\n // 100300225000000000000000000\n if iszero(lt(factor_, 100300225000000000000000000)) {\n tick := or(tick, 0x2)\n factor_ := div(mul(factor_, _1E26), 100300225000000000000000000)\n }\n // for tick = 1\n // ratioX96 = (1.0015^1) * 2^96 = 79347004758035734099934266261\n // 79347004758035734099934266261 * 10^26 / 79228162514264337593543950336 =\n // 100150000000000000000000000\n if iszero(lt(factor_, 100150000000000000000000000)) {\n tick := or(tick, 0x1)\n factor_ := div(mul(factor_, _1E26), 100150000000000000000000000)\n }\n if iszero(cond) {\n // if ratioX96 >= ZERO_TICK_SCALED_RATIO\n perfectRatioX96 := div(mul(ratioX96, _1E26), factor_)\n }\n if cond {\n // ratioX96 < ZERO_TICK_SCALED_RATIO\n tick := not(tick)\n perfectRatioX96 := div(mul(ratioX96, factor_), 100150000000000000000000000)\n }\n }\n }\n}\n"
|
|
},
|
|
"contracts/liquidity/adminModule/structs.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nabstract contract Structs {\n struct AddressBool {\n address addr;\n bool value;\n }\n\n struct AddressUint256 {\n address addr;\n uint256 value;\n }\n\n /// @notice struct to set borrow rate data for version 1\n struct RateDataV1Params {\n ///\n /// @param token for rate data\n address token;\n ///\n /// @param kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n /// utilization below kink usually means slow increase in rate, once utilization is above kink borrow rate increases fast\n uint256 kink;\n ///\n /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100\n /// i.e. constant minimum borrow rate\n /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)\n uint256 rateAtUtilizationZero;\n ///\n /// @param rateAtUtilizationKink borrow rate when utilization is at kink. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 7% at kink then rateAtUtilizationKink would be 700\n uint256 rateAtUtilizationKink;\n ///\n /// @param rateAtUtilizationMax borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500\n uint256 rateAtUtilizationMax;\n }\n\n /// @notice struct to set borrow rate data for version 2\n struct RateDataV2Params {\n ///\n /// @param token for rate data\n address token;\n ///\n /// @param kink1 first kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n /// utilization below kink 1 usually means slow increase in rate, once utilization is above kink 1 borrow rate increases faster\n uint256 kink1;\n ///\n /// @param kink2 second kink in borrow rate. in 1e2: 100% = 10_000; 1% = 100\n /// utilization below kink 2 usually means slow / medium increase in rate, once utilization is above kink 2 borrow rate increases fast\n uint256 kink2;\n ///\n /// @param rateAtUtilizationZero desired borrow rate when utilization is zero. in 1e2: 100% = 10_000; 1% = 100\n /// i.e. constant minimum borrow rate\n /// e.g. at utilization = 0.01% rate could still be at least 4% (rateAtUtilizationZero would be 400 then)\n uint256 rateAtUtilizationZero;\n ///\n /// @param rateAtUtilizationKink1 desired borrow rate when utilization is at first kink. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 7% at first kink then rateAtUtilizationKink would be 700\n uint256 rateAtUtilizationKink1;\n ///\n /// @param rateAtUtilizationKink2 desired borrow rate when utilization is at second kink. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 7% at second kink then rateAtUtilizationKink would be 1_200\n uint256 rateAtUtilizationKink2;\n ///\n /// @param rateAtUtilizationMax desired borrow rate when utilization is maximum at 100%. in 1e2: 100% = 10_000; 1% = 100\n /// e.g. when rate should be 125% at 100% then rateAtUtilizationMax would be 12_500\n uint256 rateAtUtilizationMax;\n }\n\n /// @notice struct to set token config\n struct TokenConfig {\n ///\n /// @param token address\n address token;\n ///\n /// @param fee charges on borrower's interest. in 1e2: 100% = 10_000; 1% = 100\n uint256 fee;\n ///\n /// @param threshold on when to update the storage slot. in 1e2: 100% = 10_000; 1% = 100\n uint256 threshold;\n }\n\n /// @notice struct to set user supply & withdrawal config\n struct UserSupplyConfig {\n ///\n /// @param user address\n address user;\n ///\n /// @param token address\n address token;\n ///\n /// @param mode: 0 = without interest. 1 = with interest\n uint8 mode;\n ///\n /// @param expandPercent withdrawal limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n /// Also used to calculate rate at which withdrawal limit should decrease (instant).\n uint256 expandPercent;\n ///\n /// @param expandDuration withdrawal limit expand duration in seconds.\n /// used to calculate rate together with expandPercent\n uint256 expandDuration;\n ///\n /// @param baseWithdrawalLimit base limit, below this, user can withdraw the entire amount.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 baseWithdrawalLimit;\n }\n\n /// @notice struct to set user borrow & payback config\n struct UserBorrowConfig {\n ///\n /// @param user address\n address user;\n ///\n /// @param token address\n address token;\n ///\n /// @param mode: 0 = without interest. 1 = with interest\n uint8 mode;\n ///\n /// @param expandPercent debt limit expand percent. in 1e2: 100% = 10_000; 1% = 100\n /// Also used to calculate rate at which debt limit should decrease (instant).\n uint256 expandPercent;\n ///\n /// @param expandDuration debt limit expand duration in seconds.\n /// used to calculate rate together with expandPercent\n uint256 expandDuration;\n ///\n /// @param baseDebtCeiling base borrow limit. until here, borrow limit remains as baseDebtCeiling\n /// (user can borrow until this point at once without stepped expansion). Above this, automated limit comes in place.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 baseDebtCeiling;\n ///\n /// @param maxDebtCeiling max borrow ceiling, maximum amount the user can borrow.\n /// amount in raw (to be multiplied with exchange price) or normal depends on configured mode in user config for the token:\n /// with interest -> raw, without interest -> normal\n uint256 maxDebtCeiling;\n }\n}\n"
|
|
},
|
|
"contracts/oracle/fluidOracle.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidOracle } from \"./interfaces/iFluidOracle.sol\";\n\n/// @title FluidOracle\n/// @notice Base contract that any Fluid Oracle must implement\nabstract contract FluidOracle is IFluidOracle {\n /// @inheritdoc IFluidOracle\n function getExchangeRate() external view virtual returns (uint256 exchangeRate_);\n}\n"
|
|
},
|
|
"contracts/oracle/interfaces/iFluidOracle.sol": {
|
|
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidOracle {\n /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27\n function getExchangeRate() external view returns (uint256 exchangeRate_);\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/liquidity/iLiquidityResolver.sol": {
|
|
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Structs as LiquidityStructs } from \"../../../periphery/resolvers/liquidity/structs.sol\";\n\ninterface IFluidLiquidityResolver {\n /// @notice gets the `revenueAmount_` for a `token_`.\n function getRevenue(address token_) external view returns (uint256 revenueAmount_);\n\n /// @notice address of contract that gets sent the revenue. Configurable by governance\n function getRevenueCollector() external view returns (address);\n\n /// @notice Liquidity contract paused status: status = 1 -> normal. status = 2 -> paused.\n function getStatus() external view returns (uint256);\n\n /// @notice checks if `auth_` is an allowed auth on Liquidity.\n /// Auths can set most config values. E.g. contracts that automate certain flows like e.g. adding a new fToken.\n /// Governance can add/remove auths. Governance is auth by default.\n function isAuth(address auth_) external view returns (uint256);\n\n /// @notice checks if `guardian_` is an allowed Guardian on Liquidity.\n /// Guardians can pause lower class users.\n /// Governance can add/remove guardians. Governance is guardian by default.\n function isGuardian(address guardian_) external view returns (uint256);\n\n /// @notice gets user class for `user_`. Class defines which protocols can be paused by guardians.\n /// Currently there are 2 classes: 0 can be paused by guardians. 1 cannot be paused by guardians.\n /// New protocols are added as class 0 and will be upgraded to 1 over time.\n function getUserClass(address user_) external view returns (uint256);\n\n /// @notice gets exchangePricesAndConfig packed uint256 storage slot for `token_`.\n function getExchangePricesAndConfig(address token_) external view returns (uint256);\n\n /// @notice gets rateConfig packed uint256 storage slot for `token_`.\n function getRateConfig(address token_) external view returns (uint256);\n\n /// @notice gets totalAmounts packed uint256 storage slot for `token_`.\n function getTotalAmounts(address token_) external view returns (uint256);\n\n /// @notice gets userSupply data packed uint256 storage slot for `user_` and `token_`.\n function getUserSupply(address user_, address token_) external view returns (uint256);\n\n /// @notice gets userBorrow data packed uint256 storage slot for `user_` and `token_`.\n function getUserBorrow(address user_, address token_) external view returns (uint256);\n\n /// @notice returns all `listedTokens_` at the Liquidity contract. Once configured, a token can never be removed.\n function listedTokens() external view returns (address[] memory listedTokens_);\n\n /// @notice get the Rate config data `rateData_` for a `token_` compiled from the packed uint256 rateConfig storage slot\n function getTokenRateData(address token_) external view returns (LiquidityStructs.RateData memory rateData_);\n\n /// @notice get the Rate config datas `rateDatas_` for multiple `tokens_` compiled from the packed uint256 rateConfig storage slot\n function getTokensRateData(\n address[] calldata tokens_\n ) external view returns (LiquidityStructs.RateData[] memory rateDatas_);\n\n /// @notice returns general data for `token_` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getOverallTokenData(\n address token_\n ) external view returns (LiquidityStructs.OverallTokenData memory overallTokenData_);\n\n /// @notice returns general data for multiple `tokens_` such as rates, exchange prices, utilization, fee, total amounts etc.\n function getOverallTokensData(\n address[] calldata tokens_\n ) external view returns (LiquidityStructs.OverallTokenData[] memory overallTokensData_);\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n function getUserSupplyData(\n address user_,\n address token_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData memory userSupplyData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n );\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n function getUserMultipleSupplyData(\n address user_,\n address[] calldata tokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n LiquidityStructs.OverallTokenData[] memory overallTokensData_\n );\n\n /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for `token_`\n function getUserBorrowData(\n address user_,\n address token_\n )\n external\n view\n returns (\n LiquidityStructs.UserBorrowData memory userBorrowData_,\n LiquidityStructs.OverallTokenData memory overallTokenData_\n );\n\n /// @notice returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `tokens_`\n function getUserMultipleBorrowData(\n address user_,\n address[] calldata tokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n LiquidityStructs.OverallTokenData[] memory overallTokensData_\n );\n\n /// @notice returns `user_` supply data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `supplyTokens_`\n /// and returns `user_` borrow data and general data (such as rates, exchange prices, utilization, fee, total amounts etc.) for multiple `borrowTokens_`\n function getUserMultipleBorrowSupplyData(\n address user_,\n address[] calldata supplyTokens_,\n address[] calldata borrowTokens_\n )\n external\n view\n returns (\n LiquidityStructs.UserSupplyData[] memory userSuppliesData_,\n LiquidityStructs.OverallTokenData[] memory overallSupplyTokensData_,\n LiquidityStructs.UserBorrowData[] memory userBorrowingsData_,\n LiquidityStructs.OverallTokenData[] memory overallBorrowTokensData_\n );\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/liquidity/structs.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Structs as AdminModuleStructs } from \"../../../liquidity/adminModule/structs.sol\";\n\nabstract contract Structs {\n struct RateData {\n uint256 version;\n AdminModuleStructs.RateDataV1Params rateDataV1;\n AdminModuleStructs.RateDataV2Params rateDataV2;\n }\n\n struct OverallTokenData {\n uint256 borrowRate;\n uint256 supplyRate;\n uint256 fee; // revenue fee\n uint256 lastStoredUtilization;\n uint256 storageUpdateThreshold;\n uint256 lastUpdateTimestamp;\n uint256 supplyExchangePrice;\n uint256 borrowExchangePrice;\n uint256 supplyRawInterest;\n uint256 supplyInterestFree;\n uint256 borrowRawInterest;\n uint256 borrowInterestFree;\n uint256 totalSupply;\n uint256 totalBorrow;\n uint256 revenue;\n RateData rateData;\n }\n\n // amounts are always in normal (for withInterest already multiplied with exchange price)\n struct UserSupplyData {\n bool modeWithInterest; // true if mode = with interest, false = without interest\n uint256 supply; // user supply amount\n // the withdrawal limit (e.g. if 10% is the limit, and 100M is supplied, it would be 90M)\n uint256 withdrawalLimit;\n uint256 lastUpdateTimestamp;\n uint256 expandPercent; // withdrawal limit expand percent in 1e2\n uint256 expandDuration; // withdrawal limit expand duration in seconds\n uint256 baseWithdrawalLimit;\n // the current actual max withdrawable amount (e.g. if 10% is the limit, and 100M is supplied, it would be 10M)\n uint256 withdrawableUntilLimit;\n uint256 withdrawable; // actual currently withdrawable amount (supply - withdrawal Limit) & considering balance\n }\n\n // amounts are always in normal (for withInterest already multiplied with exchange price)\n struct UserBorrowData {\n bool modeWithInterest; // true if mode = with interest, false = without interest\n uint256 borrow; // user borrow amount\n uint256 borrowLimit;\n uint256 lastUpdateTimestamp;\n uint256 expandPercent;\n uint256 expandDuration;\n uint256 baseBorrowLimit;\n uint256 maxBorrowLimit;\n uint256 borrowableUntilLimit;\n uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vault/helpers.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Variables } from \"./variables.sol\";\nimport { Structs } from \"./structs.sol\";\n\ncontract Helpers is Variables, Structs {\n function normalSlot(uint256 slot_) public pure returns (bytes32) {\n return bytes32(slot_);\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping\n function calculateStorageSlotUintMapping(uint256 slot_, uint key_) public pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for single mapping\n function calculateStorageSlotIntMapping(uint256 slot_, int key_) public pure returns (bytes32) {\n return keccak256(abi.encode(key_, slot_));\n }\n\n /// @notice Calculating the slot ID for Liquidity contract for double mapping\n function calculateDoubleIntUintMapping(uint256 slot_, int key1_, uint key2_) public pure returns (bytes32) {\n bytes32 intermediateSlot_ = keccak256(abi.encode(key1_, slot_));\n return keccak256(abi.encode(key2_, intermediateSlot_));\n }\n\n function tickHelper(uint tickRaw_) public pure returns (int tick) {\n require(tickRaw_ < X20, \"invalid-number\");\n if (tickRaw_ > 0) {\n tick = tickRaw_ & 1 == 1 ? int((tickRaw_ >> 1) & X19) : -int((tickRaw_ >> 1) & X19);\n } else {\n tick = type(int).min;\n }\n }\n\n constructor(\n address factory_,\n address liquidity_,\n address liquidityResolver_\n ) Variables(factory_, liquidity_, liquidityResolver_) {}\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vault/iVaultResolver.sol": {
|
|
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { Structs } from \"./structs.sol\";\n\ninterface IFluidVaultResolver {\n function vaultByNftId(uint nftId_) external view returns (address vault_);\n\n function positionByNftId(\n uint nftId_\n ) external view returns (Structs.UserPosition memory userPosition_, Structs.VaultEntireData memory vaultData_);\n\n function getVaultVariablesRaw(address vault_) external view returns (uint);\n\n function getAllVaultsAddresses() external view returns (address[] memory vaults_);\n\n function getVaultLiquidation(\n address vault_,\n uint tokenInAmt_\n ) external returns (Structs.LiquidationStruct memory liquidationData_);\n\n function getVaultEntireData(address vault_) external view returns (Structs.VaultEntireData memory vaultData_);\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vault/main.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Helpers } from \"./helpers.sol\";\nimport { TickMath } from \"../../../libraries/tickMath.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\nimport { IFluidOracle } from \"../../../oracle/fluidOracle.sol\";\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { Structs as LiquidityStructs } from \"../liquidity/structs.sol\";\nimport { LiquiditySlotsLink } from \"../../../libraries/liquiditySlotsLink.sol\";\nimport { LiquidityCalcs } from \"../../../libraries/liquidityCalcs.sol\";\n\ninterface TokenInterface {\n function balanceOf(address) external view returns (uint);\n}\n\n/// @notice Fluid Vault protocol resolver\n/// Implements various view-only methods to give easy access to Vault protocol data.\ncontract FluidVaultResolver is Helpers {\n function getVaultAddress(uint256 vaultId_) public view returns (address vault_) {\n // @dev based on https://ethereum.stackexchange.com/a/61413\n bytes memory data;\n if (vaultId_ == 0x00) {\n // nonce of smart contract always starts with 1. so, with nonce 0 there won't be any deployment\n return address(0);\n } else if (vaultId_ <= 0x7f) {\n data = abi.encodePacked(bytes1(0xd6), bytes1(0x94), address(FACTORY), uint8(vaultId_));\n } else if (vaultId_ <= 0xff) {\n data = abi.encodePacked(bytes1(0xd7), bytes1(0x94), address(FACTORY), bytes1(0x81), uint8(vaultId_));\n } else if (vaultId_ <= 0xffff) {\n data = abi.encodePacked(bytes1(0xd8), bytes1(0x94), address(FACTORY), bytes1(0x82), uint16(vaultId_));\n } else if (vaultId_ <= 0xffffff) {\n data = abi.encodePacked(bytes1(0xd9), bytes1(0x94), address(FACTORY), bytes1(0x83), uint24(vaultId_));\n } else {\n data = abi.encodePacked(bytes1(0xda), bytes1(0x94), address(FACTORY), bytes1(0x84), uint32(vaultId_));\n }\n\n return address(uint160(uint256(keccak256(data))));\n }\n\n function getVaultId(address vault_) public view returns (uint id_) {\n id_ = IFluidVaultT1(vault_).VAULT_ID();\n }\n\n function getTokenConfig(uint nftId_) public view returns (uint) {\n return FACTORY.readFromStorage(calculateStorageSlotUintMapping(3, nftId_));\n }\n\n function getVaultVariablesRaw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(0));\n }\n\n function getVaultVariables2Raw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(1));\n }\n\n function getAbsorbedLiquidityRaw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(2));\n }\n\n function getPositionDataRaw(address vault_, uint positionId_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotUintMapping(3, positionId_));\n }\n\n // if tick > 0 then key_ = tick / 256\n // if tick < 0 then key_ = (tick / 256) - 1\n function getTickHasDebtRaw(address vault_, int key_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotIntMapping(4, key_));\n }\n\n function getTickDataRaw(address vault_, int tick_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotIntMapping(5, tick_));\n }\n\n // TODO: Verify below\n // id_ = (realId_ / 3) + 1\n function getTickIdDataRaw(address vault_, int tick_, uint id_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateDoubleIntUintMapping(6, tick_, id_));\n }\n\n function getBranchDataRaw(address vault_, uint branch_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(calculateStorageSlotUintMapping(7, branch_));\n }\n\n function getRateRaw(address vault_) public view returns (uint) {\n return IFluidVaultT1(vault_).readFromStorage(normalSlot(8));\n }\n\n function getRebalancer(address vault_) public view returns (address) {\n return address(uint160(IFluidVaultT1(vault_).readFromStorage(normalSlot(9))));\n }\n\n function getTotalVaults() public view returns (uint) {\n return FACTORY.totalVaults();\n }\n\n function getAllVaultsAddresses() public view returns (address[] memory vaults_) {\n uint totalVaults_ = getTotalVaults();\n vaults_ = new address[](totalVaults_);\n for (uint i = 0; i < totalVaults_; i++) {\n vaults_[i] = getVaultAddress((i + 1));\n }\n }\n\n function getVaultConstants(address vault_) internal view returns (IFluidVaultT1.ConstantViews memory constants_) {\n constants_ = IFluidVaultT1(vault_).constantsView();\n }\n\n function getVaultConfig(address vault_) internal view returns (Configs memory configs_) {\n uint vaultVariables2_ = getVaultVariables2Raw(vault_);\n configs_.supplyRateMagnifier = uint16(vaultVariables2_ & X16);\n configs_.borrowRateMagnifier = uint16((vaultVariables2_ >> 16) & X16);\n configs_.collateralFactor = (uint16((vaultVariables2_ >> 32) & X10)) * 10;\n configs_.liquidationThreshold = (uint16((vaultVariables2_ >> 42) & X10)) * 10;\n configs_.liquidationMaxLimit = (uint16((vaultVariables2_ >> 52) & X10) * 10);\n configs_.withdrawalGap = uint16((vaultVariables2_ >> 62) & X10) * 10;\n configs_.liquidationPenalty = uint16((vaultVariables2_ >> 72) & X10);\n configs_.borrowFee = uint16((vaultVariables2_ >> 82) & X10);\n configs_.oracle = address(uint160(vaultVariables2_ >> 96));\n configs_.oraclePrice = IFluidOracle(configs_.oracle).getExchangeRate();\n configs_.rebalancer = getRebalancer(vault_);\n }\n\n function getExchangePricesAndRates(\n address vault_,\n Configs memory configs_,\n LiquidityStructs.OverallTokenData memory liquiditySupplytokenData_,\n LiquidityStructs.OverallTokenData memory liquidityBorrowtokenData_\n ) internal view returns (ExchangePricesAndRates memory exchangePricesAndRates_) {\n uint exchangePrices_ = getRateRaw(vault_);\n exchangePricesAndRates_.lastStoredLiquiditySupplyExchangePrice = exchangePrices_ & X64;\n exchangePricesAndRates_.lastStoredLiquidityBorrowExchangePrice = (exchangePrices_ >> 64) & X64;\n exchangePricesAndRates_.lastStoredVaultSupplyExchangePrice = (exchangePrices_ >> 128) & X64;\n exchangePricesAndRates_.lastStoredVaultBorrowExchangePrice = (exchangePrices_ >> 192) & X64;\n\n (\n exchangePricesAndRates_.liquiditySupplyExchangePrice,\n exchangePricesAndRates_.liquidityBorrowExchangePrice,\n exchangePricesAndRates_.vaultSupplyExchangePrice,\n exchangePricesAndRates_.vaultBorrowExchangePrice\n ) = IFluidVaultT1(vault_).updateExchangePrices(getVaultVariables2Raw(vault_));\n\n exchangePricesAndRates_.supplyRateLiquidity = liquiditySupplytokenData_.supplyRate;\n exchangePricesAndRates_.borrowRateLiquidity = liquidityBorrowtokenData_.borrowRate;\n exchangePricesAndRates_.supplyRateVault =\n (liquiditySupplytokenData_.supplyRate * configs_.supplyRateMagnifier) /\n 10000;\n exchangePricesAndRates_.borrowRateVault =\n (liquidityBorrowtokenData_.borrowRate * configs_.borrowRateMagnifier) /\n 10000;\n exchangePricesAndRates_.rewardsRate = configs_.supplyRateMagnifier > 10000\n ? configs_.supplyRateMagnifier - 10000\n : 0;\n }\n\n function getTotalSupplyAndBorrow(\n address vault_,\n ExchangePricesAndRates memory exchangePricesAndRates_,\n IFluidVaultT1.ConstantViews memory constantsVariables_\n ) internal view returns (TotalSupplyAndBorrow memory totalSupplyAndBorrow_) {\n uint vaultVariables_ = getVaultVariablesRaw(vault_);\n uint absorbedLiquidity_ = getAbsorbedLiquidityRaw(vault_);\n uint totalSupplyLiquidity_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserSupplySlot);\n // extracting user's supply\n totalSupplyLiquidity_ = (totalSupplyLiquidity_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;\n // converting big number into normal number\n totalSupplyLiquidity_ = (totalSupplyLiquidity_ >> 8) << (totalSupplyLiquidity_ & X8);\n uint totalBorrowLiquidity_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserBorrowSlot);\n // extracting user's borrow\n totalBorrowLiquidity_ = (totalBorrowLiquidity_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64;\n // converting big number into normal number\n totalBorrowLiquidity_ = (totalBorrowLiquidity_ >> 8) << (totalBorrowLiquidity_ & X8);\n\n totalSupplyAndBorrow_.totalSupplyVault = (vaultVariables_ >> 82) & X64;\n // Converting bignumber into normal number\n totalSupplyAndBorrow_.totalSupplyVault =\n (totalSupplyAndBorrow_.totalSupplyVault >> 8) <<\n (totalSupplyAndBorrow_.totalSupplyVault & X8);\n totalSupplyAndBorrow_.totalBorrowVault = (vaultVariables_ >> 146) & X64;\n // Converting bignumber into normal number\n totalSupplyAndBorrow_.totalBorrowVault =\n (totalSupplyAndBorrow_.totalBorrowVault >> 8) <<\n (totalSupplyAndBorrow_.totalBorrowVault & X8);\n\n totalSupplyAndBorrow_.totalSupplyLiquidity = totalSupplyLiquidity_;\n totalSupplyAndBorrow_.totalBorrowLiquidity = totalBorrowLiquidity_;\n\n totalSupplyAndBorrow_.absorbedBorrow = absorbedLiquidity_ & X128;\n totalSupplyAndBorrow_.absorbedSupply = absorbedLiquidity_ >> 128;\n\n // converting raw total supply & total borrow into normal amounts\n totalSupplyAndBorrow_.totalSupplyVault =\n (totalSupplyAndBorrow_.totalSupplyVault * exchangePricesAndRates_.vaultSupplyExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.totalBorrowVault =\n (totalSupplyAndBorrow_.totalBorrowVault * exchangePricesAndRates_.vaultBorrowExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.totalSupplyLiquidity =\n (totalSupplyAndBorrow_.totalSupplyLiquidity * exchangePricesAndRates_.liquiditySupplyExchangePrice) /\n 1e12;\n totalSupplyAndBorrow_.totalBorrowLiquidity =\n (totalSupplyAndBorrow_.totalBorrowLiquidity * exchangePricesAndRates_.liquidityBorrowExchangePrice) /\n 1e12;\n }\n\n function getLimitsAndAvailability(\n TotalSupplyAndBorrow memory totalSupplyAndBorrow_,\n ExchangePricesAndRates memory exchangePricesAndRates_,\n IFluidVaultT1.ConstantViews memory constantsVariables_,\n Configs memory configs_\n ) internal view returns (LimitsAndAvailability memory limitsAndAvailability_) {\n // fetching user's supply slot data\n uint userSupplyLiquidityData_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserSupplySlot);\n uint userBorrowLiquidityData_ = LIQUIDITY.readFromStorage(constantsVariables_.liquidityUserBorrowSlot);\n\n // converting current user's supply from big number to normal\n uint userSupply_ = (userSupplyLiquidityData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;\n userSupply_ = (userSupply_ >> 8) << (userSupply_ & X8);\n\n // fetching liquidity's withdrawal limit\n uint supplyLimitRaw_ = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(userSupplyLiquidityData_, userSupply_);\n\n // converting current user's supply from big number to normal\n uint userBorrow_ = (userBorrowLiquidityData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64;\n userBorrow_ = (userBorrow_ >> 8) << (userBorrow_ & X8);\n\n uint borrowLimitRaw_ = LiquidityCalcs.calcBorrowLimitBeforeOperate(userBorrowLiquidityData_, userBorrow_);\n\n limitsAndAvailability_.withdrawLimit =\n (supplyLimitRaw_ * exchangePricesAndRates_.liquiditySupplyExchangePrice) /\n 1e12;\n limitsAndAvailability_.borrowLimit =\n (borrowLimitRaw_ * exchangePricesAndRates_.liquidityBorrowExchangePrice) /\n 1e12;\n limitsAndAvailability_.borrowableUntilLimit = ((limitsAndAvailability_.borrowLimit * 999999) / 1000000);\n limitsAndAvailability_.borrowableUntilLimit = (limitsAndAvailability_.borrowableUntilLimit >\n totalSupplyAndBorrow_.totalBorrowLiquidity)\n ? limitsAndAvailability_.borrowableUntilLimit - totalSupplyAndBorrow_.totalBorrowLiquidity\n : 0;\n\n uint balanceOf_;\n if (constantsVariables_.borrowToken == NATIVE_TOKEN_ADDRESS) {\n balanceOf_ = address(LIQUIDITY).balance;\n } else {\n balanceOf_ = TokenInterface(constantsVariables_.borrowToken).balanceOf(address(LIQUIDITY));\n }\n limitsAndAvailability_.borrowable = balanceOf_ > limitsAndAvailability_.borrowableUntilLimit\n ? limitsAndAvailability_.borrowableUntilLimit\n : balanceOf_;\n\n limitsAndAvailability_.withdrawableUntilLimit = totalSupplyAndBorrow_.totalSupplyLiquidity >\n limitsAndAvailability_.withdrawLimit\n ? totalSupplyAndBorrow_.totalSupplyLiquidity - limitsAndAvailability_.withdrawLimit\n : 0;\n uint withdrawalGap_ = (totalSupplyAndBorrow_.totalSupplyLiquidity * configs_.withdrawalGap) / 1e4;\n limitsAndAvailability_.withdrawableUntilLimit = (limitsAndAvailability_.withdrawableUntilLimit > withdrawalGap_)\n ? (((limitsAndAvailability_.withdrawableUntilLimit - withdrawalGap_) * 999999) / 1000000)\n : 0;\n\n if (constantsVariables_.supplyToken == NATIVE_TOKEN_ADDRESS) {\n balanceOf_ = address(LIQUIDITY).balance;\n } else {\n balanceOf_ = TokenInterface(constantsVariables_.supplyToken).balanceOf(address(LIQUIDITY));\n }\n limitsAndAvailability_.withdrawable = balanceOf_ > limitsAndAvailability_.withdrawableUntilLimit\n ? limitsAndAvailability_.withdrawableUntilLimit\n : balanceOf_;\n\n limitsAndAvailability_.minimumBorrowing = (10001 * exchangePricesAndRates_.vaultBorrowExchangePrice) / 1e12;\n }\n\n function getVaultState(address vault_) public view returns (VaultState memory vaultState_) {\n uint vaultVariables_ = getVaultVariablesRaw(vault_);\n\n vaultState_.topTick = tickHelper(((vaultVariables_ >> 2) & X20));\n vaultState_.currentBranch = (vaultVariables_ >> 22) & X30;\n vaultState_.totalBranch = (vaultVariables_ >> 52) & X30;\n vaultState_.totalSupply = BigMathMinified.fromBigNumber((vaultVariables_ >> 82) & X64, 8, X8);\n vaultState_.totalBorrow = BigMathMinified.fromBigNumber((vaultVariables_ >> 146) & X64, 8, X8);\n vaultState_.totalPositions = (vaultVariables_ >> 210) & X32;\n\n uint currentBranchData_ = getBranchDataRaw(vault_, vaultState_.currentBranch);\n vaultState_.currentBranchState.status = currentBranchData_ & 3;\n vaultState_.currentBranchState.minimaTick = tickHelper(((currentBranchData_ >> 2) & X20));\n vaultState_.currentBranchState.debtFactor = (currentBranchData_ >> 116) & X50;\n vaultState_.currentBranchState.partials = (currentBranchData_ >> 22) & X30;\n vaultState_.currentBranchState.debtLiquidity = BigMathMinified.fromBigNumber(\n (currentBranchData_ >> 52) & X64,\n 8,\n X8\n );\n vaultState_.currentBranchState.baseBranchId = (currentBranchData_ >> 166) & X30;\n vaultState_.currentBranchState.baseBranchMinima = tickHelper(((currentBranchData_ >> 196) & X20));\n }\n\n function getVaultEntireData(address vault_) public view returns (VaultEntireData memory vaultData_) {\n vaultData_.vault = vault_;\n vaultData_.constantVariables = getVaultConstants(vault_);\n\n (\n LiquidityStructs.UserSupplyData memory liquidityUserSupplyData_,\n LiquidityStructs.OverallTokenData memory liquiditySupplytokenData_\n ) = LIQUIDITY_RESOLVER.getUserSupplyData(vault_, vaultData_.constantVariables.supplyToken);\n\n (\n LiquidityStructs.UserBorrowData memory liquidityUserBorrowData_,\n LiquidityStructs.OverallTokenData memory liquidityBorrowtokenData_\n ) = LIQUIDITY_RESOLVER.getUserBorrowData(vault_, vaultData_.constantVariables.borrowToken);\n\n vaultData_.configs = getVaultConfig(vault_);\n vaultData_.exchangePricesAndRates = getExchangePricesAndRates(\n vault_,\n vaultData_.configs,\n liquiditySupplytokenData_,\n liquidityBorrowtokenData_\n );\n vaultData_.totalSupplyAndBorrow = getTotalSupplyAndBorrow(\n vault_,\n vaultData_.exchangePricesAndRates,\n vaultData_.constantVariables\n );\n vaultData_.limitsAndAvailability = getLimitsAndAvailability(\n vaultData_.totalSupplyAndBorrow,\n vaultData_.exchangePricesAndRates,\n vaultData_.constantVariables,\n vaultData_.configs\n );\n vaultData_.vaultState = getVaultState(vault_);\n\n vaultData_.liquidityUserSupplyData = liquidityUserSupplyData_;\n vaultData_.liquidityUserBorrowData = liquidityUserBorrowData_;\n }\n\n function getVaultsEntireData(\n address[] memory vaults_\n ) external view returns (VaultEntireData[] memory vaultsData_) {\n uint length_ = vaults_.length;\n vaultsData_ = new VaultEntireData[](length_);\n for (uint i = 0; i < length_; i++) {\n vaultsData_[i] = getVaultEntireData(vaults_[i]);\n }\n }\n\n function getVaultsEntireData() external view returns (VaultEntireData[] memory vaultsData_) {\n address[] memory vaults_ = getAllVaultsAddresses();\n uint length_ = vaults_.length;\n vaultsData_ = new VaultEntireData[](length_);\n for (uint i = 0; i < length_; i++) {\n vaultsData_[i] = getVaultEntireData(vaults_[i]);\n }\n }\n\n function positionByNftId(\n uint nftId_\n ) public view returns (UserPosition memory userPosition_, VaultEntireData memory vaultData_) {\n userPosition_.nftId = nftId_;\n address vault_ = vaultByNftId(nftId_);\n\n uint positionData_ = getPositionDataRaw(vault_, nftId_);\n vaultData_ = getVaultEntireData(vault_);\n\n userPosition_.owner = FACTORY.ownerOf(nftId_);\n userPosition_.isSupplyPosition = (positionData_ & 1) == 1;\n userPosition_.supply = (positionData_ >> 45) & X64;\n // Converting big number into normal number\n userPosition_.supply = (userPosition_.supply >> 8) << (userPosition_.supply & X8);\n userPosition_.beforeSupply = userPosition_.supply;\n userPosition_.dustBorrow = (positionData_ >> 109) & X64;\n // Converting big number into normal number\n userPosition_.dustBorrow = (userPosition_.dustBorrow >> 8) << (userPosition_.dustBorrow & X8);\n userPosition_.beforeDustBorrow = userPosition_.dustBorrow;\n if (!userPosition_.isSupplyPosition) {\n userPosition_.tick = (positionData_ & 2) == 2\n ? int((positionData_ >> 2) & X19)\n : -int((positionData_ >> 2) & X19);\n userPosition_.tickId = (positionData_ >> 21) & X24;\n userPosition_.borrow = (TickMath.getRatioAtTick(int24(userPosition_.tick)) * userPosition_.supply) >> 96;\n userPosition_.beforeBorrow = userPosition_.borrow - userPosition_.beforeDustBorrow;\n\n uint tickData_ = getTickDataRaw(vault_, userPosition_.tick);\n\n if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > userPosition_.tickId)) {\n // user got liquidated\n userPosition_.isLiquidated = true;\n (userPosition_.tick, userPosition_.borrow, userPosition_.supply, , ) = IFluidVaultT1(vault_)\n .fetchLatestPosition(userPosition_.tick, userPosition_.tickId, userPosition_.borrow, tickData_);\n }\n\n if (userPosition_.borrow > userPosition_.dustBorrow) {\n userPosition_.borrow = userPosition_.borrow - userPosition_.dustBorrow;\n } else {\n // TODO: Make sure this is right. If borrow is less than dust debt then both gets 0\n userPosition_.borrow = 0;\n userPosition_.dustBorrow = 0;\n }\n }\n\n // converting raw amounts into normal\n userPosition_.beforeSupply =\n (userPosition_.beforeSupply * vaultData_.exchangePricesAndRates.vaultSupplyExchangePrice) /\n 1e12;\n userPosition_.beforeBorrow =\n (userPosition_.beforeBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n userPosition_.beforeDustBorrow =\n (userPosition_.beforeDustBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n userPosition_.supply =\n (userPosition_.supply * vaultData_.exchangePricesAndRates.vaultSupplyExchangePrice) /\n 1e12;\n userPosition_.borrow =\n (userPosition_.borrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n userPosition_.dustBorrow =\n (userPosition_.dustBorrow * vaultData_.exchangePricesAndRates.vaultBorrowExchangePrice) /\n 1e12;\n }\n\n function positionsNftIdOfUser(address user_) public view returns (uint[] memory nftIds_) {\n uint totalPositions_ = FACTORY.balanceOf(user_);\n nftIds_ = new uint[](totalPositions_);\n for (uint i; i < totalPositions_; i++) {\n nftIds_[i] = FACTORY.tokenOfOwnerByIndex(user_, i);\n }\n }\n\n function vaultByNftId(uint nftId_) public view returns (address vault_) {\n uint tokenConfig_ = getTokenConfig(nftId_);\n vault_ = FACTORY.getVaultAddress((tokenConfig_ >> 192) & X32);\n }\n\n function positionsByUser(\n address user_\n ) external view returns (UserPosition[] memory userPositions_, VaultEntireData[] memory vaultsData_) {\n uint[] memory nftIds_ = positionsNftIdOfUser(user_);\n uint length_ = nftIds_.length;\n userPositions_ = new UserPosition[](length_);\n vaultsData_ = new VaultEntireData[](length_);\n address[] memory vaults_ = new address[](length_);\n for (uint i = 0; i < length_; i++) {\n (userPositions_[i], vaultsData_[i]) = positionByNftId(nftIds_[i]);\n }\n }\n\n function totalPositions() external view returns (uint) {\n return FACTORY.totalSupply();\n }\n\n /// @dev fetches available liquidations\n /// @param vault_ address of vault for which to fetch\n /// @param tokenInAmt_ token in aka debt to payback, leave 0 to get max\n /// @return liquidationData_ liquidation related data. Check out structs.sol\n function getVaultLiquidation(\n address vault_,\n uint tokenInAmt_\n ) public returns (LiquidationStruct memory liquidationData_) {\n liquidationData_.vault = vault_;\n IFluidVaultT1.ConstantViews memory constants_ = getVaultConstants(vault_);\n liquidationData_.tokenIn = constants_.borrowToken;\n liquidationData_.tokenOut = constants_.supplyToken;\n\n uint amtOut_;\n uint amtIn_;\n\n tokenInAmt_ = tokenInAmt_ == 0 ? X128 : tokenInAmt_;\n // running without absorb\n try IFluidVaultT1(vault_).liquidate(tokenInAmt_, 0, 0x000000000000000000000000000000000000dEaD, false) {\n // Handle successful execution\n } catch Error(string memory reason) {\n // Handle generic errors with a reason\n } catch (bytes memory lowLevelData_) {\n // Check if the error data is long enough to contain a selector\n if (lowLevelData_.length >= 68) {\n bytes4 errorSelector_;\n assembly {\n // Extract the selector from the error data\n errorSelector_ := mload(add(lowLevelData_, 0x20))\n }\n if (errorSelector_ == IFluidVaultT1.FluidLiquidateResult.selector) {\n assembly {\n amtOut_ := mload(add(lowLevelData_, 36))\n amtIn_ := mload(add(lowLevelData_, 68))\n }\n liquidationData_.tokenOutAmtOne = amtOut_;\n liquidationData_.tokenInAmtOne = amtIn_;\n } else {\n // tokenInAmtOne & tokenOutAmtOne remains 0\n }\n }\n }\n\n // running with absorb\n try IFluidVaultT1(vault_).liquidate(tokenInAmt_, 0, 0x000000000000000000000000000000000000dEaD, true) {\n // Handle successful execution\n } catch Error(string memory reason) {\n // Handle generic errors with a reason\n } catch (bytes memory lowLevelData_) {\n // Check if the error data is long enough to contain a selector\n if (lowLevelData_.length >= 68) {\n bytes4 errorSelector_;\n bytes memory errorData_;\n assembly {\n // Extract the selector from the error data\n errorSelector_ := mload(add(lowLevelData_, 0x20))\n }\n if (errorSelector_ == IFluidVaultT1.FluidLiquidateResult.selector) {\n assembly {\n amtOut_ := mload(add(lowLevelData_, 36))\n amtIn_ := mload(add(lowLevelData_, 68))\n }\n liquidationData_.tokenOutAmtTwo = amtOut_;\n liquidationData_.tokenInAmtTwo = amtIn_;\n } else {\n // tokenInAmtTwo & tokenOutAmtTwo remains 0\n }\n }\n }\n }\n\n function getMultipleVaultsLiquidation(\n address[] memory vaults_,\n uint[] memory tokensInAmt_\n ) external returns (LiquidationStruct[] memory liquidationsData_) {\n uint length_ = vaults_.length;\n liquidationsData_ = new LiquidationStruct[](length_);\n for (uint i = 0; i < length_; i++) {\n liquidationsData_[i] = getVaultLiquidation(vaults_[i], tokensInAmt_[i]);\n }\n }\n\n function getAllVaultsLiquidation() external returns (LiquidationStruct[] memory liquidationsData_) {\n address[] memory vaults_ = getAllVaultsAddresses();\n uint length_ = vaults_.length;\n\n liquidationsData_ = new LiquidationStruct[](length_);\n for (uint i = 0; i < length_; i++) {\n liquidationsData_[i] = getVaultLiquidation(vaults_[i], 0);\n }\n }\n\n // TODO: Need Branch & ticks related data?\n // TODO: Branch history?\n\n constructor(\n address factory_,\n address liquidity_,\n address liquidityResolver_\n ) Helpers(factory_, liquidity_, liquidityResolver_) {}\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vault/structs.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { Structs as FluidLiquidityResolverStructs } from \"../liquidity/structs.sol\";\n\ncontract Structs {\n struct Configs {\n uint16 supplyRateMagnifier;\n uint16 borrowRateMagnifier;\n uint16 collateralFactor;\n uint16 liquidationThreshold;\n uint16 liquidationMaxLimit;\n uint16 withdrawalGap;\n uint16 liquidationPenalty;\n uint16 borrowFee;\n address oracle;\n uint oraclePrice;\n address rebalancer;\n }\n\n struct ExchangePricesAndRates {\n uint lastStoredLiquiditySupplyExchangePrice;\n uint lastStoredLiquidityBorrowExchangePrice;\n uint lastStoredVaultSupplyExchangePrice;\n uint lastStoredVaultBorrowExchangePrice;\n uint liquiditySupplyExchangePrice;\n uint liquidityBorrowExchangePrice;\n uint vaultSupplyExchangePrice;\n uint vaultBorrowExchangePrice;\n uint supplyRateVault;\n uint borrowRateVault;\n uint supplyRateLiquidity;\n uint borrowRateLiquidity;\n uint rewardsRate; // rewards rate in percent 1e2 precision (1% = 100, 100% = 10000)\n }\n\n struct TotalSupplyAndBorrow {\n uint totalSupplyVault;\n uint totalBorrowVault;\n uint totalSupplyLiquidity;\n uint totalBorrowLiquidity;\n uint absorbedSupply;\n uint absorbedBorrow;\n }\n\n struct LimitsAndAvailability {\n uint withdrawLimit;\n uint withdrawableUntilLimit;\n uint withdrawable;\n uint borrowLimit;\n uint borrowableUntilLimit;\n uint borrowable;\n uint minimumBorrowing;\n }\n\n struct CurrentBranchState {\n uint status; // if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed\n int minimaTick;\n uint debtFactor;\n uint partials;\n uint debtLiquidity;\n uint baseBranchId;\n int baseBranchMinima;\n }\n\n struct VaultState {\n uint totalPositions;\n int topTick;\n uint currentBranch;\n uint totalBranch;\n uint totalBorrow;\n uint totalSupply;\n CurrentBranchState currentBranchState;\n }\n\n struct VaultEntireData {\n address vault;\n IFluidVaultT1.ConstantViews constantVariables;\n Configs configs;\n ExchangePricesAndRates exchangePricesAndRates;\n TotalSupplyAndBorrow totalSupplyAndBorrow;\n LimitsAndAvailability limitsAndAvailability;\n VaultState vaultState;\n // liquidity related data such as supply amount, limits, expansion etc.\n FluidLiquidityResolverStructs.UserSupplyData liquidityUserSupplyData;\n // liquidity related data such as borrow amount, limits, expansion etc.\n FluidLiquidityResolverStructs.UserBorrowData liquidityUserBorrowData;\n }\n\n struct UserPosition {\n uint nftId;\n address owner;\n bool isLiquidated;\n bool isSupplyPosition; // if true that means borrowing is 0\n int tick;\n uint tickId;\n uint beforeSupply;\n uint beforeBorrow;\n uint beforeDustBorrow;\n uint supply;\n uint borrow;\n uint dustBorrow;\n }\n\n /// @dev liquidation related data\n /// @param vault address of vault\n /// @param tokenIn_ address of token in\n /// @param tokenOut_ address of token out\n /// @param tokenInAmtOne_ (without absorb liquidity) minimum of available liquidation & tokenInAmt_\n /// @param tokenOutAmtOne_ (without absorb liquidity) expected token out, collateral to withdraw\n /// @param tokenInAmtTwo_ (absorb liquidity included) minimum of available liquidation & tokenInAmt_. In most cases it'll be same as tokenInAmtOne_ but sometimes can be bigger.\n /// @param tokenOutAmtTwo_ (absorb liquidity included) expected token out, collateral to withdraw. In most cases it'll be same as tokenOutAmtOne_ but sometimes can be bigger.\n /// @dev Liquidity in Two will always be >= One. Sometimes One can provide better swaps, sometimes Two can provide better swaps. But available in Two will always be >= One\n struct LiquidationStruct {\n address vault;\n address tokenIn;\n address tokenOut;\n uint tokenInAmtOne;\n uint tokenOutAmtOne;\n uint tokenInAmtTwo;\n uint tokenOutAmtTwo;\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vault/variables.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidLiquidityResolver } from \"../liquidity/iLiquidityResolver.sol\";\nimport { IFluidVaultFactory } from \"../../../protocols/vault/interfaces/iVaultFactory.sol\";\n\ninterface IFluidLiquidity {\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n\ncontract Variables {\n IFluidVaultFactory public immutable FACTORY;\n IFluidLiquidity public immutable LIQUIDITY;\n IFluidLiquidityResolver public immutable LIQUIDITY_RESOLVER;\n\n // 30 bits (used for partials mainly)\n uint internal constant X8 = 0xff;\n uint internal constant X10 = 0x3ff;\n uint internal constant X14 = 0x3fff;\n uint internal constant X15 = 0x7fff;\n uint internal constant X16 = 0xffff;\n uint internal constant X19 = 0x7ffff;\n uint internal constant X20 = 0xfffff;\n uint internal constant X24 = 0xffffff;\n uint internal constant X25 = 0x1ffffff;\n uint internal constant X30 = 0x3fffffff;\n uint internal constant X32 = 0xffffffff;\n uint internal constant X35 = 0x7ffffffff;\n uint internal constant X40 = 0xffffffffff;\n uint internal constant X50 = 0x3ffffffffffff;\n uint internal constant X64 = 0xffffffffffffffff;\n uint internal constant X96 = 0xffffffffffffffffffffffff;\n uint internal constant X128 = 0xffffffffffffffffffffffffffffffff;\n /// @dev address that is mapped to the chain native token\n address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n constructor(address factory_, address liquidity_, address liquidityResolver_) {\n FACTORY = IFluidVaultFactory(factory_);\n LIQUIDITY = IFluidLiquidity(liquidity_);\n LIQUIDITY_RESOLVER = IFluidLiquidityResolver(liquidityResolver_);\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vaultLiquidation/main.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Variables } from \"./variables.sol\";\nimport { Structs } from \"./structs.sol\";\nimport { Structs as VaultResolverStructs } from \"../vault/structs.sol\";\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\n\n/// @notice Resolver contract that helps in finding available token swaps through Fluid Vault liquidations.\ncontract FluidVaultLiquidationResolver is Variables, Structs {\n /// @notice thrown if an input param address is zero\n error FluidVaultLiquidationsResolver__AddressZero();\n /// @notice thrown if an invalid param is given to a method\n error FluidVaultLiquidationsResolver__InvalidParams();\n\n /// @notice constructor sets the immutable vault resolver address\n constructor(IFluidVaultResolver vaultResolver_) Variables(vaultResolver_) {\n if (address(vaultResolver_) == address(0)) {\n revert FluidVaultLiquidationsResolver__AddressZero();\n }\n }\n\n /// @notice returns all token swap pairs available through Fluid Vault Liquidations\n function getAllSwapPairs() public view returns (VaultData[] memory vaultDatas_) {\n address[] memory vaultAddresses_ = VAULT_RESOLVER.getAllVaultsAddresses();\n vaultDatas_ = new VaultData[](vaultAddresses_.length);\n\n IFluidVaultT1.ConstantViews memory constants_;\n for (uint256 i; i < vaultAddresses_.length; ++i) {\n constants_ = IFluidVaultT1(vaultAddresses_[i]).constantsView();\n vaultDatas_[i] = VaultData({\n vault: vaultAddresses_[i],\n tokenIn: constants_.borrowToken,\n tokenOut: constants_.supplyToken\n });\n }\n }\n\n /// @notice returns the vault address for a certain `tokenIn_` swapped to a `tokenOut_`.\n /// returns zero address if no vault is available for a given pair.\n /// @dev for native token, send 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.\n function getVaultForSwap(address tokenIn_, address tokenOut_) public view returns (address vault_) {\n address[] memory vaults_ = VAULT_RESOLVER.getAllVaultsAddresses();\n\n IFluidVaultT1.ConstantViews memory constants_;\n for (uint256 i; i < vaults_.length; ++i) {\n constants_ = IFluidVaultT1(vaults_[i]).constantsView();\n\n if (constants_.borrowToken == tokenIn_ && constants_.supplyToken == tokenOut_) {\n return vaults_[i];\n }\n }\n }\n\n /// @notice returns all available token pair swaps for any `tokensIn_` to any `tokensOut_` with the vault address.\n /// @dev for native token, send 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.\n function getVaultsForSwap(\n address[] calldata tokensIn_,\n address[] calldata tokensOut_\n ) public view returns (VaultData[] memory vaultDatas_) {\n uint256 maxCombinations_ = tokensIn_.length * tokensOut_.length;\n\n VaultData[] memory allVaults_ = new VaultData[](maxCombinations_);\n\n address[] memory vaultAddresses_ = VAULT_RESOLVER.getAllVaultsAddresses();\n\n uint256 matches_;\n uint256 index_;\n\n IFluidVaultT1.ConstantViews memory constants_;\n for (uint256 vi; vi < vaultAddresses_.length; ++vi) {\n constants_ = IFluidVaultT1(vaultAddresses_[vi]).constantsView();\n\n index_ = 0;\n // for each vault, iterate over all possible input params token combinations\n for (uint256 i; i < tokensIn_.length; ++i) {\n for (uint256 j; j < tokensOut_.length; ++j) {\n if (constants_.borrowToken == tokensIn_[i] && constants_.supplyToken == tokensOut_[j]) {\n allVaults_[index_] = VaultData({\n vault: vaultAddresses_[vi],\n tokenIn: tokensIn_[i],\n tokenOut: tokensOut_[j]\n });\n ++matches_;\n }\n ++index_;\n }\n }\n }\n\n vaultDatas_ = new VaultData[](matches_);\n index_ = 0;\n for (uint256 i; i < maxCombinations_; ++i) {\n if (allVaults_[i].vault != address(0)) {\n vaultDatas_[index_] = allVaults_[i];\n ++index_;\n }\n }\n }\n\n /// @notice finds the total available swappable amount for a `tokenIn_` to `tokenOut_` swap, considering both a swap\n /// that uses liquidation with absorb and without absorb. Sometimes with absorb can provide better swaps,\n /// sometimes without absorb can provide better swaps. But available liquidity for \"withAbsorb\" amounts will\n /// always be >= normal amounts.\n /// @dev returned data can be fed into `getSwapCalldata` to prepare the tx that executes the swap.\n /// @dev expected to be called with callStatic, although this method does not do any actual state changes anyway.\n /// @dev for native token, send 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.\n function getSwapAvailable(address tokenIn_, address tokenOut_) public returns (SwapData memory swapData_) {\n return getSwapDataForVault(getVaultForSwap(tokenIn_, tokenOut_));\n }\n\n /// @notice finds the total available swappable amount for any `tokensIn_` to any `tokesnOut_` swap, considering both\n /// a swap that uses liquidation with absorb and without absorb. Sometimes with absorb can provide better swaps,\n /// sometimes without absorb can provide better swaps. But available liquidity for \"withAbsorb\" amounts will\n /// always be >= normal amounts. Token pairs that are not available will not be listed in returned SwapData array.\n /// e.g. for tokensIn_: USDC & USDT and tokensOut_: ETH & wstETH, this would return any available token pair incl.\n /// the available swappable amounts, so for USDC -> ETH, USDC -> wstETH, USDT -> ETH, USDT -> wstETH.\n /// @dev returned data can be fed into `getSwapCalldata` to prepare the tx that executes the swap.\n /// @dev expected to be called with callStatic, although this method does not do any actual state changes anyway.\n /// @dev for native token, send 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.\n function getSwapsAvailable(\n address[] calldata tokensIn_,\n address[] calldata tokensOut_\n ) public returns (SwapData[] memory swapDatas_) {\n VaultData[] memory vaults_ = getVaultsForSwap(tokensIn_, tokensOut_);\n\n swapDatas_ = new SwapData[](vaults_.length);\n\n for (uint256 i; i < vaults_.length; ++i) {\n swapDatas_[i] = getSwapDataForVault(vaults_[i].vault);\n }\n }\n\n /// @notice returns the calldata to execute a swap as found through this contract by triggering a vault liquidation.\n /// `tokenInAmt_` must come from msg.sender, `tokenOutAmt_` goes to `receiver_`. If the input token is the\n /// native token, msg.value must be sent along when triggering the actual call with the returned calldata.\n /// @param vault_ vault address at which the liquidation is executed\n /// @param receiver_ receiver address that the output token is sent to\n /// @param tokenInAmt_ input token amount (debt token at vault)\n /// @param tokenOutAmt_ expected output token amount (collateral token at vault)\n /// @param slippage_ maximum allowed slippage for the expected output token amount. Reverts iIf received token out\n /// amount is lower than this. in 1e4 percentage, e.g. 1% = 10000, 0.3% = 3000, 0.01% = 100, 0.0001% = 1.\n /// @param withAbsorb_ set to true to trigger liquidation with executing `absorb()` first. Liquidity is >= when this\n /// is set to true. Rate can be better with or without, check before via other methods.\n /// @return calldata_ the calldata that can be used to trigger the liquidation call, resulting in the desired swap.\n function getSwapCalldata(\n address vault_,\n address receiver_,\n uint256 tokenInAmt_,\n uint256 tokenOutAmt_,\n uint256 slippage_,\n bool withAbsorb_\n ) public pure returns (bytes memory calldata_) {\n if (vault_ == address(0) || receiver_ == address(0)) {\n revert FluidVaultLiquidationsResolver__AddressZero();\n }\n if (slippage_ >= 1e6 || tokenInAmt_ == 0 || tokenOutAmt_ == 0) {\n revert FluidVaultLiquidationsResolver__InvalidParams();\n }\n\n uint256 colPerUnitDebt_ = (tokenOutAmt_ * 1e18) / tokenInAmt_;\n colPerUnitDebt_ = (colPerUnitDebt_ * (1e6 - slippage_)) / 1e6; // e.g. 50 * 99% / 100% = 49.5\n\n calldata_ = abi.encodeWithSelector(\n IFluidVaultT1(vault_).liquidate.selector,\n tokenInAmt_,\n colPerUnitDebt_,\n receiver_,\n withAbsorb_\n );\n }\n\n /// @notice returns the available swap (liquidation) amounts at a certain `vault_`, considering both\n /// a swap that uses liquidation with absorb and without absorb. Sometimes with absorb can provide better swaps,\n /// sometimes without absorb can provide better swaps. But available liquidity for \"withAbsorb\" amounts will\n /// always be >= normal amounts.\n /// @dev returned data can be fed into `getSwapCalldata` to prepare the tx that executes the swap.\n /// @dev expected to be called with callStatic, although this method does not do any actual state changes anyway.\n function getSwapDataForVault(address vault_) public returns (SwapData memory swapData_) {\n if (vault_ == address(0)) {\n return swapData_;\n }\n\n VaultResolverStructs.LiquidationStruct memory liquidationData_ = VAULT_RESOLVER.getVaultLiquidation(vault_, 0);\n swapData_.vault = vault_;\n swapData_.inAmt = liquidationData_.tokenInAmtOne;\n swapData_.outAmt = liquidationData_.tokenOutAmtOne;\n swapData_.inAmtWithAbsorb = liquidationData_.tokenInAmtTwo;\n swapData_.outAmtWithAbsorb = liquidationData_.tokenOutAmtTwo;\n }\n\n /// @notice finds a swap from `tokenIn_` to `tokenOut_` for an exact input amount `inAmt_`. If available amount is\n /// less then the desired input amount, it returns the available amount. Considers the best rate available\n /// for mode with absorb and mode without absorb.\n /// @dev returned data can be fed into `getSwapCalldata` to prepare the tx that executes the swap.\n /// @param tokenIn_ input token (debt token at vault)\n /// @param tokenOut_ output token (collateral token at vault)\n /// @param inAmt_ exact input token amount that should be swapped to output token\n /// @return vault_ vault address at which the swap is available.\n /// @return actualInAmt_ actual input token amount. Equals `inAmt_`, but if less then the desired swap amount is\n /// available, then the available amount is returned instead.\n /// @return outAmt_ received output token amount for `actualInAmt_` of input token\n /// @return withAbsorb_ flag for using mode \"withAbsorb\". Is set to true if a) liquidity without absorb would not\n /// cover the desired `inAmt_` or if b) the rate of with absorb is better than without absorb.\n function exactInput(\n address tokenIn_,\n address tokenOut_,\n uint256 inAmt_\n ) public returns (address vault_, uint256 actualInAmt_, uint256 outAmt_, bool withAbsorb_) {\n SwapData memory swapData_ = getSwapAvailable(tokenIn_, tokenOut_);\n vault_ = swapData_.vault;\n\n actualInAmt_ = inAmt_; // assume inAmt_ can be covered by available amount, var is updated otherwise\n\n uint256 withAbsorbRatio_ = (swapData_.outAmtWithAbsorb * 1e27) / swapData_.inAmtWithAbsorb;\n if (inAmt_ > swapData_.inAmt && swapData_.inAmtWithAbsorb > swapData_.inAmt) {\n // with absorb has more liquidity \n withAbsorb_ = true;\n if (inAmt_ > swapData_.inAmtWithAbsorb) {\n actualInAmt_ = swapData_.inAmtWithAbsorb; // can not cover full requested inAmt_, so set to available\n outAmt_ = swapData_.outAmtWithAbsorb;\n } else {\n // inAmt_ fully covered by with absorb liquidation, get out amount\n outAmt_ = (inAmt_ * withAbsorbRatio_) / 1e27;\n }\n } else {\n // inAmt_ is covered by available liquidation with or without absorb, check which one has better ratio\n uint256 withoutAbsorbRatio_ = (swapData_.outAmt * 1e27) / swapData_.inAmt;\n if (withAbsorbRatio_ > withoutAbsorbRatio_) {\n withAbsorb_ = true;\n outAmt_ = (inAmt_ * withAbsorbRatio_) / 1e27;\n } else {\n outAmt_ = (inAmt_ * withoutAbsorbRatio_) / 1e27;\n }\n }\n }\n\n /// @notice finds a swap from `tokenIn_` to `tokenOut_` for an exact output amount `outAmt_`. If available amount is\n /// less then the desired output amount, it returns the available amount. Considers the best rate available\n /// for mode with absorb and mode without absorb.\n /// @dev returned data can be fed into `getSwapCalldata` to prepare the tx that executes the swap.\n /// @param tokenIn_ input token (debt token at vault)\n /// @param tokenOut_ output token (collateral token at vault)\n /// @param outAmt_ exact output token amount that should be received as a result of the swap\n /// @return vault_ vault address at which the swap is available.\n /// @return inAmt_ required input token amount to receive `actualOutAmt_` of output token\n /// @return actualOutAmt_ actual output token amount. Equals `outAmt_`, but if less then the desired swap amount is\n /// available, then the available amount is returned instead\n /// @return withAbsorb_ flag for using mode \"withAbsorb\". Is set to true if a) liquidity without absorb would not\n /// cover the desired `outAmt_` or if b) the rate of with absorb is better than without absorb.\n function exactOutput(\n address tokenIn_,\n address tokenOut_,\n uint256 outAmt_\n ) public returns (address vault_, uint256 inAmt_, uint256 actualOutAmt_, bool withAbsorb_) {\n SwapData memory swapData_ = getSwapAvailable(tokenIn_, tokenOut_);\n vault_ = swapData_.vault;\n\n actualOutAmt_ = outAmt_; // assume outAmt_ can be covered by available amount, var is updated otherwise\n\n uint256 withAbsorbRatio_ = (swapData_.inAmtWithAbsorb * 1e27) / swapData_.outAmtWithAbsorb;\n if (outAmt_ > swapData_.outAmt && swapData_.inAmtWithAbsorb > swapData_.inAmt) {\n // with absorb has more liquidity \n withAbsorb_ = true;\n if (outAmt_ > swapData_.outAmtWithAbsorb) {\n actualOutAmt_ = swapData_.outAmtWithAbsorb; // can not cover full requested inAmt_, so set to available\n inAmt_ = swapData_.inAmtWithAbsorb;\n } else {\n // outAmt_ fully covered by with absorb liquidation, get in amount\n inAmt_ = (outAmt_ * withAbsorbRatio_) / 1e27;\n }\n } else {\n // outAmt_ is covered by available liquidation with or without absorb, check which one has better ratio\n uint256 withoutAbsorbRatio_ = (swapData_.inAmt * 1e27) / swapData_.outAmt; // in per out\n if (withAbsorbRatio_ < withoutAbsorbRatio_) {\n withAbsorb_ = true;\n inAmt_ = (outAmt_ * withAbsorbRatio_) / 1e27;\n } else {\n inAmt_ = (outAmt_ * withoutAbsorbRatio_) / 1e27;\n }\n }\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vaultLiquidation/structs.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Structs {\n struct VaultData{\n ///\n /// @param vault vault address at which the token pair is available\n address vault;\n ///\n /// @param tokenIn input token, borrow token at the vault\n address tokenIn;\n ///\n /// @param tokenOut output token, collateral token at the vault\n address tokenOut;\n }\n\n struct SwapData {\n ///\n /// @param vault vault address at which the token pair is available\n address vault;\n ///\n /// @param inAmt total input token available amount (without absorb)\n uint256 inAmt;\n ///\n /// @param outAmt total output token amount received for `inAmt` (without absorb)\n uint256 outAmt;\n ///\n /// @param inAmtWithAbsorb total input token available amount (with absorb)\n uint256 inAmtWithAbsorb;\n ///\n /// @param outAmtWithAbsorb total output token amount received for `inAmtWithAbsorb` (with absorb)\n uint256 outAmtWithAbsorb;\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vaultLiquidation/variables.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\n\ncontract Variables {\n IFluidVaultResolver public immutable VAULT_RESOLVER;\n\n constructor(IFluidVaultResolver vaultResolver_) {\n VAULT_RESOLVER = vaultResolver_;\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vaultPositions/main.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { Variables } from \"./variables.sol\";\nimport { Structs } from \"./structs.sol\";\nimport { IFluidVaultFactory } from \"../../../protocols/vault/interfaces/iVaultFactory.sol\";\nimport { Structs as VaultResolverStructs } from \"../vault/structs.sol\";\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\n\ncontract FluidVaultPositionsResolver is Variables, Structs {\n /// @notice thrown if an input param address is zero\n error FluidVaultPositionsResolver__AddressZero();\n\n /// @notice constructor sets the immutable vault resolver and vault factory address\n constructor(\n IFluidVaultResolver vaultResolver_,\n IFluidVaultFactory vaultFactory_\n ) Variables(vaultResolver_, vaultFactory_) {\n if (address(vaultResolver_) == address(0) || address(vaultFactory_) == address(0)) {\n revert FluidVaultPositionsResolver__AddressZero();\n }\n }\n\n function getAllVaultNftIds(address vault_) public view returns (uint256[] memory nftIds_) {\n uint256 totalPositions_ = FACTORY.totalSupply();\n\n /// get total positions for vault: Next 32 bits => 210-241 => Total positions\n uint256 totalVaultPositions_ = (VAULT_RESOLVER.getVaultVariablesRaw(vault_) >> 210) & 0xFFFFFFFF;\n nftIds_ = new uint256[](totalVaultPositions_);\n\n // get nft Ids belonging to the vault_\n uint256 nftId_;\n uint256 j;\n for (uint256 i; i < totalPositions_; ++i) {\n nftId_ = FACTORY.tokenByIndex(i);\n if (VAULT_RESOLVER.vaultByNftId(nftId_) != vault_) {\n continue;\n }\n nftIds_[j] = nftId_;\n ++j;\n }\n }\n\n function getPositionsForNftIds(uint256[] memory nftIds_) public view returns (UserPosition[] memory positions_) {\n positions_ = new UserPosition[](nftIds_.length);\n\n VaultResolverStructs.UserPosition memory userPosition_;\n for (uint256 i; i < nftIds_.length; ++i) {\n (userPosition_, ) = VAULT_RESOLVER.positionByNftId(nftIds_[i]);\n\n positions_[i].nftId = nftIds_[i];\n positions_[i].owner = userPosition_.owner;\n positions_[i].supply = userPosition_.supply;\n positions_[i].borrow = userPosition_.borrow;\n }\n }\n\n function getAllVaultPositions(address vault_) public view returns (UserPosition[] memory positions_) {\n return getPositionsForNftIds(getAllVaultNftIds(vault_));\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vaultPositions/structs.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Structs {\n struct UserPosition {\n uint nftId;\n address owner;\n uint supply;\n uint borrow;\n }\n}\n"
|
|
},
|
|
"contracts/periphery/resolvers/vaultPositions/variables.sol": {
|
|
"content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\nimport { IFluidVaultFactory } from \"../../../protocols/vault/interfaces/iVaultFactory.sol\";\n\ncontract Variables {\n IFluidVaultResolver public immutable VAULT_RESOLVER;\n IFluidVaultFactory public immutable FACTORY;\n\n constructor(IFluidVaultResolver vaultResolver_, IFluidVaultFactory vaultFactory_) {\n VAULT_RESOLVER = vaultResolver_;\n FACTORY = vaultFactory_;\n }\n}\n"
|
|
},
|
|
"contracts/protocols/vault/interfaces/iVaultFactory.sol": {
|
|
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\nimport { IERC721Enumerable } from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol\";\n\ninterface IFluidVaultFactory is IERC721Enumerable {\n /// @notice Minting an NFT Vault for the user\n function mint(uint256 vaultId_, address user_) external returns (uint256 tokenId_);\n\n /// @notice returns owner of Vault which is also an NFT\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /// @notice Global auth is auth for all vaults\n function isGlobalAuth(address auth_) external view returns (bool);\n\n /// @notice Vault auth is auth for a specific vault\n function isVaultAuth(address vault_, address auth_) external view returns (bool);\n\n /// @notice Total vaults deployed.\n function totalVaults() external view returns (uint256);\n\n /// @notice Compute vaultAddress\n function getVaultAddress(uint256 vaultId) external view returns (address);\n\n /// @notice read uint256 `result_` for a storage `slot_` key\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n}\n"
|
|
},
|
|
"contracts/protocols/vault/interfaces/iVaultT1.sol": {
|
|
"content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidVaultT1 {\n /// @notice returns the vault id\n function VAULT_ID() external view returns (uint256);\n\n /// @notice reads uint256 data `result_` from storage at a bytes32 storage `slot_` key.\n function readFromStorage(bytes32 slot_) external view returns (uint256 result_);\n\n struct ConstantViews {\n address liquidity;\n address factory;\n address adminImplementation;\n address secondaryImplementation;\n address supplyToken;\n address borrowToken;\n uint8 supplyDecimals;\n uint8 borrowDecimals;\n uint vaultId;\n bytes32 liquiditySupplyExchangePriceSlot;\n bytes32 liquidityBorrowExchangePriceSlot;\n bytes32 liquidityUserSupplySlot;\n bytes32 liquidityUserBorrowSlot;\n }\n\n /// @notice returns all Vault constants\n function constantsView() external view returns (ConstantViews memory constantsView_);\n\n /// @notice fetches the latest user position after a liquidation\n function fetchLatestPosition(\n int256 positionTick_,\n uint256 positionTickId_,\n uint256 positionRawDebt_,\n uint256 tickData_\n )\n external\n view\n returns (\n int256, // tick\n uint256, // raw debt\n uint256, // raw collateral\n uint256, // branchID_\n uint256 // branchData_\n );\n\n /// @notice calculates the updated vault exchange prices\n function updateExchangePrices(\n uint256 vaultVariables2_\n )\n external\n view\n returns (\n uint256 liqSupplyExPrice_,\n uint256 liqBorrowExPrice_,\n uint256 vaultSupplyExPrice_,\n uint256 vaultBorrowExPrice_\n );\n\n /// @notice calculates the updated vault exchange prices and writes them to storage\n function updateExchangePricesOnStorage()\n external\n returns (\n uint256 liqSupplyExPrice_,\n uint256 liqBorrowExPrice_,\n uint256 vaultSupplyExPrice_,\n uint256 vaultBorrowExPrice_\n );\n\n /// @notice returns the liquidity contract address\n function LIQUIDITY() external view returns (address);\n\n function operate(\n uint256 nftId_, // if 0 then new position\n int256 newCol_, // if negative then withdraw\n int256 newDebt_, // if negative then payback\n address to_ // address at which the borrow & withdraw amount should go to. If address(0) then it'll go to msg.sender\n )\n external\n payable\n returns (\n uint256, // nftId_\n int256, // final supply amount. if - then withdraw\n int256 // final borrow amount. if - then payback\n );\n \n function liquidate(\n uint256 debtAmt_,\n uint256 colPerUnitDebt_, // min collateral needed per unit of debt in 1e18\n address to_,\n bool absorb_\n ) external payable returns (uint actualDebtAmt_, uint actualColAmt_);\n\n function absorb() external;\n\n function rebalance() external payable returns (int supplyAmt_, int borrowAmt_);\n\n error FluidLiquidateResult(uint256 colLiquidated, uint256 debtLiquidated);\n}\n"
|
|
}
|
|
},
|
|
"settings": {
|
|
"optimizer": {
|
|
"enabled": true,
|
|
"runs": 10000000
|
|
},
|
|
"evmVersion": "paris",
|
|
"outputSelection": {
|
|
"*": {
|
|
"*": [
|
|
"abi",
|
|
"evm.bytecode",
|
|
"evm.deployedBytecode",
|
|
"evm.methodIdentifiers",
|
|
"metadata",
|
|
"devdoc",
|
|
"userdoc",
|
|
"storageLayout",
|
|
"evm.gasEstimates"
|
|
],
|
|
"": [
|
|
"ast"
|
|
]
|
|
}
|
|
},
|
|
"metadata": {
|
|
"useLiteralContent": true
|
|
}
|
|
}
|
|
} |