{ "address": "0xe71313Dd1F00afef64A0D20e940603741316eDD7", "abi": [ { "inputs": [ { "internalType": "uint256", "name": "errorId_", "type": "uint256" } ], "name": "FluidLiquidityCalcsError", "type": "error" }, { "inputs": [ { "internalType": "uint256", "name": "errorId_", "type": "uint256" } ], "name": "FluidLiquidityError", "type": "error" }, { "anonymous": false, "inputs": [], "name": "BorrowRateMaxCap", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, { "indexed": true, "internalType": "address", "name": "token", "type": "address" }, { "indexed": false, "internalType": "int256", "name": "supplyAmount", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "borrowAmount", "type": "int256" }, { "indexed": false, "internalType": "address", "name": "withdrawTo", "type": "address" }, { "indexed": false, "internalType": "address", "name": "borrowTo", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "totalAmounts", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "exchangePricesAndConfig", "type": "uint256" } ], "name": "LogOperate", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "token_", "type": "address" }, { "internalType": "int256", "name": "supplyAmount_", "type": "int256" }, { "internalType": "int256", "name": "borrowAmount_", "type": "int256" }, { "internalType": "address", "name": "withdrawTo_", "type": "address" }, { "internalType": "address", "name": "borrowTo_", "type": "address" }, { "internalType": "bytes", "name": "callbackData_", "type": "bytes" } ], "name": "operate", "outputs": [ { "internalType": "uint256", "name": "memVar3_", "type": "uint256" }, { "internalType": "uint256", "name": "memVar4_", "type": "uint256" } ], "stateMutability": "payable", "type": "function" } ], "transactionHash": "0x6edcf57a80fb0be92c7ba16ab6b72495859e8888259a193f1a27ec20be7baad7", "receipt": { "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C", "from": "0x0Ed35B1609Ec45c7079E80d11149a52717e4859A", "contractAddress": null, "transactionIndex": 4, "gasUsed": "3206510", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "blockHash": "0x10ee29403f3f6280dec656bb09847b134a0a25bdd499b43346d1dd879de02bfb", "transactionHash": "0x6edcf57a80fb0be92c7ba16ab6b72495859e8888259a193f1a27ec20be7baad7", "logs": [], "blockNumber": 220375168, "cumulativeGasUsed": "6230172", "status": 1, "byzantium": true }, "args": [], "numDeployments": 1, "solcInputHash": "1989963ad64c4704dbe1170530c79d20", "metadata": "{\"compiler\":{\"version\":\"0.8.21+commit.d9974bed\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errorId_\",\"type\":\"uint256\"}],\"name\":\"FluidLiquidityCalcsError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"errorId_\",\"type\":\"uint256\"}],\"name\":\"FluidLiquidityError\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"BorrowRateMaxCap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"supplyAmount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"borrowAmount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"withdrawTo\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrowTo\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"totalAmounts\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"exchangePricesAndConfig\",\"type\":\"uint256\"}],\"name\":\"LogOperate\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token_\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"supplyAmount_\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"borrowAmount_\",\"type\":\"int256\"},{\"internalType\":\"address\",\"name\":\"withdrawTo_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrowTo_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callbackData_\",\"type\":\"bytes\"}],\"name\":\"operate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"memVar3_\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"memVar4_\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"For view methods / accessing data, use the \\\"LiquidityResolver\\\" periphery contract.\",\"events\":{\"LogOperate(address,address,int256,int256,address,address,uint256,uint256)\":{\"params\":{\"borrowAmount\":\"borrow amount for the operation. if >0 then a borrow happened, if <0 then a payback happened. if 0 then nothing.\",\"borrowTo\":\"address that funds where borrowed to (if borrowAmount >0)\",\"exchangePricesAndConfig\":\"updated exchange prices and configs storage slot. Contains updated supply & borrow exchange price: First 16 bits => 0- 15 => borrow rate (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535) Next 14 bits => 16- 29 => fee on interest from borrowers to lenders (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable. Next 14 bits => 30- 43 => last stored utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383) Next 14 bits => 44- 57 => update on storage threshold (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable. Next 33 bits => 58- 90 => last update timestamp (enough until 16 March 2242 -> max value 8589934591) Next 64 bits => 91-154 => supply exchange price (1e12 -> max value 18_446_744,073709551615) Next 64 bits => 155-218 => borrow exchange price (1e12 -> max value 18_446_744,073709551615) Next 1 bit => 219-219 => if 0 then ratio is supplyInterestFree / supplyWithInterest else ratio is supplyWithInterest / supplyInterestFree Next 14 bits => 220-233 => supplyRatio: supplyInterestFree / supplyWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383) Next 1 bit => 234-234 => if 0 then ratio is borrowInterestFree / borrowWithInterest else ratio is borrowWithInterest / borrowInterestFree Next 14 bits => 235-248 => borrowRatio: borrowInterestFree / borrowWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\",\"supplyAmount\":\"supply amount for the operation. if >0 then a deposit happened, if <0 then a withdrawal happened. if 0 then nothing.\",\"token\":\"token address for which this operation was executed\",\"totalAmounts\":\"updated total amounts, stacked uint256 as written to storage: First 64 bits => 0- 63 => total supply with interest in raw (totalSupply = totalSupplyRaw * supplyExchangePrice); BigMath: 56 | 8 Next 64 bits => 64-127 => total interest free supply in normal token amount (totalSupply = totalSupply); BigMath: 56 | 8 Next 64 bits => 128-191 => total borrow with interest in raw (totalBorrow = totalBorrowRaw * borrowExchangePrice); BigMath: 56 | 8 Next 64 bits => 192-255 => total interest free borrow in normal token amount (totalBorrow = totalBorrow); BigMath: 56 | 8\",\"user\":\"protocol that triggered this operation (e.g. via an fToken or via Vault protocol)\",\"withdrawTo\":\"address that funds where withdrawn to (if supplyAmount <0)\"}}},\"kind\":\"dev\",\"methods\":{},\"title\":\"Fluid Liquidity UserModule\",\"version\":1},\"userdoc\":{\"events\":{\"BorrowRateMaxCap()\":{\"notice\":\"emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535\"},\"LogOperate(address,address,int256,int256,address,address,uint256,uint256)\":{\"notice\":\"emitted on any `operate()` execution: deposit / supply / withdraw / borrow. includes info related to the executed operation, new total amounts (packed uint256 of BigMath numbers as in storage) and exchange prices (packed uint256 as in storage).\"}},\"kind\":\"user\",\"methods\":{\"operate(address,int256,int256,address,address,bytes)\":{\"notice\":\"inheritdoc IFluidLiquidity\"}},\"notice\":\"Fluid Liquidity public facing endpoint logic contract that implements the `operate()` method. operate can be used to deposit, withdraw, borrow & payback funds, given that they have the necessary user config allowance. Interacting users must be allowed via the Fluid Liquidity AdminModule first. Intended users are thus allow-listed protocols, e.g. the Lending protocol (fTokens), Vault protocol etc.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/liquidity/userModule/main.sol\":\"FluidLiquidityUserModule\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../token/ERC20/IERC20.sol\\\";\\n\",\"keccak256\":\"0x6ebf1944ab804b8660eb6fc52f9fe84588cee01c2566a69023e59497e7d27f45\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../extensions/draft-IERC20Permit.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n }\\n\\n /**\\n * @dev Deprecated. This function has issues similar to the ones found in\\n * {IERC20-approve}, and its usage is discouraged.\\n *\\n * Whenever possible, use {safeIncreaseAllowance} and\\n * {safeDecreaseAllowance} instead.\\n */\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender) + value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n unchecked {\\n uint256 oldAllowance = token.allowance(address(this), spender);\\n require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n uint256 newAllowance = oldAllowance - value;\\n _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n }\\n }\\n\\n function safePermit(\\n IERC20Permit token,\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal {\\n uint256 nonceBefore = token.nonces(owner);\\n token.permit(owner, spender, value, deadline, v, r, s);\\n uint256 nonceAfter = token.nonces(owner);\\n require(nonceAfter == nonceBefore + 1, \\\"SafeERC20: permit did not succeed\\\");\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n if (returndata.length > 0) {\\n // Return data is optional\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x9b72f93be69ca894d8492c244259615c4a742afc8d63720dbc8bb81087d9b238\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"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\",\"keccak256\":\"0xf0be1002909edf30aec3dc6623c2bd2407ed94064b62674c01032b844dec206a\",\"license\":\"BUSL-1.1\"},\"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 /// @notice thrown when the calculated borrow rate turns negative. This should never happen.\\n uint256 internal constant LiquidityCalcs__BorrowRateNegative = 70003;\\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\",\"keccak256\":\"0xaf7732f30d00dd38082d37aa37887be485fc94b0c76ff302aff615d03381674f\",\"license\":\"BUSL-1.1\"},\"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 update 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 also be negative for declining rates)\\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 int256 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)\\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\\n slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((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) - (slope_ * int256(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 slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings\\n if (slope_ < 0) {\\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);\\n }\\n rate_ = uint256(slope_) / 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 also be negative for declining rates)\\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 int256 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)\\n // y is in 1e2 so can not overflow when multiplied with TWELVE_DECIMALS\\n slope_ = (int256(y2_ - y1_) * int256(TWELVE_DECIMALS)) / int256((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) - (slope_ * int256(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 slope_ = (slope_ * int256(utilization_)) + constant_; // reusing `slope_` as variable for gas savings\\n if (slope_ < 0) {\\n revert FluidLiquidityCalcsError(ErrorTypes.LiquidityCalcs__BorrowRateNegative);\\n }\\n rate_ = uint256(slope_) / 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\",\"keccak256\":\"0xa65e2f84b2c33769ceb6b28fbd3221be29da2f8ac96e4d8b8cea91948d81a707\",\"license\":\"BUSL-1.1\"},\"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 /// @dev storage slot for listed tokens array at Liquidity\\n uint256 internal constant LIQUIDITY_CONFIGS2_MAPPING_SLOT = 11;\\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 uint256 internal constant BITS_EXCHANGE_PRICES_USES_CONFIGS2 = 249;\\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 // Configs2\\n uint256 internal constant BITS_CONFIGS2_MAX_UTILIZATION = 0;\\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\",\"keccak256\":\"0x0ae3e1d231bb6c14b54fc1f5ffa306edc0ac827a6a92279c77c0c09627fe08ae\",\"license\":\"BUSL-1.1\"},\"contracts/liquidity/common/helpers.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.21;\\n\\nimport { Variables } from \\\"./variables.sol\\\";\\nimport { ErrorTypes } from \\\"../errorTypes.sol\\\";\\nimport { Error } from \\\"../error.sol\\\";\\n\\n/// @dev ReentrancyGuard based on OpenZeppelin implementation.\\n/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.8/contracts/security/ReentrancyGuard.sol\\nabstract contract ReentrancyGuard is Variables, Error {\\n uint8 internal constant REENTRANCY_NOT_ENTERED = 1;\\n uint8 internal constant REENTRANCY_ENTERED = 2;\\n\\n constructor() {\\n // on logic contracts, switch reentrancy to entered so no call is possible (forces delegatecall)\\n _status = REENTRANCY_ENTERED; \\n }\\n\\n /// @dev Prevents a contract from calling itself, directly or indirectly.\\n /// See OpenZeppelin implementation for more info\\n modifier reentrancy() {\\n // On the first call to nonReentrant, _status will be NOT_ENTERED\\n if (_status == REENTRANCY_ENTERED) {\\n revert FluidLiquidityError(ErrorTypes.LiquidityHelpers__Reentrancy);\\n }\\n\\n // Any calls to nonReentrant after this point will fail\\n _status = REENTRANCY_ENTERED;\\n\\n _;\\n\\n // By storing the original value once again, a refund is triggered (see\\n // https://eips.ethereum.org/EIPS/eip-2200)\\n _status = REENTRANCY_NOT_ENTERED;\\n }\\n}\\n\\nabstract contract CommonHelpers is ReentrancyGuard {\\n /// @dev Returns the current admin (governance).\\n function _getGovernanceAddr() internal view returns (address governance_) {\\n assembly {\\n governance_ := sload(GOVERNANCE_SLOT)\\n }\\n }\\n}\\n\",\"keccak256\":\"0x0818447e79488c3da0fde292ae7219cf2a819951ad5d4456fb297082e5e83a9b\",\"license\":\"BUSL-1.1\"},\"contracts/liquidity/common/variables.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.21;\\n\\ncontract ConstantVariables {\\n /// @dev Storage slot with the admin of the contract. Logic from \\\"proxy.sol\\\".\\n /// This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is validated in the constructor.\\n bytes32 internal constant GOVERNANCE_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n uint256 internal constant EXCHANGE_PRICES_PRECISION = 1e12;\\n\\n /// @dev address that is mapped to the chain native token\\n address internal constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\\n /// @dev limit for triggering a revert if sent along excess `msg.value` is bigger than this amount\\n uint256 internal constant NATIVE_AMOUNT_EXCESS_LIMIT = 1e9;\\n /// @dev decimals for native token\\n // !! Double check compatibility with all code if this ever changes for a deployment !!\\n uint8 internal constant NATIVE_TOKEN_DECIMALS = 18;\\n\\n /// @dev Minimum token decimals for any token that can be listed at Liquidity (inclusive)\\n uint8 internal constant MIN_TOKEN_DECIMALS = 6;\\n /// @dev Maximum token decimals for any token that can be listed at Liquidity (inclusive)\\n uint8 internal constant MAX_TOKEN_DECIMALS = 18;\\n\\n /// @dev Ignoring leap years\\n uint256 internal constant SECONDS_PER_YEAR = 365 days;\\n\\n /// @dev limit any total amount to be half of type(uint128).max (~3.4e38) at type(int128).max (~1.7e38) as safety\\n /// measure for any potential overflows / unexpected outcomes. This is checked for total borrow / supply.\\n uint256 internal constant MAX_TOKEN_AMOUNT_CAP = uint256(uint128(type(int128).max));\\n\\n /// @dev time after which a write to storage of exchangePricesAndConfig will happen always.\\n uint256 internal constant FORCE_STORAGE_WRITE_AFTER_TIME = 1 days;\\n\\n /// @dev constants used for BigMath conversion from and to storage\\n uint256 internal constant SMALL_COEFFICIENT_SIZE = 10;\\n uint256 internal constant DEFAULT_COEFFICIENT_SIZE = 56;\\n uint256 internal constant DEFAULT_EXPONENT_SIZE = 8;\\n uint256 internal constant DEFAULT_EXPONENT_MASK = 0xFF;\\n\\n /// @dev constants to increase readability for using bit masks\\n uint256 internal constant FOUR_DECIMALS = 1e4;\\n uint256 internal constant TWELVE_DECIMALS = 1e12;\\n uint256 internal constant X8 = 0xff;\\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\\ncontract Variables is ConstantVariables {\\n /// @dev address of contract that gets sent the revenue. Configurable by governance\\n address internal _revenueCollector;\\n\\n // 12 bytes empty\\n\\n // ----- storage slot 1 ------\\n\\n /// @dev paused status: status = 1 -> normal. status = 2 -> paused.\\n /// not tightly packed with revenueCollector address to allow for potential changes later that improve gas more\\n /// (revenueCollector is only rarely used by admin methods, where optimization is not as important).\\n /// to be replaced with transient storage once EIP-1153 Transient storage becomes available with dencun upgrade.\\n uint256 internal _status;\\n\\n // ----- storage slot 2 ------\\n\\n /// @dev 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.\\n /// Governance is auth by default\\n mapping(address => uint256) internal _isAuth;\\n\\n // ----- storage slot 3 ------\\n\\n /// @dev Guardians can pause lower class users\\n /// Governance can add/remove guardians\\n /// Governance is guardian by default\\n mapping(address => uint256) internal _isGuardian;\\n\\n // ----- storage slot 4 ------\\n\\n /// @dev 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 mapping(address => uint256) internal _userClass;\\n\\n // ----- storage slot 5 ------\\n\\n /// @dev exchange prices and token config per token: token -> exchange prices & config\\n /// First 16 bits => 0- 15 => borrow rate (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\\n /// Next 14 bits => 16- 29 => fee on interest from borrowers to lenders (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\\n /// Next 14 bits => 30- 43 => last stored utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n /// Next 14 bits => 44- 57 => update on storage threshold (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\\n /// Next 33 bits => 58- 90 => last update timestamp (enough until 16 March 2242 -> max value 8589934591)\\n /// Next 64 bits => 91-154 => supply exchange price (1e12 -> max value 18_446_744,073709551615)\\n /// Next 64 bits => 155-218 => borrow exchange price (1e12 -> max value 18_446_744,073709551615)\\n /// Next 1 bit => 219-219 => if 0 then ratio is supplyInterestFree / supplyWithInterest else ratio is supplyWithInterest / supplyInterestFree\\n /// Next 14 bits => 220-233 => supplyRatio: supplyInterestFree / supplyWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n /// Next 1 bit => 234-234 => if 0 then ratio is borrowInterestFree / borrowWithInterest else ratio is borrowWithInterest / borrowInterestFree\\n /// Next 14 bits => 235-248 => borrowRatio: borrowInterestFree / borrowWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n /// Next 1 bit => 249-249 => flag for token uses config storage slot 2. (signals SLOAD for additional config slot is needed during execution)\\n /// Last 6 bits => 250-255 => empty for future use\\n /// if more free bits are needed in the future, update on storage threshold bits could be reduced to 7 bits\\n /// (can plan to add `MAX_TOKEN_CONFIG_UPDATE_THRESHOLD` but need to adjust more bits)\\n /// if more bits absolutely needed then we can convert fee, utilization, update on storage threshold,\\n /// supplyRatio & borrowRatio from 14 bits to 10bits (1023 max number) where 1000 = 100% & 1 = 0.1%\\n mapping(address => uint256) internal _exchangePricesAndConfig;\\n\\n // ----- storage slot 6 ------\\n\\n /// @dev Rate related data per token: token -> rate data\\n /// READ (SLOAD): all actions; WRITE (SSTORE): only on set config admin actions\\n /// token => rate related data\\n /// First 4 bits => 0-3 => rate version\\n /// rest of the bits are rate dependent:\\n\\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 => empty for future use\\n\\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 => empty for future use\\n mapping(address => uint256) internal _rateData;\\n\\n // ----- storage slot 7 ------\\n\\n /// @dev total supply / borrow amounts for with / without interest per token: token -> amounts\\n /// First 64 bits => 0- 63 => total supply with interest in raw (totalSupply = totalSupplyRaw * supplyExchangePrice); BigMath: 56 | 8\\n /// Next 64 bits => 64-127 => total interest free supply in normal token amount (totalSupply = totalSupply); BigMath: 56 | 8\\n /// Next 64 bits => 128-191 => total borrow with interest in raw (totalBorrow = totalBorrowRaw * borrowExchangePrice); BigMath: 56 | 8\\n /// Next 64 bits => 192-255 => total interest free borrow in normal token amount (totalBorrow = totalBorrow); BigMath: 56 | 8\\n mapping(address => uint256) internal _totalAmounts;\\n\\n // ----- storage slot 8 ------\\n\\n /// @dev user supply data per token: user -> token -> data\\n /// First 1 bit => 0 => mode: user supply with or without interest\\n /// 0 = without, amounts are in normal (i.e. no need to multiply with exchange price)\\n /// 1 = with interest, amounts are in raw (i.e. must multiply with exchange price to get actual token amounts)\\n /// Next 64 bits => 1- 64 => user supply amount (normal or raw depends on 1st bit); BigMath: 56 | 8\\n /// Next 64 bits => 65-128 => previous user withdrawal limit (normal or raw depends on 1st bit); BigMath: 56 | 8\\n /// Next 33 bits => 129-161 => last triggered process timestamp (enough until 16 March 2242 -> max value 8589934591)\\n /// Next 14 bits => 162-175 => expand withdrawal limit percentage (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383).\\n /// @dev shrinking is instant\\n /// Next 24 bits => 176-199 => withdrawal limit expand duration in seconds.(Max value 16_777_215; ~4_660 hours, ~194 days)\\n /// Next 18 bits => 200-217 => base withdrawal limit: below this, 100% withdrawals can be done (normal or raw depends on 1st bit); BigMath: 10 | 8\\n /// Next 37 bits => 218-254 => empty for future use\\n /// Last bit => 255-255 => is user paused (1 = paused, 0 = not paused)\\n mapping(address => mapping(address => uint256)) internal _userSupplyData;\\n\\n // ----- storage slot 9 ------\\n\\n /// @dev user borrow data per token: user -> token -> data\\n /// First 1 bit => 0 => mode: user borrow with or without interest\\n /// 0 = without, amounts are in normal (i.e. no need to multiply with exchange price)\\n /// 1 = with interest, amounts are in raw (i.e. must multiply with exchange price to get actual token amounts)\\n /// Next 64 bits => 1- 64 => user borrow amount (normal or raw depends on 1st bit); BigMath: 56 | 8\\n /// Next 64 bits => 65-128 => previous user debt ceiling (normal or raw depends on 1st bit); BigMath: 56 | 8\\n /// Next 33 bits => 129-161 => last triggered process timestamp (enough until 16 March 2242 -> max value 8589934591)\\n /// Next 14 bits => 162-175 => expand debt ceiling percentage (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n /// @dev shrinking is instant\\n /// Next 24 bits => 176-199 => debt ceiling expand duration in seconds (Max value 16_777_215; ~4_660 hours, ~194 days)\\n /// Next 18 bits => 200-217 => base debt ceiling: below this, there's no debt ceiling limits (normal or raw depends on 1st bit); BigMath: 10 | 8\\n /// Next 18 bits => 218-235 => max debt ceiling: absolute maximum debt ceiling can expand to (normal or raw depends on 1st bit); BigMath: 10 | 8\\n /// Next 19 bits => 236-254 => empty for future use\\n /// Last bit => 255-255 => is user paused (1 = paused, 0 = not paused)\\n mapping(address => mapping(address => uint256)) internal _userBorrowData;\\n\\n // ----- storage slot 10 ------\\n\\n /// @dev list of allowed tokens at Liquidity. tokens that are once configured can never be completely removed. so this\\n /// array is append-only.\\n address[] internal _listedTokens;\\n\\n // ----- storage slot 11 ------\\n\\n /// @dev expanded token configs per token: token -> config data slot 2.\\n /// Use of this is signaled by `_exchangePricesAndConfig` bit 249.\\n /// First 14 bits => 0- 13 => max allowed utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\\n /// Last 242 bits => 14-255 => empty for future use\\n mapping(address => uint256) internal _configs2;\\n}\\n\",\"keccak256\":\"0x0fdae459355d882ccb2b9b350d0abe17604078a8df887e5d7c774f69e83529dd\",\"license\":\"BUSL-1.1\"},\"contracts/liquidity/error.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.21;\\n\\ncontract Error {\\n error FluidLiquidityError(uint256 errorId_);\\n}\\n\",\"keccak256\":\"0x6013ceb756cb1301b2a5ebac8aa0dfc39dc610012670462a70c13d99a2708302\",\"license\":\"BUSL-1.1\"},\"contracts/liquidity/errorTypes.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.21;\\n\\nlibrary ErrorTypes {\\n /***********************************|\\n | Admin Module | \\n |__________________________________*/\\n\\n /// @notice thrown when an input address is zero\\n uint256 internal constant AdminModule__AddressZero = 10001;\\n\\n /// @notice thrown when msg.sender is not governance\\n uint256 internal constant AdminModule__OnlyGovernance = 10002;\\n\\n /// @notice thrown when msg.sender is not auth\\n uint256 internal constant AdminModule__OnlyAuths = 10003;\\n\\n /// @notice thrown when msg.sender is not guardian\\n uint256 internal constant AdminModule__OnlyGuardians = 10004;\\n\\n /// @notice thrown when base withdrawal limit, base debt limit or max withdrawal limit is sent as 0\\n uint256 internal constant AdminModule__LimitZero = 10005;\\n\\n /// @notice thrown whenever an invalid input param is given\\n uint256 internal constant AdminModule__InvalidParams = 10006;\\n\\n /// @notice thrown if user class 1 is paused (can not be paused)\\n uint256 internal constant AdminModule__UserNotPausable = 10007;\\n\\n /// @notice thrown if user is tried to be unpaused but is not paused in the first place\\n uint256 internal constant AdminModule__UserNotPaused = 10008;\\n\\n /// @notice thrown if user is not defined yet: Governance didn't yet set any config for this user on a particular token\\n uint256 internal constant AdminModule__UserNotDefined = 10009;\\n\\n /// @notice thrown if a token is configured in an invalid order: 1. Set rate config for token 2. Set token config 3. allow any user.\\n uint256 internal constant AdminModule__InvalidConfigOrder = 10010;\\n\\n /// @notice thrown if revenue is collected when revenue collector address is not set\\n uint256 internal constant AdminModule__RevenueCollectorNotSet = 10011;\\n\\n /// @notice all ValueOverflow errors below are thrown if a certain input param overflows the allowed storage size\\n uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_ZERO = 10012;\\n uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_KINK = 10013;\\n uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_MAX = 10014;\\n uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_KINK1 = 10015;\\n uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_KINK2 = 10016;\\n uint256 internal constant AdminModule__ValueOverflow__RATE_AT_UTIL_MAX_V2 = 10017;\\n uint256 internal constant AdminModule__ValueOverflow__FEE = 10018;\\n uint256 internal constant AdminModule__ValueOverflow__THRESHOLD = 10019;\\n uint256 internal constant AdminModule__ValueOverflow__EXPAND_PERCENT = 10020;\\n uint256 internal constant AdminModule__ValueOverflow__EXPAND_DURATION = 10021;\\n uint256 internal constant AdminModule__ValueOverflow__EXPAND_PERCENT_BORROW = 10022;\\n uint256 internal constant AdminModule__ValueOverflow__EXPAND_DURATION_BORROW = 10023;\\n uint256 internal constant AdminModule__ValueOverflow__EXCHANGE_PRICES = 10024;\\n uint256 internal constant AdminModule__ValueOverflow__UTILIZATION = 10025;\\n\\n /// @notice thrown when an address is not a contract\\n uint256 internal constant AdminModule__AddressNotAContract = 10026;\\n\\n uint256 internal constant AdminModule__ValueOverflow__MAX_UTILIZATION = 10027;\\n\\n /// @notice thrown if a token that is being listed has not between 6 and 18 decimals\\n uint256 internal constant AdminModule__TokenInvalidDecimalsRange = 10028;\\n\\n /***********************************|\\n | User Module | \\n |__________________________________*/\\n\\n /// @notice thrown when user operations are paused for an interacted token\\n uint256 internal constant UserModule__UserNotDefined = 11001;\\n\\n /// @notice thrown when user operations are paused for an interacted token\\n uint256 internal constant UserModule__UserPaused = 11002;\\n\\n /// @notice thrown when user's try to withdraw below withdrawal limit\\n uint256 internal constant UserModule__WithdrawalLimitReached = 11003;\\n\\n /// @notice thrown when user's try to borrow above borrow limit\\n uint256 internal constant UserModule__BorrowLimitReached = 11004;\\n\\n /// @notice thrown when user sent supply/withdraw and borrow/payback both as 0\\n uint256 internal constant UserModule__OperateAmountsZero = 11005;\\n\\n /// @notice thrown when user sent supply/withdraw or borrow/payback both as bigger than 2**128\\n uint256 internal constant UserModule__OperateAmountOutOfBounds = 11006;\\n\\n /// @notice thrown when the operate amount for supply / withdraw / borrow / payback is below the minimum amount\\n /// that would cause a storage difference after BigMath & rounding imprecision. Extremely unlikely to ever happen\\n /// for all normal use-cases.\\n uint256 internal constant UserModule__OperateAmountInsufficient = 11007;\\n\\n /// @notice thrown when withdraw or borrow is executed but withdrawTo or borrowTo is the zero address\\n uint256 internal constant UserModule__ReceiverNotDefined = 11008;\\n\\n /// @notice thrown when user did send excess or insufficient amount (beyond rounding issues)\\n uint256 internal constant UserModule__TransferAmountOutOfBounds = 11009;\\n\\n /// @notice thrown when user sent msg.value along for an operation not for the native token\\n uint256 internal constant UserModule__MsgValueForNonNativeToken = 11010;\\n\\n /// @notice thrown when a borrow operation is done when utilization is above 100%\\n uint256 internal constant UserModule__MaxUtilizationReached = 11011;\\n\\n /// @notice all ValueOverflow errors below are thrown if a certain input param or calc result overflows the allowed storage size\\n uint256 internal constant UserModule__ValueOverflow__EXCHANGE_PRICES = 11012;\\n uint256 internal constant UserModule__ValueOverflow__UTILIZATION = 11013;\\n uint256 internal constant UserModule__ValueOverflow__TOTAL_SUPPLY = 11014;\\n uint256 internal constant UserModule__ValueOverflow__TOTAL_BORROW = 11015;\\n\\n /***********************************|\\n | LiquidityHelpers | \\n |__________________________________*/\\n\\n /// @notice thrown when a reentrancy happens\\n uint256 internal constant LiquidityHelpers__Reentrancy = 12001;\\n}\\n\",\"keccak256\":\"0x915417f764bf86c48a3d1623bce934a9c859e6f302e42818a30d91ca107e931f\",\"license\":\"BUSL-1.1\"},\"contracts/liquidity/userModule/events.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.21;\\n\\ncontract Events {\\n /// @notice emitted on any `operate()` execution: deposit / supply / withdraw / borrow.\\n /// includes info related to the executed operation, new total amounts (packed uint256 of BigMath numbers as in storage)\\n /// and exchange prices (packed uint256 as in storage).\\n /// @param user protocol that triggered this operation (e.g. via an fToken or via Vault protocol)\\n /// @param token token address for which this operation was executed\\n /// @param supplyAmount supply amount for the operation. if >0 then a deposit happened, if <0 then a withdrawal happened.\\n /// if 0 then nothing.\\n /// @param borrowAmount borrow amount for the operation. if >0 then a borrow happened, if <0 then a payback happened.\\n /// if 0 then nothing.\\n /// @param withdrawTo address that funds where withdrawn to (if supplyAmount <0)\\n /// @param borrowTo address that funds where borrowed to (if borrowAmount >0)\\n /// @param totalAmounts updated total amounts, stacked uint256 as written to storage:\\n /// First 64 bits => 0- 63 => total supply with interest in raw (totalSupply = totalSupplyRaw * supplyExchangePrice); BigMath: 56 | 8\\n /// Next 64 bits => 64-127 => total interest free supply in normal token amount (totalSupply = totalSupply); BigMath: 56 | 8\\n /// Next 64 bits => 128-191 => total borrow with interest in raw (totalBorrow = totalBorrowRaw * borrowExchangePrice); BigMath: 56 | 8\\n /// Next 64 bits => 192-255 => total interest free borrow in normal token amount (totalBorrow = totalBorrow); BigMath: 56 | 8\\n /// @param exchangePricesAndConfig updated exchange prices and configs storage slot. Contains updated supply & borrow exchange price:\\n /// First 16 bits => 0- 15 => borrow rate (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535)\\n /// Next 14 bits => 16- 29 => fee on interest from borrowers to lenders (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\\n /// Next 14 bits => 30- 43 => last stored utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n /// Next 14 bits => 44- 57 => update on storage threshold (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable.\\n /// Next 33 bits => 58- 90 => last update timestamp (enough until 16 March 2242 -> max value 8589934591)\\n /// Next 64 bits => 91-154 => supply exchange price (1e12 -> max value 18_446_744,073709551615)\\n /// Next 64 bits => 155-218 => borrow exchange price (1e12 -> max value 18_446_744,073709551615)\\n /// Next 1 bit => 219-219 => if 0 then ratio is supplyInterestFree / supplyWithInterest else ratio is supplyWithInterest / supplyInterestFree\\n /// Next 14 bits => 220-233 => supplyRatio: supplyInterestFree / supplyWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n /// Next 1 bit => 234-234 => if 0 then ratio is borrowInterestFree / borrowWithInterest else ratio is borrowWithInterest / borrowInterestFree\\n /// Next 14 bits => 235-248 => borrowRatio: borrowInterestFree / borrowWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)\\n event LogOperate(\\n address indexed user,\\n address indexed token,\\n int256 supplyAmount,\\n int256 borrowAmount,\\n address withdrawTo,\\n address borrowTo,\\n uint256 totalAmounts,\\n uint256 exchangePricesAndConfig\\n );\\n}\\n\",\"keccak256\":\"0x34d00aa5b172195544bca0706b0168717fe1c002a6bd8fe538234e009cb219ac\",\"license\":\"BUSL-1.1\"},\"contracts/liquidity/userModule/main.sol\":{\"content\":\"// SPDX-License-Identifier: BUSL-1.1\\npragma solidity 0.8.21;\\n\\nimport { IERC20 } from \\\"@openzeppelin/contracts/interfaces/IERC20.sol\\\";\\nimport { SafeERC20 } from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport { FixedPointMathLib } from \\\"solmate/src/utils/FixedPointMathLib.sol\\\";\\nimport { Address } from \\\"@openzeppelin/contracts/utils/Address.sol\\\";\\n\\nimport { BigMathMinified } from \\\"../../libraries/bigMathMinified.sol\\\";\\nimport { LiquidityCalcs } from \\\"../../libraries/liquidityCalcs.sol\\\";\\nimport { LiquiditySlotsLink } from \\\"../../libraries/liquiditySlotsLink.sol\\\";\\nimport { CommonHelpers } from \\\"../common/helpers.sol\\\";\\nimport { Events } from \\\"./events.sol\\\";\\nimport { ErrorTypes } from \\\"../errorTypes.sol\\\";\\nimport { Error } from \\\"../error.sol\\\";\\n\\ninterface IProtocol {\\n function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external;\\n}\\n\\nabstract contract CoreInternals is Error, CommonHelpers, Events {\\n using BigMathMinified for uint256;\\n\\n /// @dev supply or withdraw for both with interest & interest free.\\n /// positive `amount_` is deposit, negative `amount_` is withdraw.\\n function _supplyOrWithdraw(\\n address token_,\\n int256 amount_,\\n uint256 supplyExchangePrice_\\n ) internal returns (int256 newSupplyInterestRaw_, int256 newSupplyInterestFree_) {\\n uint256 userSupplyData_ = _userSupplyData[msg.sender][token_];\\n\\n if (userSupplyData_ == 0) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__UserNotDefined);\\n }\\n if ((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_IS_PAUSED) & 1 == 1) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__UserPaused);\\n }\\n\\n // extract user supply amount\\n uint256 userSupply_ = (userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64;\\n userSupply_ = (userSupply_ >> DEFAULT_EXPONENT_SIZE) << (userSupply_ & DEFAULT_EXPONENT_MASK);\\n\\n // calculate current, updated (expanded etc.) withdrawal limit\\n uint256 newWithdrawalLimit_ = LiquidityCalcs.calcWithdrawalLimitBeforeOperate(userSupplyData_, userSupply_);\\n\\n // calculate updated user supply amount\\n if (userSupplyData_ & 1 == 1) {\\n // mode: with interest\\n if (amount_ > 0) {\\n // convert amount from normal to raw (divide by exchange price) -> round down for deposit\\n newSupplyInterestRaw_ = (amount_ * int256(EXCHANGE_PRICES_PRECISION)) / int256(supplyExchangePrice_);\\n userSupply_ = userSupply_ + uint256(newSupplyInterestRaw_);\\n } else {\\n // convert amount from normal to raw (divide by exchange price) -> round up for withdraw\\n newSupplyInterestRaw_ = -int256(\\n FixedPointMathLib.mulDivUp(uint256(-amount_), EXCHANGE_PRICES_PRECISION, supplyExchangePrice_)\\n );\\n // if withdrawal is more than user's supply then solidity will throw here\\n userSupply_ = userSupply_ - uint256(-newSupplyInterestRaw_);\\n }\\n } else {\\n // mode: without interest\\n newSupplyInterestFree_ = amount_;\\n if (newSupplyInterestFree_ > 0) {\\n userSupply_ = userSupply_ + uint256(newSupplyInterestFree_);\\n } else {\\n // if withdrawal is more than user's supply then solidity will throw here\\n userSupply_ = userSupply_ - uint256(-newSupplyInterestFree_);\\n }\\n }\\n\\n if (amount_ < 0 && userSupply_ < newWithdrawalLimit_) {\\n // if withdraw, then check the user supply after withdrawal is above withdrawal limit\\n revert FluidLiquidityError(ErrorTypes.UserModule__WithdrawalLimitReached);\\n }\\n\\n // calculate withdrawal limit to store as previous withdrawal limit in storage\\n newWithdrawalLimit_ = LiquidityCalcs.calcWithdrawalLimitAfterOperate(\\n userSupplyData_,\\n userSupply_,\\n newWithdrawalLimit_\\n );\\n\\n // Converting user's supply into BigNumber\\n userSupply_ = userSupply_.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_DOWN\\n );\\n if (((userSupplyData_ >> LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) & X64) == userSupply_) {\\n // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\\n // is present then rounding will be in the right direction to avoid any potential manipulation.\\n revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\\n }\\n\\n // Converting withdrawal limit into BigNumber\\n newWithdrawalLimit_ = newWithdrawalLimit_.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_DOWN\\n );\\n\\n // Updating on storage\\n _userSupplyData[msg.sender][token_] =\\n // mask to update bits 1-161 (supply amount, withdrawal limit, timestamp)\\n (userSupplyData_ & 0xfffffffffffffffffffffffc0000000000000000000000000000000000000001) |\\n (userSupply_ << LiquiditySlotsLink.BITS_USER_SUPPLY_AMOUNT) | // converted to BigNumber can not overflow\\n (newWithdrawalLimit_ << LiquiditySlotsLink.BITS_USER_SUPPLY_PREVIOUS_WITHDRAWAL_LIMIT) | // converted to BigNumber can not overflow\\n (block.timestamp << LiquiditySlotsLink.BITS_USER_SUPPLY_LAST_UPDATE_TIMESTAMP);\\n }\\n\\n /// @dev borrow or payback for both with interest & interest free.\\n /// positive `amount_` is borrow, negative `amount_` is payback.\\n function _borrowOrPayback(\\n address token_,\\n int256 amount_,\\n uint256 borrowExchangePrice_\\n ) internal returns (int256 newBorrowInterestRaw_, int256 newBorrowInterestFree_) {\\n uint256 userBorrowData_ = _userBorrowData[msg.sender][token_];\\n\\n if (userBorrowData_ == 0) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__UserNotDefined);\\n }\\n if ((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_IS_PAUSED) & 1 == 1) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__UserPaused);\\n }\\n\\n // extract user borrow amount\\n uint256 userBorrow_ = (userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64;\\n userBorrow_ = (userBorrow_ >> DEFAULT_EXPONENT_SIZE) << (userBorrow_ & DEFAULT_EXPONENT_MASK);\\n\\n // calculate current, updated (expanded etc.) borrow limit\\n uint256 newBorrowLimit_ = LiquidityCalcs.calcBorrowLimitBeforeOperate(userBorrowData_, userBorrow_);\\n\\n // calculate updated user borrow amount\\n if (userBorrowData_ & 1 == 1) {\\n // with interest\\n if (amount_ > 0) {\\n // convert amount normal to raw (divide by exchange price) -> round up for borrow\\n newBorrowInterestRaw_ = int256(\\n FixedPointMathLib.mulDivUp(uint256(amount_), EXCHANGE_PRICES_PRECISION, borrowExchangePrice_)\\n );\\n userBorrow_ = userBorrow_ + uint256(newBorrowInterestRaw_);\\n } else {\\n // convert amount from normal to raw (divide by exchange price) -> round down for payback\\n newBorrowInterestRaw_ = (amount_ * int256(EXCHANGE_PRICES_PRECISION)) / int256(borrowExchangePrice_);\\n userBorrow_ = userBorrow_ - uint256(-newBorrowInterestRaw_);\\n }\\n } else {\\n // without interest\\n newBorrowInterestFree_ = amount_;\\n if (newBorrowInterestFree_ > 0) {\\n // borrowing\\n userBorrow_ = userBorrow_ + uint256(newBorrowInterestFree_);\\n } else {\\n // payback\\n userBorrow_ = userBorrow_ - uint256(-newBorrowInterestFree_);\\n }\\n }\\n\\n if (amount_ > 0 && userBorrow_ > newBorrowLimit_) {\\n // if borrow, then check the user borrow amount after borrowing is below borrow limit\\n revert FluidLiquidityError(ErrorTypes.UserModule__BorrowLimitReached);\\n }\\n\\n // calculate borrow limit to store as previous borrow limit in storage\\n newBorrowLimit_ = LiquidityCalcs.calcBorrowLimitAfterOperate(userBorrowData_, userBorrow_, newBorrowLimit_);\\n\\n // Converting user's borrowings into bignumber\\n userBorrow_ = userBorrow_.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_UP\\n );\\n\\n if (((userBorrowData_ >> LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) & X64) == userBorrow_) {\\n // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\\n // is present then rounding will be in the right direction to avoid any potential manipulation.\\n revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\\n }\\n\\n // Converting borrow limit into bignumber\\n newBorrowLimit_ = newBorrowLimit_.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_DOWN\\n );\\n\\n // Updating on storage\\n _userBorrowData[msg.sender][token_] =\\n // mask to update bits 1-161 (borrow amount, borrow limit, timestamp)\\n (userBorrowData_ & 0xfffffffffffffffffffffffc0000000000000000000000000000000000000001) |\\n (userBorrow_ << LiquiditySlotsLink.BITS_USER_BORROW_AMOUNT) | // converted to BigNumber can not overflow\\n (newBorrowLimit_ << LiquiditySlotsLink.BITS_USER_BORROW_PREVIOUS_BORROW_LIMIT) | // converted to BigNumber can not overflow\\n (block.timestamp << LiquiditySlotsLink.BITS_USER_BORROW_LAST_UPDATE_TIMESTAMP);\\n }\\n\\n /// @dev checks if `supplyAmount_` & borrowAmount amounts balance themselves out (checked before calling this method):\\n /// - supply(+) == borrow(+), withdraw(-) == payback(-). (DEX protocol use-case)\\n /// - `withdrawTo_` / `borrowTo_` must be msg.sender (protocol)\\n /// - `callbackData_` MUST be encoded so that \\\"from\\\" address is at last 20 bytes (if this optimization is desired),\\n /// also for native token operations where liquidityCallback is not triggered!\\n /// from address must come at last position if there is more data. I.e. encode like:\\n /// abi.encode(otherVar1, otherVar2, FROM_ADDRESS). Note dynamic types used with abi.encode come at the end\\n /// so if dynamic types are needed, you must use abi.encodePacked to ensure the from address is at the end.\\n function _isInOutBalancedOut(\\n int256 supplyAmount_,\\n address withdrawTo_,\\n address borrowTo_,\\n bytes memory callbackData_\\n ) internal view returns (bool) {\\n if (callbackData_.length < 20) {\\n return false;\\n }\\n\\n address inFrom_;\\n assembly {\\n inFrom_ := mload(\\n add(\\n // add padding for length as present for dynamic arrays in memory\\n add(callbackData_, 32),\\n // assembly expects address with leading zeros / left padded so need to use 32 as length here\\n sub(mload(callbackData_), 32)\\n )\\n )\\n }\\n return\\n // case: supply & borrow. borrow receiver must be the same as depositor and must be protocol\\n (supplyAmount_ > 0 && inFrom_ == borrowTo_ && inFrom_ == msg.sender) ||\\n // case: withdraw & payback. withdraw receiver must be the same as depositor and must be protocol\\n (supplyAmount_ < 0 && inFrom_ == withdrawTo_ && inFrom_ == msg.sender);\\n }\\n}\\n\\n/// @title Fluid Liquidity UserModule\\n/// @notice Fluid Liquidity public facing endpoint logic contract that implements the `operate()` method.\\n/// operate can be used to deposit, withdraw, borrow & payback funds, given that they have the necessary\\n/// user config allowance. Interacting users must be allowed via the Fluid Liquidity AdminModule first.\\n/// Intended users are thus allow-listed protocols, e.g. the Lending protocol (fTokens), Vault protocol etc.\\n/// @dev For view methods / accessing data, use the \\\"LiquidityResolver\\\" periphery contract.\\ncontract FluidLiquidityUserModule is CoreInternals {\\n using SafeERC20 for IERC20;\\n using BigMathMinified for uint256;\\n\\n /// @dev struct for vars used in operate() that would otherwise cause a Stack too deep error\\n struct OperateMemoryVars {\\n bool skipTransfers;\\n uint256 supplyExchangePrice;\\n uint256 borrowExchangePrice;\\n uint256 supplyRawInterest;\\n uint256 supplyInterestFree;\\n uint256 borrowRawInterest;\\n uint256 borrowInterestFree;\\n uint256 totalAmounts;\\n uint256 exchangePricesAndConfig;\\n }\\n\\n /// @notice inheritdoc IFluidLiquidity\\n function operate(\\n address token_,\\n int256 supplyAmount_,\\n int256 borrowAmount_,\\n address withdrawTo_,\\n address borrowTo_,\\n bytes calldata callbackData_\\n ) external payable reentrancy returns (uint256 memVar3_, uint256 memVar4_) {\\n if (supplyAmount_ == 0 && borrowAmount_ == 0) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountsZero);\\n }\\n if (\\n supplyAmount_ < type(int128).min ||\\n supplyAmount_ > type(int128).max ||\\n borrowAmount_ < type(int128).min ||\\n borrowAmount_ > type(int128).max\\n ) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountOutOfBounds);\\n }\\n if ((supplyAmount_ < 0 && withdrawTo_ == address(0)) || (borrowAmount_ > 0 && borrowTo_ == address(0))) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__ReceiverNotDefined);\\n }\\n if (token_ != NATIVE_TOKEN_ADDRESS && msg.value > 0) {\\n // revert: there should not be msg.value if the token is not the native token\\n revert FluidLiquidityError(ErrorTypes.UserModule__MsgValueForNonNativeToken);\\n }\\n\\n OperateMemoryVars memory o_;\\n\\n // @dev temporary memory variables used as helper in between to avoid assigning new memory variables\\n uint256 memVar_;\\n // memVar2_ => operateAmountIn: deposit + payback\\n uint256 memVar2_ = uint256((supplyAmount_ > 0 ? supplyAmount_ : int256(0))) +\\n uint256((borrowAmount_ < 0 ? -borrowAmount_ : int256(0)));\\n // check if in & output amounts balance themselves out:\\n // supply(+) == borrow(+), withdraw(-) == payback(-). (DEX protocol use-case)\\n // AND msg.value must be 0 otherwise we assume protocol wants normal transfers to happen\\n if (\\n supplyAmount_ == borrowAmount_ &&\\n msg.value == 0 &&\\n _isInOutBalancedOut(supplyAmount_, withdrawTo_, borrowTo_, callbackData_)\\n ) {\\n memVar2_ = 0; // set to 0 to skip transfers IN\\n o_.skipTransfers = true; // set flag to true to skip transfers OUT\\n }\\n if (token_ == NATIVE_TOKEN_ADDRESS) {\\n unchecked {\\n // check supply and payback amount is covered by available sent msg.value and\\n // protection that msg.value is not unintentionally way more than actually used in operate()\\n if (memVar2_ > msg.value || msg.value > memVar2_ + NATIVE_AMOUNT_EXCESS_LIMIT) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__TransferAmountOutOfBounds);\\n }\\n }\\n memVar2_ = 0; // set to 0 to skip transfers IN more gas efficient. No need for native token.\\n }\\n // if supply or payback or both -> transfer token amount from sender to here.\\n // for native token this is already covered by msg.value checks in operate(). memVar2_ is set to 0\\n // for same amounts in same operate(): supply(+) == borrow(+), withdraw(-) == payback(-). memVar2_ is set to 0\\n if (memVar2_ > 0) {\\n // memVar_ => initial token balance of this contract\\n memVar_ = IERC20(token_).balanceOf(address(this));\\n // trigger protocol to send token amount and pass callback data\\n IProtocol(msg.sender).liquidityCallback(token_, memVar2_, callbackData_);\\n // memVar_ => current token balance of this contract - initial balance\\n memVar_ = IERC20(token_).balanceOf(address(this)) - memVar_;\\n unchecked {\\n if (memVar_ < memVar2_ || memVar_ > (memVar2_ + 10)) {\\n // revert if protocol did not send enough to cover supply / payback\\n // or if protocol sent more than expected, with minor tolerance for any potential rounding issues,\\n // even though that should not be needed (liquidityCallback should send exact amount as in params).\\n revert FluidLiquidityError(ErrorTypes.UserModule__TransferAmountOutOfBounds);\\n }\\n }\\n }\\n\\n o_.exchangePricesAndConfig = _exchangePricesAndConfig[token_];\\n\\n // calculate updated exchange prices\\n (o_.supplyExchangePrice, o_.borrowExchangePrice) = LiquidityCalcs.calcExchangePrices(\\n o_.exchangePricesAndConfig\\n );\\n\\n // Extract total supply / borrow amounts for the token\\n o_.totalAmounts = _totalAmounts[token_];\\n memVar_ = o_.totalAmounts & X64;\\n o_.supplyRawInterest = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\\n memVar_ = (o_.totalAmounts >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE) & X64;\\n o_.supplyInterestFree = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\\n memVar_ = (o_.totalAmounts >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST) & X64;\\n o_.borrowRawInterest = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\\n // no & mask needed for borrow interest free as it occupies the last bits in the storage slot\\n memVar_ = (o_.totalAmounts >> LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE);\\n o_.borrowInterestFree = (memVar_ >> DEFAULT_EXPONENT_SIZE) << (memVar_ & DEFAULT_EXPONENT_MASK);\\n\\n if (supplyAmount_ != 0) {\\n // execute supply or withdraw and update total amounts\\n {\\n uint256 totalAmountsBefore_ = o_.totalAmounts;\\n (int256 newSupplyInterestRaw_, int256 newSupplyInterestFree_) = _supplyOrWithdraw(\\n token_,\\n supplyAmount_,\\n o_.supplyExchangePrice\\n );\\n // update total amounts. this is done here so that values are only written to storage once\\n // if a borrow / payback also happens in the same `operate()` call\\n if (newSupplyInterestFree_ == 0) {\\n // Note newSupplyInterestFree_ can ONLY be 0 if mode is with interest,\\n // easy to check as that variable is NOT the result of a dvision etc.\\n // supply or withdraw with interest -> raw amount\\n if (newSupplyInterestRaw_ > 0) {\\n o_.supplyRawInterest += uint256(newSupplyInterestRaw_);\\n } else {\\n unchecked {\\n o_.supplyRawInterest = o_.supplyRawInterest > uint256(-newSupplyInterestRaw_)\\n ? o_.supplyRawInterest - uint256(-newSupplyInterestRaw_)\\n : 0; // withdraw amount is > total supply -> withdraw total supply down to 0\\n // Note no risk here as if the user withdraws more than supplied it would revert already\\n // earlier. Total amounts can end up < sum of user amounts because of rounding\\n }\\n }\\n\\n // Note check for revert {UserModule}__ValueOverflow__TOTAL_SUPPLY is further down when we anyway\\n // calculate the normal amount from raw\\n\\n // Converting the updated total amount into big number for storage\\n memVar_ = o_.supplyRawInterest.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_DOWN\\n );\\n // update total supply with interest at total amounts in storage (only update changed values)\\n o_.totalAmounts =\\n // mask to update bits 0-63\\n (o_.totalAmounts & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000) |\\n memVar_; // converted to BigNumber can not overflow\\n } else {\\n // supply or withdraw interest free -> normal amount\\n if (newSupplyInterestFree_ > 0) {\\n o_.supplyInterestFree += uint256(newSupplyInterestFree_);\\n } else {\\n unchecked {\\n o_.supplyInterestFree = o_.supplyInterestFree > uint256(-newSupplyInterestFree_)\\n ? o_.supplyInterestFree - uint256(-newSupplyInterestFree_)\\n : 0; // withdraw amount is > total supply -> withdraw total supply down to 0\\n // Note no risk here as if the user withdraws more than supplied it would revert already\\n // earlier. Total amounts can end up < sum of user amounts because of rounding\\n }\\n }\\n if (o_.supplyInterestFree > MAX_TOKEN_AMOUNT_CAP) {\\n // only withdrawals allowed if total supply interest free reaches MAX_TOKEN_AMOUNT_CAP\\n revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_SUPPLY);\\n }\\n // Converting the updated total amount into big number for storage\\n memVar_ = o_.supplyInterestFree.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_DOWN\\n );\\n // update total supply interest free at total amounts in storage (only update changed values)\\n o_.totalAmounts =\\n // mask to update bits 64-127\\n (o_.totalAmounts & 0xffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff) |\\n (memVar_ << LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_SUPPLY_INTEREST_FREE); // converted to BigNumber can not overflow\\n }\\n if (totalAmountsBefore_ == o_.totalAmounts) {\\n // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\\n // is present then rounding will be in the right direction to avoid any potential manipulation.\\n revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\\n }\\n }\\n }\\n if (borrowAmount_ != 0) {\\n // execute borrow or payback and update total amounts\\n {\\n uint256 totalAmountsBefore_ = o_.totalAmounts;\\n (int256 newBorrowInterestRaw_, int256 newBorrowInterestFree_) = _borrowOrPayback(\\n token_,\\n borrowAmount_,\\n o_.borrowExchangePrice\\n );\\n // update total amounts. this is done here so that values are only written to storage once\\n // if a supply / withdraw also happens in the same `operate()` call\\n if (newBorrowInterestFree_ == 0) {\\n // Note newBorrowInterestFree_ can ONLY be 0 if mode is with interest,\\n // easy to check as that variable is NOT the result of a dvision etc.\\n // borrow or payback with interest -> raw amount\\n if (newBorrowInterestRaw_ > 0) {\\n o_.borrowRawInterest += uint256(newBorrowInterestRaw_);\\n } else {\\n unchecked {\\n o_.borrowRawInterest = o_.borrowRawInterest > uint256(-newBorrowInterestRaw_)\\n ? o_.borrowRawInterest - uint256(-newBorrowInterestRaw_)\\n : 0; // payback amount is > total borrow -> payback total borrow down to 0\\n }\\n }\\n\\n // Note check for revert UserModule__ValueOverflow__TOTAL_BORROW is further down when we anyway\\n // calculate the normal amount from raw\\n\\n // Converting the updated total amount into big number for storage\\n memVar_ = o_.borrowRawInterest.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_UP\\n );\\n // update total borrow with interest at total amounts in storage (only update changed values)\\n o_.totalAmounts =\\n // mask to update bits 128-191\\n (o_.totalAmounts & 0xffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff) |\\n (memVar_ << LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_WITH_INTEREST); // converted to BigNumber can not overflow\\n } else {\\n // borrow or payback interest free -> normal amount\\n if (newBorrowInterestFree_ > 0) {\\n o_.borrowInterestFree += uint256(newBorrowInterestFree_);\\n } else {\\n unchecked {\\n o_.borrowInterestFree = o_.borrowInterestFree > uint256(-newBorrowInterestFree_)\\n ? o_.borrowInterestFree - uint256(-newBorrowInterestFree_)\\n : 0; // payback amount is > total borrow -> payback total borrow down to 0\\n }\\n }\\n if (o_.borrowInterestFree > MAX_TOKEN_AMOUNT_CAP) {\\n // only payback allowed if total borrow interest free reaches MAX_TOKEN_AMOUNT_CAP\\n revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_BORROW);\\n }\\n // Converting the updated total amount into big number for storage\\n memVar_ = o_.borrowInterestFree.toBigNumber(\\n DEFAULT_COEFFICIENT_SIZE,\\n DEFAULT_EXPONENT_SIZE,\\n BigMathMinified.ROUND_UP\\n );\\n // update total borrow interest free at total amounts in storage (only update changed values)\\n o_.totalAmounts =\\n // mask to update bits 192-255\\n (o_.totalAmounts & 0x0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff) |\\n (memVar_ << LiquiditySlotsLink.BITS_TOTAL_AMOUNTS_BORROW_INTEREST_FREE); // converted to BigNumber can not overflow\\n }\\n if (totalAmountsBefore_ == o_.totalAmounts) {\\n // make sure that operate amount is not so small that it wouldn't affect storage update. if a difference\\n // is present then rounding will be in the right direction to avoid any potential manipulation.\\n revert FluidLiquidityError(ErrorTypes.UserModule__OperateAmountInsufficient);\\n }\\n }\\n }\\n // Updating total amounts on storage\\n _totalAmounts[token_] = o_.totalAmounts;\\n {\\n // update exchange prices / utilization / ratios\\n // exchangePricesAndConfig is only written to storage if either utilization, supplyRatio or borrowRatio\\n // change is above the required storageUpdateThreshold config value or if the last write was > 1 day ago.\\n\\n // 1. calculate new supply ratio, borrow ratio & utilization.\\n // 2. check if last storage write was > 1 day ago.\\n // 3. If false -> check if utilization is above update threshold\\n // 4. If false -> check if supply ratio is above update threshold\\n // 5. If false -> check if borrow ratio is above update threshold\\n // 6. If any true, then update on storage\\n\\n // ########## calculating supply ratio ##########\\n // supplyWithInterest in normal amount\\n memVar3_ = ((o_.supplyRawInterest * o_.supplyExchangePrice) / EXCHANGE_PRICES_PRECISION);\\n if (memVar3_ > MAX_TOKEN_AMOUNT_CAP && supplyAmount_ > 0) {\\n // only withdrawals allowed if total supply raw reaches MAX_TOKEN_AMOUNT_CAP\\n revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_SUPPLY);\\n }\\n // memVar_ => total supply. set here so supplyWithInterest (memVar3_) is only calculated once. For utilization\\n memVar_ = o_.supplyInterestFree + memVar3_;\\n if (memVar3_ > o_.supplyInterestFree) {\\n // memVar3_ is ratio with 1 bit as 0 as supply interest raw is bigger\\n memVar3_ = ((o_.supplyInterestFree * FOUR_DECIMALS) / memVar3_) << 1;\\n // because of checking to divide by bigger amount, ratio can never be > 100%\\n } else if (memVar3_ < o_.supplyInterestFree) {\\n // memVar3_ is ratio with 1 bit as 1 as supply interest free is bigger\\n memVar3_ = (((memVar3_ * FOUR_DECIMALS) / o_.supplyInterestFree) << 1) | 1;\\n // because of checking to divide by bigger amount, ratio can never be > 100%\\n } else if (memVar_ > 0) {\\n // supplies match exactly (memVar3_ == o_.supplyInterestFree) and total supplies are not 0\\n // -> set ratio to 1 (with first bit set to 0, doesn't matter)\\n memVar3_ = FOUR_DECIMALS << 1;\\n } // else if total supply = 0, memVar3_ (supplyRatio) is already 0.\\n\\n // ########## calculating borrow ratio ##########\\n // borrowWithInterest in normal amount\\n memVar4_ = ((o_.borrowRawInterest * o_.borrowExchangePrice) / EXCHANGE_PRICES_PRECISION);\\n if (memVar4_ > MAX_TOKEN_AMOUNT_CAP && borrowAmount_ > 0) {\\n // only payback allowed if total borrow raw reaches MAX_TOKEN_AMOUNT_CAP\\n revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__TOTAL_BORROW);\\n }\\n // memVar2_ => total borrow. set here so borrowWithInterest (memVar4_) is only calculated once. For utilization\\n memVar2_ = o_.borrowInterestFree + memVar4_;\\n if (memVar4_ > o_.borrowInterestFree) {\\n // memVar4_ is ratio with 1 bit as 0 as borrow interest raw is bigger\\n memVar4_ = ((o_.borrowInterestFree * FOUR_DECIMALS) / memVar4_) << 1;\\n // because of checking to divide by bigger amount, ratio can never be > 100%\\n } else if (memVar4_ < o_.borrowInterestFree) {\\n // memVar4_ is ratio with 1 bit as 1 as borrow interest free is bigger\\n memVar4_ = (((memVar4_ * FOUR_DECIMALS) / o_.borrowInterestFree) << 1) | 1;\\n // because of checking to divide by bigger amount, ratio can never be > 100%\\n } else if (memVar2_ > 0) {\\n // borrows match exactly (memVar4_ == o_.borrowInterestFree) and total borrows are not 0\\n // -> set ratio to 1 (with first bit set to 0, doesn't matter)\\n memVar4_ = FOUR_DECIMALS << 1;\\n } // else if total borrow = 0, memVar4_ (borrowRatio) is already 0.\\n\\n // calculate utilization. If there is no supply, utilization must be 0 (avoid division by 0)\\n uint256 utilization_;\\n if (memVar_ > 0) {\\n utilization_ = ((memVar2_ * FOUR_DECIMALS) / memVar_);\\n\\n // for borrow operations, ensure max utilization is not reached\\n if (borrowAmount_ > 0) {\\n // memVar_ => max utilization\\n // if any max utilization other than 100% is set, the flag usesConfigs2 in\\n // exchangePricesAndConfig is 1. (optimized to avoid SLOAD if not needed).\\n memVar_ = (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_USES_CONFIGS2) &\\n 1 ==\\n 1\\n ? (_configs2[token_] & X14) // read configured max utilization\\n : FOUR_DECIMALS; // default max utilization = 100%\\n\\n if (utilization_ > memVar_) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__MaxUtilizationReached);\\n }\\n }\\n }\\n\\n // check if time difference is big enough (> 1 day)\\n unchecked {\\n if (\\n block.timestamp >\\n // extract last update timestamp + 1 day\\n (((o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) & X33) +\\n FORCE_STORAGE_WRITE_AFTER_TIME)\\n ) {\\n memVar_ = 1; // set write to storage flag\\n } else {\\n memVar_ = 0;\\n }\\n }\\n\\n if (memVar_ == 0) {\\n // time difference is not big enough to cause storage write -> check utilization\\n\\n // memVar_ => extract last utilization\\n memVar_ = (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) & X14;\\n // memVar2_ => storage update threshold in percent\\n memVar2_ =\\n (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UPDATE_THRESHOLD) &\\n X14;\\n unchecked {\\n // set memVar_ to 1 if current utilization to previous utilization difference is > update storage threshold\\n memVar_ = (utilization_ > memVar_ ? utilization_ - memVar_ : memVar_ - utilization_) > memVar2_\\n ? 1\\n : 0;\\n if (memVar_ == 0) {\\n // utilization & time difference is not big enough -> check supplyRatio difference\\n // memVar_ => extract last supplyRatio\\n memVar_ =\\n (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) &\\n X15;\\n // set memVar_ to 1 if current supplyRatio to previous supplyRatio difference is > update storage threshold\\n if ((memVar_ & 1) == (memVar3_ & 1)) {\\n memVar_ = memVar_ >> 1;\\n memVar_ = (\\n (memVar3_ >> 1) > memVar_ ? (memVar3_ >> 1) - memVar_ : memVar_ - (memVar3_ >> 1)\\n ) > memVar2_\\n ? 1\\n : 0; // memVar3_ = supplyRatio, memVar_ = previous supplyRatio, memVar2_ = update storage threshold\\n } else {\\n // if inverse bit is changing then always update on storage\\n memVar_ = 1;\\n }\\n if (memVar_ == 0) {\\n // utilization, time, and supplyRatio difference is not big enough -> check borrowRatio difference\\n // memVar_ => extract last borrowRatio\\n memVar_ =\\n (o_.exchangePricesAndConfig >> LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO) &\\n X15;\\n // set memVar_ to 1 if current borrowRatio to previous borrowRatio difference is > update storage threshold\\n if ((memVar_ & 1) == (memVar4_ & 1)) {\\n memVar_ = memVar_ >> 1;\\n memVar_ = (\\n (memVar4_ >> 1) > memVar_ ? (memVar4_ >> 1) - memVar_ : memVar_ - (memVar4_ >> 1)\\n ) > memVar2_\\n ? 1\\n : 0; // memVar4_ = borrowRatio, memVar_ = previous borrowRatio, memVar2_ = update storage threshold\\n } else {\\n // if inverse bit is changing then always update on storage\\n memVar_ = 1;\\n }\\n }\\n }\\n }\\n }\\n\\n // memVar_ is 1 if either time diff was enough or if\\n // utilization, supplyRatio or borrowRatio difference was > update storage threshold\\n if (memVar_ == 1) {\\n // memVar_ => calculate new borrow rate for utilization. includes value overflow check.\\n memVar_ = LiquidityCalcs.calcBorrowRateFromUtilization(_rateData[token_], utilization_);\\n // ensure values written to storage do not exceed the dedicated bit space in packed uint256 slots\\n if (o_.supplyExchangePrice > X64 || o_.borrowExchangePrice > X64) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__EXCHANGE_PRICES);\\n }\\n if (utilization_ > X14) {\\n revert FluidLiquidityError(ErrorTypes.UserModule__ValueOverflow__UTILIZATION);\\n }\\n o_.exchangePricesAndConfig =\\n (o_.exchangePricesAndConfig &\\n // mask to update bits: 0-15 (borrow rate), 30-43 (utilization), 58-248 (timestamp, exchange prices, ratios)\\n 0xfe000000000000000000000000000000000000000000000003fff0003fff0000) |\\n memVar_ | // calcBorrowRateFromUtilization already includes an overflow check\\n (utilization_ << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_UTILIZATION) |\\n (block.timestamp << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_LAST_TIMESTAMP) |\\n (o_.supplyExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) |\\n (o_.borrowExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE) |\\n // ratios can never be > 100%, no overflow check needed\\n (memVar3_ << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_RATIO) | // supplyRatio (memVar3_ holds that value)\\n (memVar4_ << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_RATIO); // borrowRatio (memVar4_ holds that value)\\n // Updating on storage\\n _exchangePricesAndConfig[token_] = o_.exchangePricesAndConfig;\\n } else {\\n // do not update in storage but update o_.exchangePricesAndConfig for updated exchange prices at\\n // event emit of LogOperate\\n o_.exchangePricesAndConfig =\\n (o_.exchangePricesAndConfig &\\n // mask to update bits: 91-218 (exchange prices)\\n 0xfffffffffc00000000000000000000000000000007ffffffffffffffffffffff) |\\n (o_.supplyExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_SUPPLY_EXCHANGE_PRICE) |\\n (o_.borrowExchangePrice << LiquiditySlotsLink.BITS_EXCHANGE_PRICES_BORROW_EXCHANGE_PRICE);\\n }\\n }\\n // sending tokens to user at the end after updating everything\\n // only transfer to user in case of withdraw or borrow.\\n // do not transfer for same amounts in same operate(): supply(+) == borrow(+), withdraw(-) == payback(-). (DEX protocol use-case)\\n if ((supplyAmount_ < 0 || borrowAmount_ > 0) && !o_.skipTransfers) {\\n // sending tokens to user at the end after updating everything\\n // set memVar2_ to borrowAmount (if borrow) or reset memVar2_ var to 0 because\\n // it is used with > 0 check below to transfer withdraw / borrow / both\\n memVar2_ = borrowAmount_ > 0 ? uint256(borrowAmount_) : 0;\\n if (supplyAmount_ < 0) {\\n unchecked {\\n memVar_ = uint256(-supplyAmount_);\\n }\\n } else {\\n memVar_ = 0;\\n }\\n if (memVar_ > 0 && memVar2_ > 0 && withdrawTo_ == borrowTo_) {\\n // if user is doing borrow & withdraw together and address for both is the same\\n // then transfer tokens of borrow & withdraw together to save on gas\\n if (token_ == NATIVE_TOKEN_ADDRESS) {\\n Address.sendValue(payable(withdrawTo_), memVar_ + memVar2_);\\n } else {\\n IERC20(token_).safeTransfer(withdrawTo_, memVar_ + memVar2_);\\n }\\n } else {\\n if (token_ == NATIVE_TOKEN_ADDRESS) {\\n // if withdraw\\n if (memVar_ > 0) {\\n Address.sendValue(payable(withdrawTo_), memVar_);\\n }\\n // if borrow\\n if (memVar2_ > 0) {\\n Address.sendValue(payable(borrowTo_), memVar2_);\\n }\\n } else {\\n // if withdraw\\n if (memVar_ > 0) {\\n IERC20(token_).safeTransfer(withdrawTo_, memVar_);\\n }\\n // if borrow\\n if (memVar2_ > 0) {\\n IERC20(token_).safeTransfer(borrowTo_, memVar2_);\\n }\\n }\\n }\\n }\\n // emit Operate event\\n emit LogOperate(\\n msg.sender,\\n token_,\\n supplyAmount_,\\n borrowAmount_,\\n withdrawTo_,\\n borrowTo_,\\n o_.totalAmounts,\\n o_.exchangePricesAndConfig\\n );\\n // set return values\\n memVar3_ = o_.supplyExchangePrice;\\n memVar4_ = o_.borrowExchangePrice;\\n }\\n}\\n\",\"keccak256\":\"0x75e47de0bf416a523160193c887cbf988f17c5039ec585d744d6fe57537c614e\",\"license\":\"BUSL-1.1\"},\"solmate/src/utils/FixedPointMathLib.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Arithmetic library with operations for fixed-point numbers.\\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)\\n/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\\nlibrary FixedPointMathLib {\\n /*//////////////////////////////////////////////////////////////\\n SIMPLIFIED FIXED POINT OPERATIONS\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal constant MAX_UINT256 = 2**256 - 1;\\n\\n uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.\\n\\n function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.\\n }\\n\\n function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.\\n }\\n\\n function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.\\n }\\n\\n function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {\\n return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n LOW LEVEL FIXED POINT OPERATIONS\\n //////////////////////////////////////////////////////////////*/\\n\\n function mulDivDown(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 z) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\\n if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\\n revert(0, 0)\\n }\\n\\n // Divide x * y by the denominator.\\n z := div(mul(x, y), denominator)\\n }\\n }\\n\\n function mulDivUp(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 z) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))\\n if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {\\n revert(0, 0)\\n }\\n\\n // If x * y modulo the denominator is strictly greater than 0,\\n // 1 is added to round up the division of x * y by the denominator.\\n z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))\\n }\\n }\\n\\n function rpow(\\n uint256 x,\\n uint256 n,\\n uint256 scalar\\n ) internal pure returns (uint256 z) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n switch x\\n case 0 {\\n switch n\\n case 0 {\\n // 0 ** 0 = 1\\n z := scalar\\n }\\n default {\\n // 0 ** n = 0\\n z := 0\\n }\\n }\\n default {\\n switch mod(n, 2)\\n case 0 {\\n // If n is even, store scalar in z for now.\\n z := scalar\\n }\\n default {\\n // If n is odd, store x in z for now.\\n z := x\\n }\\n\\n // Shifting right by 1 is like dividing by 2.\\n let half := shr(1, scalar)\\n\\n for {\\n // Shift n right by 1 before looping to halve it.\\n n := shr(1, n)\\n } n {\\n // Shift n right by 1 each iteration to halve it.\\n n := shr(1, n)\\n } {\\n // Revert immediately if x ** 2 would overflow.\\n // Equivalent to iszero(eq(div(xx, x), x)) here.\\n if shr(128, x) {\\n revert(0, 0)\\n }\\n\\n // Store x squared.\\n let xx := mul(x, x)\\n\\n // Round to the nearest number.\\n let xxRound := add(xx, half)\\n\\n // Revert if xx + half overflowed.\\n if lt(xxRound, xx) {\\n revert(0, 0)\\n }\\n\\n // Set x to scaled xxRound.\\n x := div(xxRound, scalar)\\n\\n // If n is even:\\n if mod(n, 2) {\\n // Compute z * x.\\n let zx := mul(z, x)\\n\\n // If z * x overflowed:\\n if iszero(eq(div(zx, x), z)) {\\n // Revert if x is non-zero.\\n if iszero(iszero(x)) {\\n revert(0, 0)\\n }\\n }\\n\\n // Round to the nearest number.\\n let zxRound := add(zx, half)\\n\\n // Revert if zx + half overflowed.\\n if lt(zxRound, zx) {\\n revert(0, 0)\\n }\\n\\n // Return properly scaled zxRound.\\n z := div(zxRound, scalar)\\n }\\n }\\n }\\n }\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n GENERAL NUMBER UTILITIES\\n //////////////////////////////////////////////////////////////*/\\n\\n function sqrt(uint256 x) internal pure returns (uint256 z) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let y := x // We start y at x, which will help us make our initial estimate.\\n\\n z := 181 // The \\\"correct\\\" value is 1, but this saves a multiplication later.\\n\\n // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad\\n // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.\\n\\n // We check y >= 2^(k + 8) but shift right by k bits\\n // each branch to ensure that if x >= 256, then y >= 256.\\n if iszero(lt(y, 0x10000000000000000000000000000000000)) {\\n y := shr(128, y)\\n z := shl(64, z)\\n }\\n if iszero(lt(y, 0x1000000000000000000)) {\\n y := shr(64, y)\\n z := shl(32, z)\\n }\\n if iszero(lt(y, 0x10000000000)) {\\n y := shr(32, y)\\n z := shl(16, z)\\n }\\n if iszero(lt(y, 0x1000000)) {\\n y := shr(16, y)\\n z := shl(8, z)\\n }\\n\\n // Goal was to get z*z*y within a small factor of x. More iterations could\\n // get y in a tighter range. Currently, we will have y in [256, 256*2^16).\\n // We ensured y >= 256 so that the relative difference between y and y+1 is small.\\n // That's not possible if x < 256 but we can just verify those cases exhaustively.\\n\\n // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.\\n // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.\\n // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.\\n\\n // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range\\n // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.\\n\\n // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate\\n // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.\\n\\n // There is no overflow risk here since y < 2^136 after the first branch above.\\n z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.\\n\\n // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.\\n z := shr(1, add(z, div(x, z)))\\n z := shr(1, add(z, div(x, z)))\\n z := shr(1, add(z, div(x, z)))\\n z := shr(1, add(z, div(x, z)))\\n z := shr(1, add(z, div(x, z)))\\n z := shr(1, add(z, div(x, z)))\\n z := shr(1, add(z, div(x, z)))\\n\\n // If x+1 is a perfect square, the Babylonian method cycles between\\n // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.\\n // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division\\n // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.\\n // If you don't care whether the floor or ceil square root is returned, you can remove this statement.\\n z := sub(z, lt(div(x, z), z))\\n }\\n }\\n\\n function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Mod x by y. Note this will return\\n // 0 instead of reverting if y is zero.\\n z := mod(x, y)\\n }\\n }\\n\\n function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Divide x by y. Note this will return\\n // 0 instead of reverting if y is zero.\\n r := div(x, y)\\n }\\n }\\n\\n function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Add 1 to x * y if x % y > 0. Note this will\\n // return 0 instead of reverting if y is zero.\\n z := add(gt(mod(x, y), 0), div(x, y))\\n }\\n }\\n}\\n\",\"keccak256\":\"0x1b62af9baf5b8e991ed7531bc87f45550ba9d61e8dbff5caf237ccaf3a3fd843\",\"license\":\"AGPL-3.0-only\"}},\"version\":1}", "bytecode": "0x608060405234801561001057600080fd5b506002600155612951806100256000396000f3fe60806040526004361061001e5760003560e01c8063ad967e1514610023575b600080fd5b61003661003136600461258b565b61004f565b6040805192835260208301919091520160405180910390f35b600080600260ff166001540361009a576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612ee160048201526024015b60405180910390fd5b6002600155871580156100ab575086155b156100e6576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afd6004820152602401610091565b7fffffffffffffffffffffffffffffffff8000000000000000000000000000000088128061012357506f7fffffffffffffffffffffffffffffff88135b8061014d57507fffffffffffffffffffffffffffffffff8000000000000000000000000000000087125b8061016757506f7fffffffffffffffffffffffffffffff87135b156101a2576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afe6004820152602401610091565b6000881280156101c6575073ffffffffffffffffffffffffffffffffffffffff8616155b806101f057506000871380156101f0575073ffffffffffffffffffffffffffffffffffffffff8516155b1561022b576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b006004820152602401610091565b73ffffffffffffffffffffffffffffffffffffffff891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906102655750600034115b156102a0576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b026004820152602401610091565b6102f160405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008060008a1261030357600061030c565b61030c8a612672565b60008c1361031b57600061031d565b8b5b61032791906126aa565b9050898b148015610336575034155b801561037f575061037f8b8a8a8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061130b92505050565b1561038c57506001825260005b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8d160161041b57348111806103dc5750633b9aca00810134115b15610417576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b016004820152602401610091565b5060005b801561060d576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8d16906370a0823190602401602060405180830381865afa15801561048b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104af91906126bd565b6040517fad207501000000000000000000000000000000000000000000000000000000008152909250339063ad207501906104f4908f9085908c908c906004016126d6565b600060405180830381600087803b15801561050e57600080fd5b505af1158015610522573d6000803e3d6000fd5b50506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284925073ffffffffffffffffffffffffffffffffffffffff8f1691506370a0823190602401602060405180830381865afa158015610592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b691906126bd565b6105c09190612747565b9150808210806105d2575080600a0182115b1561060d576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b016004820152602401610091565b73ffffffffffffffffffffffffffffffffffffffff8c166000908152600560205260409020546101008401819052610644906113ee565b60408086019190915260208086019290925273ffffffffffffffffffffffffffffffffffffffff8e1660009081526007909252908190205460e0850181905266ffffffffffffff600882901c811660ff8084169190911b6060880152604883901c82169383901c81169390931b608080880191909152608883901c9091169082901c83161b60a086015260c881901c60c091821c9283161b9085015291508a156108c05760008360e0015190506000806107038f8f88602001516115fc565b915091508060000361079c57600082131561073257818660600181815161072a91906126aa565b905250610755565b8160000386606001511161074757600061074f565b606086015182015b60608701525b6060860151610769906038600860006118b5565b60e0870180517fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001682179052945061087b565b60008113156107bf5780866080018181516107b791906126aa565b9052506107e2565b806000038660800151116107d45760006107dc565b608086015181015b60808701525b60808601516f7fffffffffffffffffffffffffffffff1015610834576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b066004820152602401610091565b6080860151610848906038600860006118b5565b60e0870180517fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff16604083901b17905294505b8560e0015183036108bc576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b5050505b8915610a9a5760008360e0015190506000806108e18f8e88604001516119de565b915091508060000361097e57600082131561091057818660a00181815161090891906126aa565b905250610933565b816000038660a001511161092557600061092d565b60a086015182015b60a08701525b60a0860151610947906038600860016118b5565b60e0870180517fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16608083901b1790529450610a55565b60008113156109a157808660c00181815161099991906126aa565b9052506109c4565b806000038660c00151116109b65760006109be565b60c086015181015b60c08701525b60c08601516f7fffffffffffffffffffffffffffffff1015610a16576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b076004820152602401610091565b60c0860151610a2a906038600860016118b5565b60e08701805177ffffffffffffffffffffffffffffffffffffffffffffffff1660c083901b17905294505b8560e001518303610a96576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b5050505b60e083015173ffffffffffffffffffffffffffffffffffffffff8d16600090815260076020908152604090912091909155830151606084015164e8d4a5100091610ae39161275a565b610aed91906127a0565b94506f7fffffffffffffffffffffffffffffff85118015610b0e575060008b135b15610b49576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b066004820152602401610091565b848360800151610b5991906126aa565b91508260800151851115610b8f576001856127108560800151610b7c919061275a565b610b8691906127a0565b901b9450610bd1565b8260800151851015610bc5576080830151600190610baf6127108861275a565b610bb991906127a0565b901b6001179450610bd1565b8115610bd157614e2094505b64e8d4a5100083604001518460a00151610beb919061275a565b610bf591906127a0565b93506f7fffffffffffffffffffffffffffffff84118015610c16575060008a135b15610c51576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b076004820152602401610091565b838360c00151610c6191906126aa565b90508260c00151841115610c97576001846127108560c00151610c84919061275a565b610c8e91906127a0565b901b9350610cd9565b8260c00151841015610ccd5760c0830151600190610cb76127108761275a565b610cc191906127a0565b901b6001179350610cd9565b8015610cd957614e2093505b60008215610d8a5782610cee6127108461275a565b610cf891906127a0565b905060008b1315610d8a5760f9846101000151901c600116600114610d1f57612710610d4a565b73ffffffffffffffffffffffffffffffffffffffff8d166000908152600b6020526040902054613fff165b925082811115610d8a576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b036004820152602401610091565b610100840151603a1c6401ffffffff166201518001421115610daf5760019250610db4565b600092505b82600003610ed857613fff601e856101000151901c169250613fff602c856101000151901c16915081838211610dec57818403610df0565b8382035b11610dfc576000610dff565b60015b60ff16925082600003610ed857617fff60db856101000151901c169250856001168360011603610e6957600183901c92508183600188901c11610e4857600187901c8403610e50565b83600188901c035b11610e5c576000610e5f565b60015b60ff169250610e6e565b600192505b82600003610ed857617fff60ea856101000151901c169250846001168360011603610ed357600183901c92508183600187901c11610eb257600186901c8403610eba565b83600187901c035b11610ec6576000610ec9565b60015b60ff169250610ed8565b600192505b826001036110605773ffffffffffffffffffffffffffffffffffffffff8d16600090815260066020526040902054610f109082611c86565b925067ffffffffffffffff84602001511180610f37575067ffffffffffffffff8460400151115b15610f72576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b046004820152602401610091565b613fff811115610fb2576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b056004820152602401610091565b60ea85901b60db87901b609b8660400151901b605b8760200151901b603a42901b601e86901b888a61010001517ffe000000000000000000000000000000000000000000000003fff0003fff0000161717171717171784610100018181525050836101000151600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506110a7565b609b8460400151901b605b8560200151901b8561010001517ffffffffffc00000000000000000000000000000007ffffffffffffffffffffff161717846101000181815250505b5060008b12806110b7575060008a135b80156110c257508251155b1561126b5760008a136110d65760006110d8565b895b905060008b12156110ee578a60000391506110f3565b600091505b6000821180156111035750600081115b801561113a57508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16145b156111c0577fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8d16016111945761118f8961118a83856126aa565b611d2f565b61126b565b61118f896111a283856126aa565b73ffffffffffffffffffffffffffffffffffffffff8f169190611e8e565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8d160161121d57811561120d5761120d8983611d2f565b801561118f5761118f8882611d2f565b81156112445761124473ffffffffffffffffffffffffffffffffffffffff8d168a84611e8e565b801561126b5761126b73ffffffffffffffffffffffffffffffffffffffff8d168983611e8e565b60e0830151610100840151604080518e8152602081018e905273ffffffffffffffffffffffffffffffffffffffff8d8116828401528c81166060830152608082019490945260a081019290925251918e169133917f4d93b232a24e82b284ced7461bf4deacffe66759d5c24513e6f29e571ad78d15919081900360c00190a35050602081015160409091015160018055909a909950975050505050505050565b600060148251101561131f575060006113e6565b815182015160008613801561135f57508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b8015611380575073ffffffffffffffffffffffffffffffffffffffff811633145b806113e257506000861280156113c157508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b80156113e2575073ffffffffffffffffffffffffffffffffffffffff811633145b9150505b949350505050565b67ffffffffffffffff605b82901c811690609b83901c16811580611410575080155b1561144c576040517fd50d7512000000000000000000000000000000000000000000000000000000008152620111716004820152602401610091565b61ffff8316603a84901c6401ffffffff16428181039160ea87901c617fff16911480611476575082155b806114815750806001145b1561148e57505050915091565b64496cebb80084840283020484019350617fff60db87901c169250826001036114b957505050915091565b8260011660010361150e5760019290921c91826c7e37be2022c0914b2680000000816114e7576114e7612771565b049250612710601e87901c613fff166b033b2e3c9fd0803ce800000085010204925061153b565b60019290921c916305f5e100601e87901c613fff166127108501026b033b2e3c9fd0803ce8000000020492505b806001166001036115725760011c61271081016b033b2e3c9fd0803ce800000082028161156a5761156a612771565b0490506115a8565b60011c61271081016b033b2e3c9fd0803ce800000082028161159657611596612771565b046b033b2e3c9fd0803ce80000000390505b760a70c3c40a64e6c51999090b65f67d92400000000000008382026127100261ffff881691900402601087901c613fff16612710030292506801b5a660ea44b8000085840283020485019450505050915091565b33600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054819080820361166c576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612af96004820152602401610091565b60ff81901c6001036116ae576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afa6004820152602401610091565b66ffffffffffffff600982901c1660ff600183901c161b60006116d18383611f1b565b90508260011660010361174a57600087131561171457856116f764e8d4a51000896127b4565b6117019190612800565b945061170d85836126aa565b9150611776565b61172c61172088612672565b64e8d4a5100088611fb0565b61173590612672565b945061174085612672565b61170d9083612747565b86935060008413156117605761170d84836126aa565b61176984612672565b6117739083612747565b91505b60008712801561178557508082105b156117c0576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afb6004820152602401610091565b6117cb838383611ff4565b90506117dc826038600860006118b5565b91508167ffffffffffffffff600185901c1603611829576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b611838816038600860006118b5565b33600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff9c909c1683529a9052989098207ffffffffffffffffffffffffc000000000000000000000000000000000000000190931660019290921b9190911760419790971b969096174260811b1790559094909350915050565b600080856fffffffffffffffffffffffffffffffff8111156118d85760809150811c5b67ffffffffffffffff8111156118f0576040918201911c5b63ffffffff811115611904576020918201911c5b61ffff811115611916576010918201911c5b60ff811115611927576008918201911c5b600f811115611938576004918201911c5b6003811115611949576002918201911c5b6001811115611959576001820191505b8015611966576001820191505b50848110156119725750835b848103905085811c600082118416156119c157600181019050806001871b036119c157506001908101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86011b5b6001851b82106119d057600080fd5b90931b909201949350505050565b33600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120548190808203611a4e576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612af96004820152602401610091565b60ff81901c600103611a90576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afa6004820152602401610091565b66ffffffffffffff600982901c1660ff600183901c161b6000611ab38383612047565b905082600116600103611b1b576000871315611aec57611ad98764e8d4a5100088611fb0565b9450611ae585836126aa565b9150611b47565b85611afc64e8d4a51000896127b4565b611b069190612800565b9450611b1185612672565b611ae59083612747565b8693506000841315611b3157611ae584836126aa565b611b3a84612672565b611b449083612747565b91505b600087138015611b5657508082115b15611b91576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afc6004820152602401610091565b611b9c8383836120ff565b9050611bad826038600860016118b5565b91508167ffffffffffffffff600185901c1603611bfa576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b611c09816038600860006118b5565b33600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff9c909c1683529a9052989098207ffffffffffffffffffffffffc000000000000000000000000000000000000000190931660019290921b9190911760419790971b969096174260811b1790559094909350915050565b6000600f83166001819003611ca657611c9f848461215e565b9150611cef565b80600203611cb857611c9f848461223d565b6040517fd50d7512000000000000000000000000000000000000000000000000000000008152620111726004820152602401610091565b61ffff821115611d285760405161ffff92507fe41708b2641eb1f7442f6a1e760ae5098fd7ba9f85e0c101513add0fbb27bcd790600090a15b5092915050565b80471015611d99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610091565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611df3576040519150601f19603f3d011682016040523d82523d6000602084013e611df8565b606091505b5050905080611e89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610091565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611e899084906122e5565b600066ffffffffffffff604984901c1660ff604185901c161b808203611f45576000915050611faa565b612710613fff60a286901c168402046401ffffffff608186901c16420362ffffff60b087901c16611f76828461275a565b611f8091906127a0565b9050808311611f90576000611f94565b8083035b93505080840383811115611fa6578093505b5050505b92915050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0484118302158202611fe557600080fd5b50910281810615159190040190565b60006103ff60d085901c1660ff60c886901c161b8084101561201a576000915050612040565b50612710613fff60a286901c1684020483038281111561203b579050612040565b829150505b9392505050565b60d082901c6103ff1660c883901c60ff161b613fff60a284901c16612710838202048084018381101561207c57505050611faa565b608186901c6401ffffffff164203925066ffffffffffffff604987901c1660ff604188901c161b60b087901c62ffffff166120b7858561275a565b6120c191906127a0565b6120cb91906126aa565b9350808411156120d9578093505b6103ff60e287901c1660ff60da88901c161b925082841115611fa6575090949350505050565b612710613fff60a285901c16830204820160d084901c6103ff1660c885901c60ff161b80821015612131579050612040565b506103ff60e285901c1660ff60da86901c161b80821115612150578091505b8183111561203b5750612040565b600080808080601487901c61ffff16808710156121975761ffff600489901c16945061ffff602489901c169350600092508091506121b6565b61ffff602489901c16945061ffff603489901c16935080925061271091505b60008084840364e8d4a5100088880302816121d3576121d3612771565b0585810264e8d4a5100089020392508902820190506000811215612228576040517fd50d7512000000000000000000000000000000000000000000000000000000008152620111736004820152602401610091565b64e8d4a5100090049998505050505050505050565b600080808080601487901c61ffff16808710156122765761ffff600489901c16945061ffff602489901c169350600092508091506121b6565b603488901c61ffff16808810156122a85761ffff60248a901c16955061ffff60448a901c1694508193508092506122c7565b61ffff60448a901c16955061ffff60548a901c16945080935061271092505b5060008084840364e8d4a5100088880302816121d3576121d3612771565b6000612347826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166123f19092919063ffffffff16565b805190915015611e8957808060200190518101906123659190612868565b611e89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610091565b60606113e68484600085856000808673ffffffffffffffffffffffffffffffffffffffff16858760405161242591906128ae565b60006040518083038185875af1925050503d8060008114612462576040519150601f19603f3d011682016040523d82523d6000602084013e612467565b606091505b509150915061247887838387612483565b979650505050505050565b606083156125195782516000036125125773ffffffffffffffffffffffffffffffffffffffff85163b612512576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610091565b50816113e6565b6113e6838381511561252e5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161009191906128ca565b803573ffffffffffffffffffffffffffffffffffffffff8116811461258657600080fd5b919050565b600080600080600080600060c0888a0312156125a657600080fd5b6125af88612562565b965060208801359550604088013594506125cb60608901612562565b93506125d960808901612562565b925060a088013567ffffffffffffffff808211156125f657600080fd5b818a0191508a601f83011261260a57600080fd5b81358181111561261957600080fd5b8b602082850101111561262b57600080fd5b60208301945080935050505092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007f800000000000000000000000000000000000000000000000000000000000000082036126a3576126a3612643565b5060000390565b80820180821115611faa57611faa612643565b6000602082840312156126cf57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260606040820152816060820152818360808301376000818301608090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01601019392505050565b81810381811115611faa57611faa612643565b8082028115828204841417611faa57611faa612643565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826127af576127af612771565b500490565b808202600082127f8000000000000000000000000000000000000000000000000000000000000000841416156127ec576127ec612643565b8181058314821517611faa57611faa612643565b60008261280f5761280f612771565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561286357612863612643565b500590565b60006020828403121561287a57600080fd5b8151801515811461204057600080fd5b60005b838110156128a557818101518382015260200161288d565b50506000910152565b600082516128c081846020870161288a565b9190910192915050565b60208152600082518060208401526128e981604085016020870161288a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220ec6b9d278d5a3e314004fda88866b4ad289c98842b9a74f67bd2c6882c8ac48964736f6c63430008150033", "deployedBytecode": "0x60806040526004361061001e5760003560e01c8063ad967e1514610023575b600080fd5b61003661003136600461258b565b61004f565b6040805192835260208301919091520160405180910390f35b600080600260ff166001540361009a576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612ee160048201526024015b60405180910390fd5b6002600155871580156100ab575086155b156100e6576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afd6004820152602401610091565b7fffffffffffffffffffffffffffffffff8000000000000000000000000000000088128061012357506f7fffffffffffffffffffffffffffffff88135b8061014d57507fffffffffffffffffffffffffffffffff8000000000000000000000000000000087125b8061016757506f7fffffffffffffffffffffffffffffff87135b156101a2576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afe6004820152602401610091565b6000881280156101c6575073ffffffffffffffffffffffffffffffffffffffff8616155b806101f057506000871380156101f0575073ffffffffffffffffffffffffffffffffffffffff8516155b1561022b576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b006004820152602401610091565b73ffffffffffffffffffffffffffffffffffffffff891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906102655750600034115b156102a0576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b026004820152602401610091565b6102f160405180610120016040528060001515815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60008060008a1261030357600061030c565b61030c8a612672565b60008c1361031b57600061031d565b8b5b61032791906126aa565b9050898b148015610336575034155b801561037f575061037f8b8a8a8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061130b92505050565b1561038c57506001825260005b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8d160161041b57348111806103dc5750633b9aca00810134115b15610417576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b016004820152602401610091565b5060005b801561060d576040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8d16906370a0823190602401602060405180830381865afa15801561048b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104af91906126bd565b6040517fad207501000000000000000000000000000000000000000000000000000000008152909250339063ad207501906104f4908f9085908c908c906004016126d6565b600060405180830381600087803b15801561050e57600080fd5b505af1158015610522573d6000803e3d6000fd5b50506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015284925073ffffffffffffffffffffffffffffffffffffffff8f1691506370a0823190602401602060405180830381865afa158015610592573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105b691906126bd565b6105c09190612747565b9150808210806105d2575080600a0182115b1561060d576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b016004820152602401610091565b73ffffffffffffffffffffffffffffffffffffffff8c166000908152600560205260409020546101008401819052610644906113ee565b60408086019190915260208086019290925273ffffffffffffffffffffffffffffffffffffffff8e1660009081526007909252908190205460e0850181905266ffffffffffffff600882901c811660ff8084169190911b6060880152604883901c82169383901c81169390931b608080880191909152608883901c9091169082901c83161b60a086015260c881901c60c091821c9283161b9085015291508a156108c05760008360e0015190506000806107038f8f88602001516115fc565b915091508060000361079c57600082131561073257818660600181815161072a91906126aa565b905250610755565b8160000386606001511161074757600061074f565b606086015182015b60608701525b6060860151610769906038600860006118b5565b60e0870180517fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001682179052945061087b565b60008113156107bf5780866080018181516107b791906126aa565b9052506107e2565b806000038660800151116107d45760006107dc565b608086015181015b60808701525b60808601516f7fffffffffffffffffffffffffffffff1015610834576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b066004820152602401610091565b6080860151610848906038600860006118b5565b60e0870180517fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff16604083901b17905294505b8560e0015183036108bc576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b5050505b8915610a9a5760008360e0015190506000806108e18f8e88604001516119de565b915091508060000361097e57600082131561091057818660a00181815161090891906126aa565b905250610933565b816000038660a001511161092557600061092d565b60a086015182015b60a08701525b60a0860151610947906038600860016118b5565b60e0870180517fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff16608083901b1790529450610a55565b60008113156109a157808660c00181815161099991906126aa565b9052506109c4565b806000038660c00151116109b65760006109be565b60c086015181015b60c08701525b60c08601516f7fffffffffffffffffffffffffffffff1015610a16576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b076004820152602401610091565b60c0860151610a2a906038600860016118b5565b60e08701805177ffffffffffffffffffffffffffffffffffffffffffffffff1660c083901b17905294505b8560e001518303610a96576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b5050505b60e083015173ffffffffffffffffffffffffffffffffffffffff8d16600090815260076020908152604090912091909155830151606084015164e8d4a5100091610ae39161275a565b610aed91906127a0565b94506f7fffffffffffffffffffffffffffffff85118015610b0e575060008b135b15610b49576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b066004820152602401610091565b848360800151610b5991906126aa565b91508260800151851115610b8f576001856127108560800151610b7c919061275a565b610b8691906127a0565b901b9450610bd1565b8260800151851015610bc5576080830151600190610baf6127108861275a565b610bb991906127a0565b901b6001179450610bd1565b8115610bd157614e2094505b64e8d4a5100083604001518460a00151610beb919061275a565b610bf591906127a0565b93506f7fffffffffffffffffffffffffffffff84118015610c16575060008a135b15610c51576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b076004820152602401610091565b838360c00151610c6191906126aa565b90508260c00151841115610c97576001846127108560c00151610c84919061275a565b610c8e91906127a0565b901b9350610cd9565b8260c00151841015610ccd5760c0830151600190610cb76127108761275a565b610cc191906127a0565b901b6001179350610cd9565b8015610cd957614e2093505b60008215610d8a5782610cee6127108461275a565b610cf891906127a0565b905060008b1315610d8a5760f9846101000151901c600116600114610d1f57612710610d4a565b73ffffffffffffffffffffffffffffffffffffffff8d166000908152600b6020526040902054613fff165b925082811115610d8a576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b036004820152602401610091565b610100840151603a1c6401ffffffff166201518001421115610daf5760019250610db4565b600092505b82600003610ed857613fff601e856101000151901c169250613fff602c856101000151901c16915081838211610dec57818403610df0565b8382035b11610dfc576000610dff565b60015b60ff16925082600003610ed857617fff60db856101000151901c169250856001168360011603610e6957600183901c92508183600188901c11610e4857600187901c8403610e50565b83600188901c035b11610e5c576000610e5f565b60015b60ff169250610e6e565b600192505b82600003610ed857617fff60ea856101000151901c169250846001168360011603610ed357600183901c92508183600187901c11610eb257600186901c8403610eba565b83600187901c035b11610ec6576000610ec9565b60015b60ff169250610ed8565b600192505b826001036110605773ffffffffffffffffffffffffffffffffffffffff8d16600090815260066020526040902054610f109082611c86565b925067ffffffffffffffff84602001511180610f37575067ffffffffffffffff8460400151115b15610f72576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b046004820152602401610091565b613fff811115610fb2576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612b056004820152602401610091565b60ea85901b60db87901b609b8660400151901b605b8760200151901b603a42901b601e86901b888a61010001517ffe000000000000000000000000000000000000000000000003fff0003fff0000161717171717171784610100018181525050836101000151600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506110a7565b609b8460400151901b605b8560200151901b8561010001517ffffffffffc00000000000000000000000000000007ffffffffffffffffffffff161717846101000181815250505b5060008b12806110b7575060008a135b80156110c257508251155b1561126b5760008a136110d65760006110d8565b895b905060008b12156110ee578a60000391506110f3565b600091505b6000821180156111035750600081115b801561113a57508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16145b156111c0577fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8d16016111945761118f8961118a83856126aa565b611d2f565b61126b565b61118f896111a283856126aa565b73ffffffffffffffffffffffffffffffffffffffff8f169190611e8e565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8d160161121d57811561120d5761120d8983611d2f565b801561118f5761118f8882611d2f565b81156112445761124473ffffffffffffffffffffffffffffffffffffffff8d168a84611e8e565b801561126b5761126b73ffffffffffffffffffffffffffffffffffffffff8d168983611e8e565b60e0830151610100840151604080518e8152602081018e905273ffffffffffffffffffffffffffffffffffffffff8d8116828401528c81166060830152608082019490945260a081019290925251918e169133917f4d93b232a24e82b284ced7461bf4deacffe66759d5c24513e6f29e571ad78d15919081900360c00190a35050602081015160409091015160018055909a909950975050505050505050565b600060148251101561131f575060006113e6565b815182015160008613801561135f57508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b8015611380575073ffffffffffffffffffffffffffffffffffffffff811633145b806113e257506000861280156113c157508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b80156113e2575073ffffffffffffffffffffffffffffffffffffffff811633145b9150505b949350505050565b67ffffffffffffffff605b82901c811690609b83901c16811580611410575080155b1561144c576040517fd50d7512000000000000000000000000000000000000000000000000000000008152620111716004820152602401610091565b61ffff8316603a84901c6401ffffffff16428181039160ea87901c617fff16911480611476575082155b806114815750806001145b1561148e57505050915091565b64496cebb80084840283020484019350617fff60db87901c169250826001036114b957505050915091565b8260011660010361150e5760019290921c91826c7e37be2022c0914b2680000000816114e7576114e7612771565b049250612710601e87901c613fff166b033b2e3c9fd0803ce800000085010204925061153b565b60019290921c916305f5e100601e87901c613fff166127108501026b033b2e3c9fd0803ce8000000020492505b806001166001036115725760011c61271081016b033b2e3c9fd0803ce800000082028161156a5761156a612771565b0490506115a8565b60011c61271081016b033b2e3c9fd0803ce800000082028161159657611596612771565b046b033b2e3c9fd0803ce80000000390505b760a70c3c40a64e6c51999090b65f67d92400000000000008382026127100261ffff881691900402601087901c613fff16612710030292506801b5a660ea44b8000085840283020485019450505050915091565b33600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054819080820361166c576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612af96004820152602401610091565b60ff81901c6001036116ae576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afa6004820152602401610091565b66ffffffffffffff600982901c1660ff600183901c161b60006116d18383611f1b565b90508260011660010361174a57600087131561171457856116f764e8d4a51000896127b4565b6117019190612800565b945061170d85836126aa565b9150611776565b61172c61172088612672565b64e8d4a5100088611fb0565b61173590612672565b945061174085612672565b61170d9083612747565b86935060008413156117605761170d84836126aa565b61176984612672565b6117739083612747565b91505b60008712801561178557508082105b156117c0576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afb6004820152602401610091565b6117cb838383611ff4565b90506117dc826038600860006118b5565b91508167ffffffffffffffff600185901c1603611829576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b611838816038600860006118b5565b33600090815260086020908152604080832073ffffffffffffffffffffffffffffffffffffffff9c909c1683529a9052989098207ffffffffffffffffffffffffc000000000000000000000000000000000000000190931660019290921b9190911760419790971b969096174260811b1790559094909350915050565b600080856fffffffffffffffffffffffffffffffff8111156118d85760809150811c5b67ffffffffffffffff8111156118f0576040918201911c5b63ffffffff811115611904576020918201911c5b61ffff811115611916576010918201911c5b60ff811115611927576008918201911c5b600f811115611938576004918201911c5b6003811115611949576002918201911c5b6001811115611959576001820191505b8015611966576001820191505b50848110156119725750835b848103905085811c600082118416156119c157600181019050806001871b036119c157506001908101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86011b5b6001851b82106119d057600080fd5b90931b909201949350505050565b33600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120548190808203611a4e576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612af96004820152602401610091565b60ff81901c600103611a90576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afa6004820152602401610091565b66ffffffffffffff600982901c1660ff600183901c161b6000611ab38383612047565b905082600116600103611b1b576000871315611aec57611ad98764e8d4a5100088611fb0565b9450611ae585836126aa565b9150611b47565b85611afc64e8d4a51000896127b4565b611b069190612800565b9450611b1185612672565b611ae59083612747565b8693506000841315611b3157611ae584836126aa565b611b3a84612672565b611b449083612747565b91505b600087138015611b5657508082115b15611b91576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612afc6004820152602401610091565b611b9c8383836120ff565b9050611bad826038600860016118b5565b91508167ffffffffffffffff600185901c1603611bfa576040517fdcab82e2000000000000000000000000000000000000000000000000000000008152612aff6004820152602401610091565b611c09816038600860006118b5565b33600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff9c909c1683529a9052989098207ffffffffffffffffffffffffc000000000000000000000000000000000000000190931660019290921b9190911760419790971b969096174260811b1790559094909350915050565b6000600f83166001819003611ca657611c9f848461215e565b9150611cef565b80600203611cb857611c9f848461223d565b6040517fd50d7512000000000000000000000000000000000000000000000000000000008152620111726004820152602401610091565b61ffff821115611d285760405161ffff92507fe41708b2641eb1f7442f6a1e760ae5098fd7ba9f85e0c101513add0fbb27bcd790600090a15b5092915050565b80471015611d99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610091565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611df3576040519150601f19603f3d011682016040523d82523d6000602084013e611df8565b606091505b5050905080611e89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610091565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611e899084906122e5565b600066ffffffffffffff604984901c1660ff604185901c161b808203611f45576000915050611faa565b612710613fff60a286901c168402046401ffffffff608186901c16420362ffffff60b087901c16611f76828461275a565b611f8091906127a0565b9050808311611f90576000611f94565b8083035b93505080840383811115611fa6578093505b5050505b92915050565b6000827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0484118302158202611fe557600080fd5b50910281810615159190040190565b60006103ff60d085901c1660ff60c886901c161b8084101561201a576000915050612040565b50612710613fff60a286901c1684020483038281111561203b579050612040565b829150505b9392505050565b60d082901c6103ff1660c883901c60ff161b613fff60a284901c16612710838202048084018381101561207c57505050611faa565b608186901c6401ffffffff164203925066ffffffffffffff604987901c1660ff604188901c161b60b087901c62ffffff166120b7858561275a565b6120c191906127a0565b6120cb91906126aa565b9350808411156120d9578093505b6103ff60e287901c1660ff60da88901c161b925082841115611fa6575090949350505050565b612710613fff60a285901c16830204820160d084901c6103ff1660c885901c60ff161b80821015612131579050612040565b506103ff60e285901c1660ff60da86901c161b80821115612150578091505b8183111561203b5750612040565b600080808080601487901c61ffff16808710156121975761ffff600489901c16945061ffff602489901c169350600092508091506121b6565b61ffff602489901c16945061ffff603489901c16935080925061271091505b60008084840364e8d4a5100088880302816121d3576121d3612771565b0585810264e8d4a5100089020392508902820190506000811215612228576040517fd50d7512000000000000000000000000000000000000000000000000000000008152620111736004820152602401610091565b64e8d4a5100090049998505050505050505050565b600080808080601487901c61ffff16808710156122765761ffff600489901c16945061ffff602489901c169350600092508091506121b6565b603488901c61ffff16808810156122a85761ffff60248a901c16955061ffff60448a901c1694508193508092506122c7565b61ffff60448a901c16955061ffff60548a901c16945080935061271092505b5060008084840364e8d4a5100088880302816121d3576121d3612771565b6000612347826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166123f19092919063ffffffff16565b805190915015611e8957808060200190518101906123659190612868565b611e89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610091565b60606113e68484600085856000808673ffffffffffffffffffffffffffffffffffffffff16858760405161242591906128ae565b60006040518083038185875af1925050503d8060008114612462576040519150601f19603f3d011682016040523d82523d6000602084013e612467565b606091505b509150915061247887838387612483565b979650505050505050565b606083156125195782516000036125125773ffffffffffffffffffffffffffffffffffffffff85163b612512576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610091565b50816113e6565b6113e6838381511561252e5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161009191906128ca565b803573ffffffffffffffffffffffffffffffffffffffff8116811461258657600080fd5b919050565b600080600080600080600060c0888a0312156125a657600080fd5b6125af88612562565b965060208801359550604088013594506125cb60608901612562565b93506125d960808901612562565b925060a088013567ffffffffffffffff808211156125f657600080fd5b818a0191508a601f83011261260a57600080fd5b81358181111561261957600080fd5b8b602082850101111561262b57600080fd5b60208301945080935050505092959891949750929550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007f800000000000000000000000000000000000000000000000000000000000000082036126a3576126a3612643565b5060000390565b80820180821115611faa57611faa612643565b6000602082840312156126cf57600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260606040820152816060820152818360808301376000818301608090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01601019392505050565b81810381811115611faa57611faa612643565b8082028115828204841417611faa57611faa612643565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826127af576127af612771565b500490565b808202600082127f8000000000000000000000000000000000000000000000000000000000000000841416156127ec576127ec612643565b8181058314821517611faa57611faa612643565b60008261280f5761280f612771565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561286357612863612643565b500590565b60006020828403121561287a57600080fd5b8151801515811461204057600080fd5b60005b838110156128a557818101518382015260200161288d565b50506000910152565b600082516128c081846020870161288a565b9190910192915050565b60208152600082518060208401526128e981604085016020870161288a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220ec6b9d278d5a3e314004fda88866b4ad289c98842b9a74f67bd2c6882c8ac48964736f6c63430008150033", "devdoc": { "details": "For view methods / accessing data, use the \"LiquidityResolver\" periphery contract.", "events": { "LogOperate(address,address,int256,int256,address,address,uint256,uint256)": { "params": { "borrowAmount": "borrow amount for the operation. if >0 then a borrow happened, if <0 then a payback happened. if 0 then nothing.", "borrowTo": "address that funds where borrowed to (if borrowAmount >0)", "exchangePricesAndConfig": "updated exchange prices and configs storage slot. Contains updated supply & borrow exchange price: First 16 bits => 0- 15 => borrow rate (in 1e2: 100% = 10_000; 1% = 100 -> max value 65535) Next 14 bits => 16- 29 => fee on interest from borrowers to lenders (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable. Next 14 bits => 30- 43 => last stored utilization (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383) Next 14 bits => 44- 57 => update on storage threshold (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383). configurable. Next 33 bits => 58- 90 => last update timestamp (enough until 16 March 2242 -> max value 8589934591) Next 64 bits => 91-154 => supply exchange price (1e12 -> max value 18_446_744,073709551615) Next 64 bits => 155-218 => borrow exchange price (1e12 -> max value 18_446_744,073709551615) Next 1 bit => 219-219 => if 0 then ratio is supplyInterestFree / supplyWithInterest else ratio is supplyWithInterest / supplyInterestFree Next 14 bits => 220-233 => supplyRatio: supplyInterestFree / supplyWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383) Next 1 bit => 234-234 => if 0 then ratio is borrowInterestFree / borrowWithInterest else ratio is borrowWithInterest / borrowInterestFree Next 14 bits => 235-248 => borrowRatio: borrowInterestFree / borrowWithInterest (in 1e2: 100% = 10_000; 1% = 100 -> max value 16_383)", "supplyAmount": "supply amount for the operation. if >0 then a deposit happened, if <0 then a withdrawal happened. if 0 then nothing.", "token": "token address for which this operation was executed", "totalAmounts": "updated total amounts, stacked uint256 as written to storage: First 64 bits => 0- 63 => total supply with interest in raw (totalSupply = totalSupplyRaw * supplyExchangePrice); BigMath: 56 | 8 Next 64 bits => 64-127 => total interest free supply in normal token amount (totalSupply = totalSupply); BigMath: 56 | 8 Next 64 bits => 128-191 => total borrow with interest in raw (totalBorrow = totalBorrowRaw * borrowExchangePrice); BigMath: 56 | 8 Next 64 bits => 192-255 => total interest free borrow in normal token amount (totalBorrow = totalBorrow); BigMath: 56 | 8", "user": "protocol that triggered this operation (e.g. via an fToken or via Vault protocol)", "withdrawTo": "address that funds where withdrawn to (if supplyAmount <0)" } } }, "kind": "dev", "methods": {}, "title": "Fluid Liquidity UserModule", "version": 1 }, "userdoc": { "events": { "BorrowRateMaxCap()": { "notice": "emitted if the calculated borrow rate surpassed max borrow rate (16 bits) and was capped at maximum value 65535" }, "LogOperate(address,address,int256,int256,address,address,uint256,uint256)": { "notice": "emitted on any `operate()` execution: deposit / supply / withdraw / borrow. includes info related to the executed operation, new total amounts (packed uint256 of BigMath numbers as in storage) and exchange prices (packed uint256 as in storage)." } }, "kind": "user", "methods": { "operate(address,int256,int256,address,address,bytes)": { "notice": "inheritdoc IFluidLiquidity" } }, "notice": "Fluid Liquidity public facing endpoint logic contract that implements the `operate()` method. operate can be used to deposit, withdraw, borrow & payback funds, given that they have the necessary user config allowance. Interacting users must be allowed via the Fluid Liquidity AdminModule first. Intended users are thus allow-listed protocols, e.g. the Lending protocol (fTokens), Vault protocol etc.", "version": 1 }, "storageLayout": { "storage": [ { "astId": 17816, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_revenueCollector", "offset": 0, "slot": "0", "type": "t_address" }, { "astId": 17819, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_status", "offset": 0, "slot": "1", "type": "t_uint256" }, { "astId": 17824, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_isAuth", "offset": 0, "slot": "2", "type": "t_mapping(t_address,t_uint256)" }, { "astId": 17829, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_isGuardian", "offset": 0, "slot": "3", "type": "t_mapping(t_address,t_uint256)" }, { "astId": 17834, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_userClass", "offset": 0, "slot": "4", "type": "t_mapping(t_address,t_uint256)" }, { "astId": 17839, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_exchangePricesAndConfig", "offset": 0, "slot": "5", "type": "t_mapping(t_address,t_uint256)" }, { "astId": 17844, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_rateData", "offset": 0, "slot": "6", "type": "t_mapping(t_address,t_uint256)" }, { "astId": 17849, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_totalAmounts", "offset": 0, "slot": "7", "type": "t_mapping(t_address,t_uint256)" }, { "astId": 17856, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_userSupplyData", "offset": 0, "slot": "8", "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" }, { "astId": 17863, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_userBorrowData", "offset": 0, "slot": "9", "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))" }, { "astId": 17867, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_listedTokens", "offset": 0, "slot": "10", "type": "t_array(t_address)dyn_storage" }, { "astId": 17872, "contract": "contracts/liquidity/userModule/main.sol:FluidLiquidityUserModule", "label": "_configs2", "offset": 0, "slot": "11", "type": "t_mapping(t_address,t_uint256)" } ], "types": { "t_address": { "encoding": "inplace", "label": "address", "numberOfBytes": "20" }, "t_array(t_address)dyn_storage": { "base": "t_address", "encoding": "dynamic_array", "label": "address[]", "numberOfBytes": "32" }, "t_mapping(t_address,t_mapping(t_address,t_uint256))": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => mapping(address => uint256))", "numberOfBytes": "32", "value": "t_mapping(t_address,t_uint256)" }, "t_mapping(t_address,t_uint256)": { "encoding": "mapping", "key": "t_address", "label": "mapping(address => uint256)", "numberOfBytes": "32", "value": "t_uint256" }, "t_uint256": { "encoding": "inplace", "label": "uint256", "numberOfBytes": "32" } } } }