{ "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/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 // perfect ratio should always be <= ratioX96\n // not sure if it can ever be bigger but better to have extra checks\n if gt(perfectRatioX96, ratioX96) {\n revert(0, 0)\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 /// @param maxUtilization maximum allowed utilization. in 1e2: 100% = 10_000; 1% = 100\n /// set to 100% to disable and have default limit of 100% (avoiding SLOAD).\n uint256 maxUtilization;\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/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 uint256 maxUtilization; // maximum allowed utilization\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; // borrowable amount until any borrow limit (incl. max utilization limit)\n uint256 borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization\n uint256 borrowLimitUtilization; // borrow limit for `maxUtilization`\n }\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 getVaultVariables2Raw(address vault_) external view returns (uint);\n\n function getTickHasDebtRaw(address vault_, int key_) external view returns (uint);\n\n function getTickDataRaw(address vault_, int tick_) external view returns (uint);\n\n function getBranchDataRaw(address vault_, uint branch_) external view returns (uint);\n\n function getPositionDataRaw(address vault_, uint positionId_) 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/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 oraclePriceOperate;\n uint oraclePriceLiquidate;\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; // borrowable amount until any borrow limit (incl. max utilization limit)\n uint borrowable; // actual currently borrowable amount (borrow limit - already borrowed) & considering balance, max utilization\n uint borrowLimitUtilization; // borrow limit for `maxUtilization` config at Liquidity\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 struct AbsorbStruct {\n address vault;\n bool absorbAvailable;\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\";\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\nimport { TickMath } from \"../../../libraries/tickMath.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_; ) {\n nftId_ = FACTORY.tokenByIndex(i);\n unchecked {\n ++i;\n }\n if (_vaultByNftId(nftId_) == vault_) {\n nftIds_[j] = nftId_;\n\n unchecked {\n ++j;\n }\n }\n }\n }\n\n function getPositionsForNftIds(uint256[] memory nftIds_) public view returns (UserPosition[] memory positions_) {\n positions_ = new UserPosition[](nftIds_.length);\n\n for (uint256 i; i < nftIds_.length; ++i) {\n address vault_ = _vaultByNftId(nftIds_[i]);\n if (vault_ == address(0)) {\n // should never happen but make sure it wouldn't lead to a revert\n positions_[i] = UserPosition({ nftId: nftIds_[i], owner: address(0), supply: 0, borrow: 0 });\n } else {\n (, , uint vaultSupplyExchangePrice_, uint vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)\n .updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));\n\n positions_[i] = _getVaultPosition(\n vault_,\n nftIds_[i],\n vaultSupplyExchangePrice_,\n vaultBorrowExchangePrice_\n );\n }\n }\n }\n\n function getAllVaultPositions(address vault_) public view returns (UserPosition[] memory positions_) {\n if (vault_ != address(0)) {\n // exchange prices are always the same for the same vault\n (, , uint vaultSupplyExchangePrice_, uint vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)\n .updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));\n\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 positions_ = new UserPosition[](totalVaultPositions_);\n\n uint256 nftId_;\n uint256 j;\n for (uint256 i; i < totalPositions_; ) {\n nftId_ = FACTORY.tokenByIndex(i);\n unchecked {\n ++i;\n }\n\n if (_vaultByNftId(nftId_) == vault_) {\n positions_[j] = _getVaultPosition(\n vault_,\n nftId_,\n vaultSupplyExchangePrice_,\n vaultBorrowExchangePrice_\n );\n\n unchecked {\n ++j;\n }\n }\n }\n }\n }\n\n function _vaultByNftId(uint nftId_) internal view returns (address vault_) {\n uint tokenConfig_ = FACTORY.readFromStorage(keccak256(abi.encode(nftId_, 3)));\n vault_ = FACTORY.getVaultAddress((tokenConfig_ >> 192) & X32);\n }\n\n function _getVaultPosition(\n address vault_,\n uint nftId_,\n uint vaultSupplyExchangePrice_,\n uint vaultBorrowExchangePrice_\n ) internal view returns (UserPosition memory userPosition_) {\n // @dev code below based on VaultResolver `positionByNftId()`\n userPosition_.nftId = nftId_;\n userPosition_.owner = FACTORY.ownerOf(nftId_);\n\n uint positionData_ = VAULT_RESOLVER.getPositionDataRaw(vault_, nftId_);\n\n userPosition_.supply = (positionData_ >> 45) & X64;\n // Converting big number into normal number\n userPosition_.supply = (userPosition_.supply >> 8) << (userPosition_.supply & X8);\n\n if ((positionData_ & 1) != 1) {\n // not just a supply position\n\n int tick_ = (positionData_ & 2) == 2 ? int((positionData_ >> 2) & X19) : -int((positionData_ >> 2) & X19);\n userPosition_.borrow = (TickMath.getRatioAtTick(int24(tick_)) * userPosition_.supply) >> 96;\n\n uint tickData_ = VAULT_RESOLVER.getTickDataRaw(vault_, tick_);\n uint tickId_ = (positionData_ >> 21) & X24;\n if (((tickData_ & 1) == 1) || (((tickData_ >> 1) & X24) > tickId_)) {\n (tick_, userPosition_.borrow, userPosition_.supply, , ) = IFluidVaultT1(vault_).fetchLatestPosition(\n tick_,\n tickId_,\n userPosition_.borrow,\n tickData_\n );\n }\n\n uint dustBorrow_ = (positionData_ >> 109) & X64;\n // Converting big number into normal number\n dustBorrow_ = (dustBorrow_ >> 8) << (dustBorrow_ & X8);\n\n if (userPosition_.borrow > dustBorrow_) {\n userPosition_.borrow = userPosition_.borrow - 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 }\n\n userPosition_.borrow = (userPosition_.borrow * vaultBorrowExchangePrice_) / 1e12;\n }\n\n userPosition_.supply = (userPosition_.supply * vaultSupplyExchangePrice_) / 1e12;\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 // 30 bits (used for partials mainly)\n uint internal constant X8 = 0xff;\n uint internal constant X19 = 0x7ffff;\n uint internal constant X24 = 0xffffff;\n uint internal constant X32 = 0xffffffff;\n uint internal constant X64 = 0xffffffffffffffff;\n\n constructor(IFluidVaultResolver vaultResolver_, IFluidVaultFactory vaultFactory_) {\n VAULT_RESOLVER = vaultResolver_;\n FACTORY = vaultFactory_;\n }\n}\n" }, "contracts/periphery/resolvers/vaultTicksBranches/main.sol": { "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { TickMath } from \"../../../libraries/tickMath.sol\";\nimport { BigMathMinified } from \"../../../libraries/bigMathMinified.sol\";\nimport { IFluidVaultResolver } from \"../vault/iVaultResolver.sol\";\nimport { IFluidVaultT1 } from \"../../../protocols/vault/interfaces/iVaultT1.sol\";\n\nimport { Structs } from \"./structs.sol\";\nimport { Variables } from \"./variables.sol\";\n\n/// @notice Fluid Vault protocol ticks & branches resolver\ncontract FluidVaultTicksBranchesResolver is Variables, Structs {\n /// @notice thrown if an input param address is zero\n error FluidVaultTicksBranchesResolver__AddressZero();\n\n /// @notice constructor sets the immutable vault resolver address\n constructor(IFluidVaultResolver vaultResolver_) Variables(vaultResolver_) {\n if (address(vaultResolver_) == address(0)) {\n revert FluidVaultTicksBranchesResolver__AddressZero();\n }\n }\n\n function getTicksDebt(\n address vault_,\n int fromTick_,\n uint totalTicks_\n ) public view returns (TickDebt[] memory ticksDebt_, int toTick_) {\n int topTick_ = _tickHelper(((VAULT_RESOLVER.getVaultVariablesRaw(vault_) >> 2) & X20));\n\n fromTick_ = topTick_ < fromTick_ ? topTick_ : fromTick_;\n if (fromTick_ > type(int).min) {\n // if fromTick_ == tpye(int).min means top tick is not set, meaning no positions exist\n int startMapId_ = fromTick_ < 0 ? ((fromTick_ + 1) / 256) - 1 : fromTick_ / 256;\n // Removing all other after fromTick\n uint tickHasDebt_;\n {\n uint tickHasDebtRaw_ = VAULT_RESOLVER.getTickHasDebtRaw(vault_, startMapId_);\n\n uint bitsToRemove_ = uint(-fromTick_ + (startMapId_ * 256 + 255));\n tickHasDebt_ = (tickHasDebtRaw_ << bitsToRemove_) >> bitsToRemove_;\n }\n\n // Adding 1 here as toTick_ is inclusive in the data so if totalTicks_ = 400 then it'll only check 400\n toTick_ = fromTick_ - int(totalTicks_) + 1;\n\n uint count_ = _countTicksWithDebt(vault_, toTick_, startMapId_, tickHasDebt_);\n\n (, , uint vaultSupplyExchangePrice_, uint vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)\n .updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));\n\n ticksDebt_ = _populateTicksDebt(\n vault_,\n toTick_,\n startMapId_,\n tickHasDebt_,\n count_,\n vaultSupplyExchangePrice_,\n vaultBorrowExchangePrice_\n );\n }\n }\n\n function getMultipleVaultsTicksDebt(\n address[] memory vaults_,\n int[] memory fromTicks_,\n uint[] memory totalTicks_\n ) public view returns (VaultsTickDebt[] memory vaultsTickDebt_) {\n uint length_ = vaults_.length;\n\n vaultsTickDebt_ = new VaultsTickDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n (vaultsTickDebt_[i].tickDebt, vaultsTickDebt_[i].toTick) = getTicksDebt(\n vaults_[i],\n fromTicks_[i],\n totalTicks_[i]\n );\n }\n }\n\n function getAllVaultsTicksDebt(uint totalTicks_) public view returns (VaultsTickDebt[] memory vaultsTickDebt_) {\n address[] memory vaults_ = VAULT_RESOLVER.getAllVaultsAddresses();\n uint length_ = vaults_.length;\n\n vaultsTickDebt_ = new VaultsTickDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n (vaultsTickDebt_[i].tickDebt, vaultsTickDebt_[i].toTick) = getTicksDebt(\n vaults_[i],\n type(int).max,\n totalTicks_\n );\n }\n }\n\n function getBranchesDebt(\n address vault_,\n uint fromBranchId_,\n uint toBranchId_\n ) public view returns (BranchDebt[] memory branchesDebt_) {\n uint vaultVariables_ = VAULT_RESOLVER.getVaultVariablesRaw(vault_);\n uint totalBranch_ = (vaultVariables_ >> 52) & X30;\n toBranchId_ = (toBranchId_ == 0 ? 1 : toBranchId_);\n fromBranchId_ = (totalBranch_ < fromBranchId_ ? totalBranch_ : fromBranchId_);\n\n require(fromBranchId_ >= toBranchId_, \"fromBranchId_ must be greater than or equal to toBranchId_\");\n\n branchesDebt_ = new BranchDebt[](fromBranchId_ - toBranchId_ + 1);\n\n uint index_;\n\n for (uint i = fromBranchId_; i >= toBranchId_; i--) {\n branchesDebt_[index_++] = _getBranchDebt(vault_, vaultVariables_, i);\n }\n }\n\n function getMultipleVaultsBranchesDebt(\n address[] memory vaults_,\n uint[] memory fromBranchIds_,\n uint[] memory toBranchIds_\n ) external view returns (BranchesDebt[] memory branchesDebt_) {\n uint length_ = vaults_.length;\n\n branchesDebt_ = new BranchesDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n branchesDebt_[i].branchDebt = getBranchesDebt(vaults_[i], fromBranchIds_[i], toBranchIds_[i]);\n }\n }\n\n function getAllVaultsBranchesDebt() external view returns (BranchesDebt[] memory branchesDebt_) {\n address[] memory vaults_ = VAULT_RESOLVER.getAllVaultsAddresses();\n uint length_ = vaults_.length;\n\n branchesDebt_ = new BranchesDebt[](length_);\n for (uint i = 0; i < length_; i++) {\n branchesDebt_[i].branchDebt = getBranchesDebt(vaults_[i], type(uint).max, 0);\n }\n }\n\n function _populateTicksDebt(\n address vault_,\n int toTick_,\n int mapId_,\n uint tickHasDebt_,\n uint count_,\n uint vaultSupplyExchangePrice_,\n uint vaultBorrowExchangePrice_\n ) internal view returns (TickDebt[] memory ticksDebt_) {\n ticksDebt_ = new TickDebt[](count_);\n\n count_ = 0; // reuse var for loop index counter\n int nextTick_;\n uint tickExistingRawDebt_;\n uint ratio_;\n uint collateralRaw_;\n\n while (true) {\n while (tickHasDebt_ > 0) {\n {\n uint msb_ = BigMathMinified.mostSignificantBit(tickHasDebt_);\n // removing next tick from tickHasDebt\n tickHasDebt_ = (tickHasDebt_ << (257 - msb_)) >> (257 - msb_);\n nextTick_ = mapId_ * 256 + int(msb_ - 1);\n }\n if (nextTick_ < toTick_) {\n return ticksDebt_;\n }\n tickExistingRawDebt_ = (VAULT_RESOLVER.getTickDataRaw(vault_, nextTick_) >> 25) & X64;\n tickExistingRawDebt_ = (tickExistingRawDebt_ >> 8) << (tickExistingRawDebt_ & X8);\n ratio_ = TickMath.getRatioAtTick(nextTick_);\n collateralRaw_ = (tickExistingRawDebt_ * (1 << 96)) / ratio_;\n ticksDebt_[count_++] = TickDebt({\n debtRaw: tickExistingRawDebt_,\n collateralRaw: collateralRaw_,\n debtNormal: (tickExistingRawDebt_ * vaultBorrowExchangePrice_) / 1e12,\n collateralNormal: (collateralRaw_ * vaultSupplyExchangePrice_) / 1e12,\n ratio: ratio_,\n tick: nextTick_\n });\n }\n\n if (--mapId_ == -129) {\n break;\n }\n\n tickHasDebt_ = VAULT_RESOLVER.getTickHasDebtRaw(vault_, mapId_);\n }\n }\n\n function _tickHelper(uint tickRaw_) internal 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 function _countTicksWithDebt(\n address vault_,\n int toTick_,\n int mapId_,\n uint tickHasDebt_\n ) internal view returns (uint count_) {\n uint msb_;\n int nextTick_;\n while (true) {\n while (tickHasDebt_ > 0) {\n msb_ = BigMathMinified.mostSignificantBit(tickHasDebt_);\n // removing next tick from tickHasDebt\n tickHasDebt_ = (tickHasDebt_ << (257 - msb_)) >> (257 - msb_);\n nextTick_ = mapId_ * 256 + int(msb_ - 1);\n if (nextTick_ < toTick_) {\n return count_;\n }\n count_++;\n }\n\n if (--mapId_ == -129) {\n break;\n }\n tickHasDebt_ = VAULT_RESOLVER.getTickHasDebtRaw(vault_, mapId_);\n }\n return count_;\n }\n\n function _getBranchDebt(\n address vault_,\n uint vaultVariables_,\n uint branchId_\n ) internal view returns (BranchDebt memory) {\n uint currentBranchData_ = VAULT_RESOLVER.getBranchDataRaw(vault_, branchId_);\n\n int minimaTick_ = _tickHelper((currentBranchData_ >> 2) & X20);\n uint status_ = currentBranchData_ & 3;\n\n if (status_ == 0) {\n // not liquidated status == 0\n // only current branch can be non-liquidated branch\n return _getActiveBranchDebt(vaultVariables_, currentBranchData_, branchId_, status_);\n } else if (status_ == 1) {\n // liquidated status == 1\n return _getLiquidatedBranchDebt(vault_, currentBranchData_, branchId_, status_, minimaTick_);\n } else {\n // merged status == 2\n // absorbed status == 3\n return _getClosedOrMergedBranchDebt(currentBranchData_, branchId_, status_);\n }\n }\n\n function _getActiveBranchDebt(\n uint vaultVariables_,\n uint currentBranchData_,\n uint branchId_,\n uint status_\n ) internal pure returns (BranchDebt memory branchDebt_) {\n int topTick_ = _tickHelper((vaultVariables_ >> 2) & X20);\n\n uint ratio_ = topTick_ > type(int).min ? TickMath.getRatioAtTick(topTick_) : 0;\n\n branchDebt_ = BranchDebt({\n debtRaw: 0,\n collateralRaw: 0,\n debtNormal: 0,\n collateralNormal: 0,\n branchId: branchId_,\n status: status_, // active status\n tick: topTick_, // as branch is not liquidated, just returning topTick for now, as whenever liquidation starts it'll start from topTick\n partials: 0,\n ratio: ratio_,\n debtFactor: (currentBranchData_ >> 116) & X50,\n baseBranchId: ((currentBranchData_ >> 166) & X30),\n baseBranchTick: _tickHelper((currentBranchData_ >> 196) & X20) // if == type(int).min, then current branch is master branch\n });\n }\n\n function _getClosedOrMergedBranchDebt(\n uint currentBranchData_,\n uint branchId_,\n uint status_\n ) internal pure returns (BranchDebt memory branchDebt_) {\n int baseBranchTick_ = _tickHelper((currentBranchData_ >> 196) & X20);\n uint ratio_ = baseBranchTick_ > type(int).min ? TickMath.getRatioAtTick(baseBranchTick_) : 0;\n\n branchDebt_ = BranchDebt({\n debtRaw: 0,\n collateralRaw: 0,\n debtNormal: 0,\n collateralNormal: 0,\n branchId: branchId_,\n status: status_,\n tick: baseBranchTick_, // as branch is merged/closed, so adding baseBranchTick_ as this is where it went out of existance\n partials: 0,\n ratio: ratio_,\n debtFactor: (currentBranchData_ >> 116) & X50,\n baseBranchId: ((currentBranchData_ >> 166) & X30),\n baseBranchTick: baseBranchTick_ // if == type(int).min, then current branch is master branch\n });\n }\n\n function _getLiquidatedBranchDebt(\n address vault_,\n uint currentBranchData_,\n uint branchId_,\n uint status_,\n int minimaTick_\n ) internal view returns (BranchDebt memory branchDebt_) {\n uint debtLiquidity_ = BigMathMinified.fromBigNumber((currentBranchData_ >> 52) & X64, 8, X8);\n (uint collateralRaw_, uint ratio_) = _getCollateralRaw(currentBranchData_, debtLiquidity_, minimaTick_);\n\n (, , uint256 vaultSupplyExchangePrice_, uint256 vaultBorrowExchangePrice_) = IFluidVaultT1(vault_)\n .updateExchangePrices(VAULT_RESOLVER.getVaultVariables2Raw(vault_));\n\n branchDebt_ = BranchDebt({\n debtRaw: debtLiquidity_,\n collateralRaw: collateralRaw_,\n debtNormal: (debtLiquidity_ * vaultBorrowExchangePrice_) / 1e12,\n collateralNormal: (collateralRaw_ * vaultSupplyExchangePrice_) / 1e12,\n branchId: branchId_,\n status: status_,\n tick: minimaTick_, // as branch is merged/closed, so adding baseBranchTick_ as this is where it went out of existance\n partials: 0,\n ratio: ratio_,\n debtFactor: (currentBranchData_ >> 116) & X50,\n baseBranchId: ((currentBranchData_ >> 166) & X30),\n baseBranchTick: _tickHelper((currentBranchData_ >> 196) & X20) // if == type(int).min, then current branch is master branch\n });\n }\n\n function _getCollateralRaw(\n uint currentBranchData_,\n uint debtLiquidity_,\n int minimaTick_\n ) internal pure returns (uint collateralRaw_, uint ratio_) {\n ratio_ = TickMath.getRatioAtTick(int24(minimaTick_));\n uint ratioOneLess_ = (ratio_ * 10000) / 10015;\n uint length_ = ratio_ - ratioOneLess_;\n uint partials_ = (currentBranchData_ >> 22) & X30;\n uint currentRatio_ = ratioOneLess_ + ((length_ * partials_) / X30);\n collateralRaw_ = (debtLiquidity_ * TickMath.ZERO_TICK_SCALED_RATIO) / currentRatio_;\n }\n}\n" }, "contracts/periphery/resolvers/vaultTicksBranches/structs.sol": { "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Structs {\n struct TickDebt {\n uint256 debtRaw;\n uint256 collateralRaw;\n uint256 debtNormal; // debtRaw * exchange price\n uint256 collateralNormal; // collateralRaw * exchange price\n uint256 ratio;\n int256 tick;\n }\n\n struct VaultsTickDebt {\n TickDebt[] tickDebt;\n int toTick;\n }\n\n struct BranchDebt {\n uint256 debtRaw;\n uint256 collateralRaw;\n uint256 debtNormal; // debtRaw * exchange price\n uint256 collateralNormal; // collateralRaw * exchange price\n uint256 branchId;\n uint256 status; // if 0 then not liquidated, if 1 then liquidated, if 2 then merged, if 3 then closed\n int256 tick;\n uint256 partials;\n uint256 ratio;\n uint debtFactor; // debt factor or connection factor\n uint baseBranchId;\n int baseBranchTick;\n }\n\n struct BranchesDebt {\n BranchDebt[] branchDebt;\n }\n}\n" }, "contracts/periphery/resolvers/vaultTicksBranches/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 uint internal constant X8 = 0xff;\n uint internal constant X19 = 0x7ffff;\n uint internal constant X20 = 0xfffff;\n uint internal constant X30 = 0x3fffffff;\n uint internal constant X50 = 0x3ffffffffffff;\n uint internal constant X64 = 0xffffffffffffffff;\n\n constructor(IFluidVaultResolver vaultResolver_) {\n VAULT_RESOLVER = vaultResolver_;\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 } } }