creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/utils/EscrowLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\npragma solidity ^0.8.20;\n\nimport {Denominations} from \"chainlink/Denominations.sol\";\nimport {IERC20} from \"openzeppelin/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"openzeppelin/token/ERC20/utils/SafeERC20.sol\";\nimport {IOracle} from \"../interfaces/IOracle.sol\";\nimport {ILineOfCredit} from \"../interfaces/ILineOfCredit.sol\";\nimport {IEscrow} from \"../interfaces/IEscrow.sol\";\nimport {CreditLib} from \"../utils/CreditLib.sol\";\nimport {LineLib} from \"../utils/LineLib.sol\";\n\nstruct EscrowState {\n    address line;\n    address[] collateralTokens;\n    /// if lenders allow token as collateral. ensures uniqueness in collateralTokens\n    mapping(address => bool) enabled;\n    /// tokens used as collateral (must be able to value with oracle)\n    mapping(address => IEscrow.Deposit) deposited;\n}\n\nlibrary EscrowLib {\n    using SafeERC20 for IERC20;\n\n    // return if have collateral but no debt\n    uint256 constant MAX_INT = type(uint256).max;\n\n    /**\n     * @notice updates the cratio according to the collateral value vs line value\n     * @dev calls accrue interest on the line contract to update the latest interest payable\n     * @param oracle - address to call for collateral token prices\n     * @return cratio - the updated collateral ratio in 4 decimals\n     */\n    function _getLatestCollateralRatio(EscrowState storage self, address oracle) public returns (uint256) {\n        (uint256 principal, uint256 interest) = ILineOfCredit(self.line).updateOutstandingDebt();\n        uint256 debtValue = principal + interest;\n        uint256 collateralValue = _getCollateralValue(self, oracle);\n        if (debtValue == 0) return MAX_INT;\n        if (collateralValue == 0) return 0;\n\n        uint256 _numerator = collateralValue * 10 ** 5; // scale to 4 decimals\n        return ((_numerator / debtValue) + 5) / 10;\n    }\n\n    /**\n     * @notice - Iterates over all enabled tokens and calculates the USD value of all deposited collateral\n     * @param oracle - address to call for collateral token prices\n     * @return totalCollateralValue - the collateral's USD value in 8 decimals\n     */\n    function _getCollateralValue(EscrowState storage self, address oracle) public returns (uint256) {\n        uint256 collateralValue;\n        // gas savings\n        uint256 length = self.collateralTokens.length;\n        IOracle o = IOracle(oracle);\n        IEscrow.Deposit memory d;\n        for (uint256 i; i < length; ++i) {\n            address token = self.collateralTokens[i];\n            d = self.deposited[token];\n            // new var so we don't override original deposit amount for 4626 tokens\n            uint256 deposit = d.amount;\n            if (deposit != 0) {\n                if (d.isERC4626) {\n                    // this conversion could shift, hence it is best to get it each time\n                    (bool success, bytes memory assetAmount) = token.call(\n                        abi.encodeWithSignature(\"previewRedeem(uint256)\", deposit)\n                    );\n                    if (!success) continue;\n                    deposit = abi.decode(assetAmount, (uint256));\n                }\n                collateralValue += CreditLib.calculateValue(o.getLatestAnswer(d.asset), deposit, d.assetDecimals);\n            }\n        }\n\n        return collateralValue;\n    }\n\n    /** see Escrow.addCollateral */\n    function addCollateral(\n        EscrowState storage self,\n        address oracle,\n        uint256 amount,\n        address token\n    ) external returns (uint256) {\n        if (amount == 0) {\n            revert InvalidZeroAmount();\n        }\n        if (!self.enabled[token]) {\n            revert InvalidCollateral();\n        }\n\n        LineLib.receiveTokenOrETH(token, msg.sender, amount);\n\n        self.deposited[token].amount += amount;\n\n        emit AddCollateral(token, amount);\n\n        return _getLatestCollateralRatio(self, oracle);\n    }\n\n    /** see Escrow.enableCollateral */\n    function enableCollateral(EscrowState storage self, address oracle, address token) external returns (bool) {\n        if (msg.sender != ILineOfCredit(self.line).arbiter()) {\n            revert ArbiterOnly();\n        }\n        if (token == address(0) || token == Denominations.ETH) {\n            revert EthSupportDisabled();\n        }\n\n        bool isEnabled = self.enabled[token];\n        IEscrow.Deposit memory deposit = self.deposited[token]; // gas savings\n        if (!isEnabled) {\n            (bool passed, bytes memory tokenAddrBytes) = token.call(abi.encodeWithSignature(\"asset()\"));\n\n            bool is4626 = tokenAddrBytes.length != 0 && passed;\n            deposit.isERC4626 = is4626;\n\n            // if 4626 save the underlying token to use for oracle pricing\n            deposit.asset = !is4626 ? token : abi.decode(tokenAddrBytes, (address));\n\n            int256 price = IOracle(oracle).getLatestAnswer(deposit.asset);\n            if (price <= 0) {\n                revert InvalidCollateral();\n            }\n\n            (bool successDecimals, bytes memory decimalBytes) = deposit.asset.call(\n                abi.encodeWithSignature(\"decimals()\")\n            );\n\n            if (!successDecimals || decimalBytes.length == 0) {\n                revert InvalidTokenDecimals();\n            }\n            deposit.assetDecimals = abi.decode(decimalBytes, (uint8));\n\n            // update collateral settings\n            self.enabled[token] = true;\n            self.deposited[token] = deposit;\n            self.collateralTokens.push(token);\n            emit EnableCollateral(deposit.asset);\n        }\n\n        return true;\n    }\n\n    /** see Escrow.releaseCollateral */\n    function releaseCollateral(\n        EscrowState storage self,\n        address borrower,\n        address oracle,\n        uint256 minimumCollateralRatio,\n        uint256 amount,\n        address token,\n        address to\n    ) external returns (uint256) {\n        if (amount == 0) {\n            revert InvalidZeroAmount();\n        }\n        if (msg.sender != borrower) {\n            revert CallerAccessDenied();\n        }\n        if (self.deposited[token].amount < amount) {\n            revert InvalidCollateral();\n        }\n        self.deposited[token].amount -= amount;\n\n        LineLib.sendOutTokenOrETH(token, to, amount);\n\n        uint256 cratio = _getLatestCollateralRatio(self, oracle);\n        // fail if reduces cratio below min\n        // but allow borrower to always withdraw if fully repaid\n        if (\n            cratio < minimumCollateralRatio && // if undercollateralized, revert;\n            ILineOfCredit(self.line).status() != LineLib.STATUS.REPAID // if repaid, skip;\n        ) {\n            revert UnderCollateralized();\n        }\n\n        emit RemoveCollateral(token, amount);\n\n        return cratio;\n    }\n\n    /** see Escrow.getCollateralRatio */\n    function getCollateralRatio(EscrowState storage self, address oracle) external returns (uint256) {\n        return _getLatestCollateralRatio(self, oracle);\n    }\n\n    /** see Escrow.getCollateralValue */\n    function getCollateralValue(EscrowState storage self, address oracle) external returns (uint256) {\n        return _getCollateralValue(self, oracle);\n    }\n\n    /** see Escrow.liquidate */\n    function liquidate(EscrowState storage self, uint256 amount, address token, address to) external returns (bool) {\n        if (amount == 0) {\n            revert InvalidZeroAmount();\n        }\n\n        if (msg.sender != self.line) {\n            revert CallerAccessDenied();\n        }\n        if (self.deposited[token].amount < amount) {\n            revert InvalidCollateral();\n        }\n\n        self.deposited[token].amount -= amount;\n\n        LineLib.sendOutTokenOrETH(token, to, amount);\n\n        return true;\n    }\n\n    /** see Escrow.isLiquidatable */\n    function isLiquidatable(\n        EscrowState storage self,\n        address oracle,\n        uint256 minimumCollateralRatio\n    ) external returns (bool) {\n        return _getLatestCollateralRatio(self, oracle) < minimumCollateralRatio;\n    }\n\n    /** see Escrow.updateLine */\n    function updateLine(EscrowState storage self, address _line) external returns (bool) {\n        require(msg.sender == self.line);\n        self.line = _line;\n        return true;\n    }\n\n    event AddCollateral(address indexed token, uint256 indexed amount);\n\n    event RemoveCollateral(address indexed token, uint256 indexed amount);\n\n    event EnableCollateral(address indexed token);\n\n    event Liquidate(address indexed token, uint256 indexed amount);\n\n    error ArbiterOnly();\n\n    error InvalidZeroAmount();\n\n    error InvalidCollateral();\n\n    error EthSupportDisabled();\n\n    error CallerAccessDenied();\n\n    error UnderCollateralized();\n\n    error NotLiquidatable();\n\n    error InvalidTokenDecimals();\n}\n"
      },
      "lib/chainlink/contracts/src/v0.8/Denominations.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nlibrary Denominations {\n  address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n  address public constant BTC = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;\n\n  // Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217\n  address public constant USD = address(840);\n  address public constant GBP = address(826);\n  address public constant EUR = address(978);\n  address public constant JPY = address(392);\n  address public constant KRW = address(410);\n  address public constant CNY = address(156);\n  address public constant AUD = address(36);\n  address public constant CAD = address(124);\n  address public constant CHF = address(756);\n  address public constant ARS = address(32);\n  address public constant PHP = address(608);\n  address public constant NZD = address(554);\n  address public constant SGD = address(702);\n  address public constant NGN = address(566);\n  address public constant ZAR = address(710);\n  address public constant RUB = address(643);\n  address public constant INR = address(356);\n  address public constant BRL = address(986);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\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 value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens as the allowance of `spender` over the\n     * 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 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` 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(address from, address to, uint256 value) external returns (bool);\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC20Permit} from \"../extensions/IERC20Permit.sol\";\nimport {Address} from \"../../../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    /**\n     * @dev An operation with an ERC20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\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);\n        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\n            revert SafeERC20FailedOperation(address(token));\n        }\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     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\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 cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\n    }\n}\n"
      },
      "contracts/interfaces/IOracle.sol": {
        "content": " pragma solidity ^0.8.16;\n\ninterface IOracle {\n    /** current price for token asset. denominated in USD */\n    function getLatestAnswer(address token) external returns (int256);\n\n    /** Readonly function providing the current price for token asset. denominated in USD */\n    function _getLatestAnswer(address token) external view returns (int256);\n}\n"
      },
      "contracts/interfaces/ILineOfCredit.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\n pragma solidity ^0.8.16;\n\nimport {LineLib} from \"../utils/LineLib.sol\";\nimport {IOracle} from \"../interfaces/IOracle.sol\";\n\ninterface ILineOfCredit {\n    // Lender data\n    struct Credit {\n        //  all denominated in token, not USD\n        uint256 deposit; // The total liquidity provided by a Lender in a given token on a Line of Credit\n        uint256 principal; // The amount of a Lender's Deposit on a Line of Credit that has actually been drawn down by the Borrower (in Tokens)\n        uint256 interestAccrued; // Interest due by a Borrower but not yet repaid to the Line of Credit contract\n        uint256 interestRepaid; // Interest repaid by a Borrower to the Line of Credit contract but not yet withdrawn by a Lender\n        uint8 decimals; // Decimals of Credit Token for calcs\n        address token; // The token being lent out (Credit Token)\n        address lender; // The person to repay\n        bool isOpen; // Status of position\n    }\n\n    // General Events\n    event UpdateStatus(uint256 indexed status); // store as normal uint so it can be indexed in subgraph\n\n    event DeployLine(address indexed oracle, address indexed arbiter, address indexed borrower);\n\n    event SortedIntoQ(bytes32 indexed id, uint256 indexed newIdx, uint256 indexed oldIdx, bytes32 oldId);\n\n    // MutualConsent borrower/lender events\n\n    event AddCredit(address indexed lender, address indexed token, uint256 indexed deposit, bytes32 id);\n    // can only reference id once AddCredit is emitted because it will be indexed offchain\n\n    event SetRates(bytes32 indexed id, uint128 indexed dRate, uint128 indexed fRate);\n\n    event IncreaseCredit(bytes32 indexed id, uint256 indexed deposit);\n\n    // Lender Events\n\n    // Emits data re Lender removes funds (principal) - there is no corresponding function, just withdraw()\n    event WithdrawDeposit(bytes32 indexed id, uint256 indexed amount);\n\n    // Emits data re Lender withdraws interest - there is no corresponding function, just withdraw()\n    event WithdrawProfit(bytes32 indexed id, uint256 indexed amount);\n\n    // Emitted when any credit line is closed by the line's borrower or the position's lender\n    event CloseCreditPosition(bytes32 indexed id);\n\n    // After accrueInterest runs, emits the amount of interest added to a Borrower's outstanding balance of interest due\n    // but not yet repaid to the Line of Credit contract\n    event InterestAccrued(bytes32 indexed id, uint256 indexed amount);\n\n    // Borrower Events\n\n    // receive full line or drawdown on credit\n    event Borrow(bytes32 indexed id, uint256 indexed amount);\n\n    // Emits that a Borrower has repaid an amount of interest Results in an increase in interestRepaid, i.e. interest not yet withdrawn by a Lender). There is no corresponding function\n    event RepayInterest(bytes32 indexed id, uint256 indexed amount);\n\n    // Emits that a Borrower has repaid an amount of principal - there is no corresponding function\n    event RepayPrincipal(bytes32 indexed id, uint256 indexed amount);\n\n    event Default(bytes32 indexed id);\n\n    // Access Errors\n    error NotActive();\n    error NotBorrowing();\n    error CallerAccessDenied();\n\n    // Tokens\n    error TokenTransferFailed();\n    error NoTokenPrice();\n\n    // Line\n    error BadModule(address module);\n    error NoLiquidity();\n    error PositionExists();\n    error CloseFailedWithPrincipal();\n    error NotInsolvent(address module);\n    error NotLiquidatable();\n    error AlreadyInitialized();\n    error PositionIsClosed();\n    error RepayAmountExceedsDebt(uint256 totalAvailable);\n    error CantStepQ();\n    error EthSupportDisabled();\n    error BorrowFailed();\n\n    // Fully public functions\n\n    /**\n     * @notice - Runs logic to ensure Line owns all modules are configured properly - collateral, interest rates, arbiter, etc.\n     *          - Changes `status` from UNINITIALIZED to ACTIVE\n     * @dev     - Reverts on failure to update status\n     */\n    function init() external;\n\n    // MutualConsent functions\n\n    /**\n    * @notice        - On first call, creates proposed terms and emits MutualConsentRegistsered event. No position is created.\n                      - On second call, creates position and stores in Line contract, sets interest rates, and starts accruing facility rate fees.\n    * @dev           - Requires mutualConsent participants send EXACT same params when calling addCredit\n    * @dev           - Fully executes function after a Borrower and a Lender have agreed terms, both Lender and borrower have agreed through mutualConsent\n    * @dev           - callable by `lender` and `borrower`\n    * @param drate   - The interest rate charged to a Borrower on borrowed / drawn down funds. In bps, 4 decimals.\n    * @param frate   - The interest rate charged to a Borrower on the remaining funds available, but not yet drawn down\n                        (rate charged on the available headroom). In bps, 4 decimals.\n    * @param amount  - The amount of Credit Token to initially deposit by the Lender\n    * @param token   - The Credit Token, i.e. the token to be lent out\n    * @param lender  - The address that will manage credit line\n    * @return id     - Lender's position id to look up in `credits`\n  */\n    function addCredit(\n        uint128 drate,\n        uint128 frate,\n        uint256 amount,\n        address token,\n        address lender\n    ) external payable returns (bytes32);\n\n    /**\n     * @notice           - lets Lender and Borrower update rates on the lender's position\n     *                   - accrues interest before updating terms, per InterestRate docs\n     *                   - can do so even when LIQUIDATABLE for the purpose of refinancing and/or renego\n     * @dev              - callable by Borrower or Lender\n     * @param id         - position id that we are updating\n     * @param drate      - new drawn rate. In bps, 4 decimals\n     * @param frate      - new facility rate. In bps, 4 decimals\n     */\n    function setRates(bytes32 id, uint128 drate, uint128 frate) external;\n\n    /**\n     * @notice           - Lets a Lender and a Borrower increase the credit limit on a position\n     * @dev              - line status must be ACTIVE\n     * @dev              - callable by borrower\n     * @dev              - The function retains the `payable` designation, despite not accepting Eth via mutualConsent modifier, as a gas-optimization\n     * @param id         - position id that we are updating\n     * @param amount     - amount to deposit by the Lender\n     */\n    function increaseCredit(bytes32 id, uint256 amount) external payable;\n\n    // Borrower functions\n\n    /**\n     * @notice       - Borrower chooses which lender position draw down on and transfers tokens from Line contract to Borrower\n     * @dev          - callable by borrower\n     * @param id     - the position to draw down on\n     * @param amount - amount of tokens the borrower wants to withdraw\n     */\n    function borrow(bytes32 id, uint256 amount) external;\n\n    /**\n     * @notice       - Transfers token used in position id from msg.sender to Line contract.\n     * @dev          - Available for anyone to deposit Credit Tokens to be available to be withdrawn by Lenders\n     * @dev          - The function retains the `payable` designation, despite reverting with a non-zero msg.value, as a gas-optimization\n     * @notice       - see LineOfCredit._repay() for more details\n     * @param amount - amount of `token` in `id` to pay back\n     */\n    function depositAndRepay(uint256 amount) external payable;\n\n    /**\n     * @notice       - A Borrower deposits enough tokens to repay and close a credit line.\n     * @dev          - callable by borrower\n     * @dev          - The function retains the `payable` designation, despite reverting with a non-zero msg.value, as a gas-optimization\n     */\n    function depositAndClose() external payable;\n\n    /**\n     * @notice - Removes and deletes a position, preventing any more borrowing or interest.\n     *         - Requires that the position principal has already been repais in full\n     * @dev      - MUST repay accrued interest from facility fee during call\n     * @dev - callable by `borrower` or Lender\n     * @dev          - The function retains the `payable` designation, despite reverting with a non-zero msg.value, as a gas-optimization\n     * @param id -the position id to be closed\n     */\n    function close(bytes32 id) external payable;\n\n    // Lender functions\n\n    /**\n     * @notice - Withdraws liquidity from a Lender's position available to the Borrower.\n     *         - Lender is only allowed to withdraw tokens not already lent out\n     *         - Withdraws from repaid interest (profit) first and then deposit is reduced\n     * @dev - can only withdraw tokens from their own position. If multiple lenders lend DAI, the lender1 can't withdraw using lender2's tokens\n     * @dev - callable by Lender on `id`\n     * @param id - the position id that Lender is withdrawing from\n     * @param amount - amount of tokens the Lender would like to withdraw (withdrawn amount may be lower)\n     */\n    function withdraw(bytes32 id, uint256 amount) external;\n\n    // Arbiter functions\n    /**\n     * @notice - Allow the Arbiter to signify that the Borrower is incapable of repaying debt permanently.\n     *         - Recoverable funds for Lender after declaring insolvency = deposit + interestRepaid - principal\n     * @dev    - Needed for onchain impairment accounting e.g. updating ERC4626 share price\n     *         - MUST NOT have collateral left for call to succeed. Any collateral must already have been liquidated.\n     * @dev    - Callable only by Arbiter.\n     */\n    function declareInsolvent() external;\n\n    /**\n     *\n     * @notice - Updates accrued interest for the whole Line of Credit facility (i.e. for all credit lines)\n     * @dev    - Loops over all position ids and calls related internal functions during which InterestRateCredit.sol\n     *           is called with the id data and then 'interestAccrued' is updated.\n     * @dev    - The related internal function _accrue() is called by other functions any time the balance on an individual\n     *           credit line changes or if the interest rates of a credit line are changed by mutual consent\n     *           between a Borrower and a Lender.\n     */\n    function accrueInterest() external;\n\n    function healthcheck() external returns (LineLib.STATUS);\n\n    /**\n     * @notice - Cycles through position ids andselects first position with non-null principal to the zero index\n     * @dev - Only works if the first element in the queue is null\n     */\n    function stepQ() external;\n\n    /**\n     * @notice - Returns the total debt of a Borrower across all positions for all Lenders.\n     * @dev    - Denominated in USD, 8 decimals.\n     * @dev    - callable by anyone\n     * @return totalPrincipal - total amount of principal, in USD, owed across all positions\n     * @return totalInterest - total amount of interest, in USD,  owed across all positions\n     */\n    function updateOutstandingDebt() external returns (uint256, uint256);\n\n    // State getters\n\n    function status() external returns (LineLib.STATUS);\n\n    function borrower() external returns (address);\n\n    function arbiter() external returns (address);\n\n    function oracle() external returns (IOracle);\n\n    /**\n     * @notice - getter for amount of active ids + total ids in list\n     * @return - (uint256, uint256) - active credit lines, total length\n     */\n    function counts() external view returns (uint256, uint256);\n\n    /**\n     * @notice - getter for amount of active ids + total ids in list\n     * @return - (uint256, uint256) - active credit lines, total length\n     */\n\n    function interestAccrued(bytes32 id) external returns (uint256);\n\n    /**\n     * @notice - info on the next lender position that must be repaid\n     * @return - (bytes32, address, address, uint, uint) - id, lender, token, principal, interestAccrued\n     */\n    function nextInQ() external view returns (bytes32, address, address, uint256, uint256, uint256, uint128, uint128);\n\n    /**\n     * @notice - how many tokens can be withdrawn from positions by borrower or lender\n     * @return - (uint256, uint256) - remaining deposit, claimable interest\n     */\n    function available(bytes32 id) external returns (uint256, uint256);\n}\n"
      },
      "contracts/interfaces/IEscrow.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\n pragma solidity ^0.8.16;\n\ninterface IEscrow {\n    struct Deposit {\n        uint amount;\n        bool isERC4626;\n        address asset; // eip4626 asset else the erc20 token itself\n        uint8 assetDecimals;\n    }\n\n    event AddCollateral(address indexed token, uint indexed amount);\n\n    event RemoveCollateral(address indexed token, uint indexed amount);\n\n    event EnableCollateral(address indexed token);\n\n    error InvalidCollateral();\n\n    error CallerAccessDenied();\n\n    error UnderCollateralized();\n\n    error NotLiquidatable();\n\n    // State var getters.\n\n    function line() external returns (address);\n\n    function oracle() external returns (address);\n\n    function borrower() external returns (address);\n\n    function minimumCollateralRatio() external returns (uint32);\n\n    // Functions\n\n    function isLiquidatable() external returns (bool);\n\n    function updateLine(address line_) external returns (bool);\n\n    function getCollateralRatio() external returns (uint);\n\n    function getCollateralValue() external returns (uint);\n\n    function enableCollateral(address token) external returns (bool);\n\n    function addCollateral(uint amount, address token) external payable returns (uint);\n\n    function releaseCollateral(uint amount, address token, address to) external returns (uint);\n\n    function liquidate(uint amount, address token, address to) external returns (bool);\n}\n"
      },
      "contracts/utils/CreditLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\n pragma solidity ^0.8.16;\nimport {Denominations} from \"chainlink/Denominations.sol\";\nimport {ILineOfCredit} from \"../interfaces/ILineOfCredit.sol\";\nimport {IOracle} from \"../interfaces/IOracle.sol\";\nimport {IInterestRateCredit} from \"../interfaces/IInterestRateCredit.sol\";\nimport {ILineOfCredit} from \"../interfaces/ILineOfCredit.sol\";\nimport {LineLib} from \"./LineLib.sol\";\n\n/**\n * @title Credit Cooperative Line of Credit Library\n * @notice Core logic and variables to be reused across all Credit Cooperative Marketplace Line of Credit contracts\n */\n\nlibrary CreditLib {\n    event AddCredit(address indexed lender, address indexed token, uint256 indexed deposit, bytes32 id);\n\n    /// @notice Emitted when Lender withdraws from their initial deposit\n    event WithdrawDeposit(bytes32 indexed id, uint256 indexed amount);\n\n    /// @notice Emitted when Lender withdraws interest paid by borrower\n    event WithdrawProfit(bytes32 indexed id, uint256 indexed amount);\n\n    /// @notice Emits amount of interest (denominated in credit token) added to a Borrower's outstanding balance\n    event InterestAccrued(bytes32 indexed id, uint256 indexed amount);\n\n    // Borrower Events\n\n    /// @notice Emits when Borrower has drawn down an amount (denominated in credit.token) on a credit line\n    event Borrow(bytes32 indexed id, uint256 indexed amount);\n\n    /// @notice Emits that a Borrower has repaid some amount of interest (denominated in credit.token)\n    event RepayInterest(bytes32 indexed id, uint256 indexed amount);\n\n    /// @notice Emits that a Borrower has repaid some amount of principal (denominated in credit.token)\n    event RepayPrincipal(bytes32 indexed id, uint256 indexed amount);\n\n    // Errors\n\n    error NoTokenPrice();\n\n    error PositionExists();\n\n    error RepayAmountExceedsDebt(uint256 totalAvailable);\n\n    error InvalidTokenDecimals();\n\n    error NoQueue();\n\n    error PositionIsClosed();\n\n    error NoLiquidity();\n\n    error CloseFailedWithPrincipal();\n\n    error CallerAccessDenied();\n\n    /**\n     * @dev          - Creates a deterministic hash id for a credit line provided by a single Lender for a given token on a Line of Credit facility\n     * @param line   - The Line of Credit facility concerned\n     * @param lender - The address managing the credit line concerned\n     * @param token  - The token being lent out on the credit line concerned\n     * @return id\n     */\n    function computeId(address line, address lender, address token) external pure returns (bytes32) {\n        return keccak256(abi.encode(line, lender, token));\n    }\n\n    // getOutstandingDebt() is called by updateOutstandingDebt()\n    function getOutstandingDebt(\n        ILineOfCredit.Credit memory credit,\n        bytes32 id,\n        address oracle,\n        address interestRate\n    ) external returns (ILineOfCredit.Credit memory c, uint256 principal, uint256 interest) {\n        c = accrue(credit, id, interestRate);\n\n        int256 price = IOracle(oracle).getLatestAnswer(c.token);\n\n        principal = calculateValue(price, c.principal, c.decimals);\n        interest = calculateValue(price, c.interestAccrued, c.decimals);\n\n        return (c, principal, interest);\n    }\n\n    /**\n     * @notice         - Calculates value of tokens.  Used for calculating the USD value of principal and of interest during getOutstandingDebt()\n     * @dev            - Assumes Oracle returns answers in USD with 1e8 decimals\n     *                 - If price < 0 then we treat it as 0.\n     * @param price    - The Oracle price of the asset. 8 decimals\n     * @param amount   - The amount of tokens being valued.\n     * @param decimals - Token decimals to remove for USD price\n     * @return         - The total USD value of the amount of tokens being valued in 8 decimals\n     */\n    function calculateValue(int price, uint256 amount, uint8 decimals) public pure returns (uint256) {\n        return price <= 0 ? 0 : (amount * uint(price)) / (1 * 10 ** decimals);\n    }\n\n    /**\n     * see ILineOfCredit._createCredit\n     * @notice called by LineOfCredit._createCredit during every repayment function\n     * @param oracle - interset rate contract used by line that will calculate interest owed\n     */\n    function create(\n        bytes32 id,\n        uint256 amount,\n        address lender,\n        address token,\n        address oracle\n    ) external returns (ILineOfCredit.Credit memory credit) {\n        int price = IOracle(oracle).getLatestAnswer(token);\n        if (price <= 0) {\n            revert NoTokenPrice();\n        }\n\n        (bool passed, bytes memory result) = token.call(abi.encodeWithSignature(\"decimals()\"));\n\n        if (!passed || result.length == 0) {\n            revert InvalidTokenDecimals();\n        }\n\n        uint8 decimals = abi.decode(result, (uint8));\n\n        credit = ILineOfCredit.Credit({\n            lender: lender,\n            token: token,\n            decimals: decimals,\n            deposit: amount,\n            principal: 0,\n            interestAccrued: 0,\n            interestRepaid: 0,\n            isOpen: true\n        });\n\n        emit AddCredit(lender, token, amount, id);\n\n        return credit;\n    }\n\n    /**\n     * see ILineOfCredit._repay\n     * @notice called by LineOfCredit._repay during every repayment function\n     * @dev uses uncheckd math. assumes checks have been done in caller\n     * @param credit - The lender position being repaid\n     */\n    function repay(\n        ILineOfCredit.Credit memory credit,\n        bytes32 id,\n        uint256 amount,\n        address payer\n    ) external returns (ILineOfCredit.Credit memory) {\n        if (!credit.isOpen) {\n            revert PositionIsClosed();\n        }\n\n        unchecked {\n            if (amount > credit.principal + credit.interestAccrued) {\n                revert RepayAmountExceedsDebt(credit.principal + credit.interestAccrued);\n            }\n\n            if (amount <= credit.interestAccrued) {\n                credit.interestAccrued -= amount;\n                credit.interestRepaid += amount;\n                emit RepayInterest(id, amount);\n            } else {\n                uint256 interest = credit.interestAccrued;\n                uint256 principalPayment = amount - interest;\n\n                // update individual credit line denominated in token\n                credit.principal -= principalPayment;\n                credit.interestRepaid += interest;\n                credit.interestAccrued = 0;\n\n                emit RepayInterest(id, interest);\n                emit RepayPrincipal(id, principalPayment);\n            }\n        }\n\n        // if we arent using funds from reserves to repay then pull tokens from target\n        if(payer != address(0)) {\n            LineLib.receiveTokenOrETH(credit.token, payer, amount);\n        }\n\n        return credit;\n    }\n\n    /**\n     * see ILineOfCredit.withdraw\n     * @notice called by LineOfCredit.withdraw during every repayment function\n     * @dev uses uncheckd math. assumes checks have been done in caller\n     * @param credit - The lender position that is being bwithdrawn from\n     */\n    function withdraw(\n        ILineOfCredit.Credit memory credit,\n        bytes32 id,\n        address caller,\n        uint256 amount\n    ) external returns (ILineOfCredit.Credit memory) {\n        if (caller != credit.lender) {\n            revert CallerAccessDenied();\n        }\n\n        unchecked {\n            if (amount > credit.deposit - credit.principal + credit.interestRepaid) {\n                revert ILineOfCredit.NoLiquidity();\n            }\n\n            if (amount > credit.interestRepaid) {\n                uint256 interest = credit.interestRepaid;\n\n                credit.deposit -= amount - interest;\n                credit.interestRepaid = 0;\n\n                // emit events before setting to 0\n                emit WithdrawDeposit(id, amount - interest);\n                emit WithdrawProfit(id, interest);\n            } else {\n                credit.interestRepaid -= amount;\n                emit WithdrawProfit(id, amount);\n            }\n        }\n\n        LineLib.sendOutTokenOrETH(credit.token, credit.lender, amount);\n\n        return credit;\n    }\n\n    /**\n     * see ILineOfCredit._accrue\n     * @notice called by LineOfCredit._accrue during every repayment function\n     * @dev public to use in `getOutstandingDebt`\n     * @param interest - interset rate contract used by line that will calculate interest owed\n     */\n    function accrue(\n        ILineOfCredit.Credit memory credit,\n        bytes32 id,\n        address interest\n    ) public returns (ILineOfCredit.Credit memory) {\n        if (!credit.isOpen) {\n            return credit;\n        }\n        unchecked {\n            // interest will almost always be less than deposit\n            // low risk of overflow unless extremely high interest rate\n\n            // get token demoninated interest accrued\n            uint256 accruedToken = IInterestRateCredit(interest).accrueInterest(id, credit.principal, credit.deposit);\n\n            // update credit line balance\n            credit.interestAccrued += accruedToken;\n\n            emit InterestAccrued(id, accruedToken);\n            return credit;\n        }\n    }\n\n    function interestAccrued(\n        ILineOfCredit.Credit memory credit,\n        bytes32 id,\n        address interest\n    ) external view returns (uint256) {\n        return\n            credit.interestAccrued +\n            IInterestRateCredit(interest).getInterestAccrued(id, credit.principal, credit.deposit);\n    }\n\n    function getNextRateInQ(uint256 principal, bytes32 id, address interest) external view returns (uint128, uint128) {\n        if (principal == 0) {\n            revert NoQueue();\n        } else {\n            return IInterestRateCredit(interest).getRates(id);\n        }\n    }\n}\n"
      },
      "contracts/utils/LineLib.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\n pragma solidity ^0.8.16;\nimport {IInterestRateCredit} from \"../interfaces/IInterestRateCredit.sol\";\nimport {ILineOfCredit} from \"../interfaces/ILineOfCredit.sol\";\nimport {IOracle} from \"../interfaces/IOracle.sol\";\nimport {IERC20} from \"openzeppelin/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"openzeppelin/token/ERC20/utils/SafeERC20.sol\";\nimport {Denominations} from \"chainlink/Denominations.sol\";\n\n/**\n * @title Credit Cooperative Line of Credit Library\n * @notice Core logic and variables to be reused across all Credit Cooperative Marketplace Line of Credit contracts\n */\nlibrary LineLib {\n    using SafeERC20 for IERC20;\n\n    address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // mainnet WETH\n\n    error EthSentWithERC20();\n    error TransferFailed();\n    error SendingEthFailed();\n    error RefundEthFailed();\n\n    error BadToken();\n\n    event RefundIssued(address indexed recipient, uint256 value);\n\n    enum STATUS {\n        UNINITIALIZED,\n        ACTIVE,\n        LIQUIDATABLE,\n        REPAID,\n        INSOLVENT\n    }\n\n    /**\n     * @notice - Send ETH or ERC20 token from this contract to an external contract\n     * @param token - address of token to send out. Denominations.ETH for raw ETH\n     * @param receiver - address to send tokens to\n     * @param amount - amount of tokens to send\n     */\n    function sendOutTokenOrETH(address token, address receiver, uint256 amount) external returns (bool) {\n        if (token == address(0)) {\n            revert TransferFailed();\n        }\n\n        // both branches revert if call failed\n        if (token != Denominations.ETH) {\n            // ERC20\n            IERC20(token).safeTransfer(receiver, amount);\n        } else {\n            // ETH\n            bool success = _safeTransferFunds(receiver, amount);\n            if (!success) {\n                revert SendingEthFailed();\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @notice - Receive ETH or ERC20 token at this contract from an external contract\n     * @dev    - If the sender overpays, the difference will be refunded to the sender\n     * @dev    - If the sender is unable to receive the refund, it will be diverted to the calling contract\n     * @param token - address of token to receive. Denominations.ETH for raw ETH\n     * @param sender - address that is sendingtokens/ETH\n     * @param amount - amount of tokens to send\n     */\n    function receiveTokenOrETH(address token, address sender, uint256 amount) external returns (bool) {\n        if (token == address(0)) {\n            revert TransferFailed();\n        }\n        if (token != Denominations.ETH) {\n            // ERC20\n            if (msg.value != 0) {\n                revert EthSentWithERC20();\n            }\n            IERC20(token).safeTransferFrom(sender, address(this), amount);\n        } else {\n            // ETH\n            if (msg.value < amount) {\n                revert TransferFailed();\n            }\n\n            if (msg.value > amount) {\n                uint256 refund = msg.value - amount;\n\n                if (_safeTransferFunds(msg.sender, refund)) {\n                    emit RefundIssued(msg.sender, refund);\n                }\n            }\n        }\n        return true;\n    }\n\n    /**\n     * @notice - Helper function to get current balance of this contract for ERC20 or ETH\n     * @param token - address of token to check. Denominations.ETH for raw ETH\n     */\n    function getBalance(address token) external view returns (uint256) {\n        if (token == address(0)) return 0;\n        return token != Denominations.ETH ? IERC20(token).balanceOf(address(this)) : address(this).balance;\n    }\n\n    /**\n     * @notice  - Helper function to safely transfer Eth using native call\n     * @dev     - Errors should be handled in the calling function\n     * @param recipient - address of the recipient\n     * @param value - value to be sent (in wei)\n     */\n    function _safeTransferFunds(address recipient, uint256 value) internal returns (bool success) {\n        (success, ) = payable(recipient).call{value: value}(\"\");\n    }\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.20;\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 *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\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     * CAUTION: See Security Considerations above.\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"
      },
      "lib/openzeppelin-contracts/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev The ETH balance of the account is not enough to perform the operation.\n     */\n    error AddressInsufficientBalance(address account);\n\n    /**\n     * @dev There's no code at `target` (it is not a contract).\n     */\n    error AddressEmptyCode(address target);\n\n    /**\n     * @dev A call to an address target failed. The target may have reverted.\n     */\n    error FailedInnerCall();\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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        if (address(this).balance < amount) {\n            revert AddressInsufficientBalance(address(this));\n        }\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        if (!success) {\n            revert FailedInnerCall();\n        }\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 or custom error, it is bubbled\n     * up by this function (like regular Solidity function calls). However, if\n     * the call reverted with no returned reason, this function reverts with a\n     * {FailedInnerCall} error.\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    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0);\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    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        if (address(this).balance < value) {\n            revert AddressInsufficientBalance(address(this));\n        }\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n     * unsuccessful call.\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata\n    ) internal view returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            // only check if target is a contract if the call was successful and the return data is empty\n            // otherwise we already know that it was a contract\n            if (returndata.length == 0 && target.code.length == 0) {\n                revert AddressEmptyCode(target);\n            }\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n     * revert reason or with a default {FailedInnerCall} error.\n     */\n    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n        if (!success) {\n            _revert(returndata);\n        } else {\n            return returndata;\n        }\n    }\n\n    /**\n     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n     */\n    function _revert(bytes memory returndata) 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 FailedInnerCall();\n        }\n    }\n}\n"
      },
      "contracts/interfaces/IInterestRateCredit.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\n pragma solidity ^0.8.16;\n\ninterface IInterestRateCredit {\n    struct Rate {\n        // The interest rate charged to a Borrower on borrowed / drawn down funds\n        // in bps, 4 decimals\n        uint128 dRate;\n        // The interest rate charged to a Borrower on the remaining funds available, but not yet drawn down (rate charged on the available headroom)\n        // in bps, 4 decimals\n        uint128 fRate;\n        // The time stamp at which accrued interest was last calculated on an ID and then added to the overall interestAccrued (interest due but not yet repaid)\n        uint256 lastAccrued;\n    }\n\n    /**\n     * @notice - allows `lineContract to calculate how much interest is owed since it was last calculated charged at time `lastAccrued`\n     * @dev    - pure function that only calculates interest owed. Line is responsible for actually updating credit balances with returned value\n     * @dev    - callable by `lineContract`\n     * @param id - position id on Line to look up interest rates for\n     * @param drawnBalance the balance of funds that a Borrower has drawn down on the credit line\n     * @param facilityBalance the remaining balance of funds that a Borrower can still drawn down on a credit line (aka headroom)\n     *\n     * @return - the amount of interest to be repaid for this interest period\n     */\n\n    function accrueInterest(bytes32 id, uint256 drawnBalance, uint256 facilityBalance) external returns (uint256);\n\n    /**\n     * @notice - updates interest rates on a lender's position. Updates lastAccrued time to block.timestamp\n     * @dev    - MUST call accrueInterest() on Line before changing rates. If not, lender will not accrue interest over previous interest period.\n     * @dev    - callable by `line`\n     * @return - if call was successful or not\n     */\n    function setRate(bytes32 id, uint128 dRate, uint128 fRate) external returns (bool);\n\n    function getInterestAccrued(\n        bytes32 id,\n        uint256 drawnBalance,\n        uint256 facilityBalance\n    ) external view returns (uint256);\n\n    function getRates(bytes32 id) external view returns (uint128, uint128);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "chainlink/=lib/chainlink/contracts/src/v0.8/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "openzeppelin/=lib/openzeppelin-contracts/contracts/",
        "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
        "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
        "openzeppelin-contracts/=lib/openzeppelin-contracts/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "london",
      "libraries": {
        "contracts/utils/CreditLib.sol": {
          "CreditLib": "0x4dca189d7fb51d9cc375e4d697e5800c5d21ff87"
        },
        "contracts/utils/EscrowLib.sol": {
          "EscrowLib": "0x9ae9c76276e503105f20c8b452ccd0c4ee3b2df2"
        },
        "contracts/utils/LineLib.sol": {
          "LineLib": "0x73cb72a7efaddd99cdd2d110e2f4b8b65bf3b812"
        }
      }
    }
  }}