creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/modules/credit/SecuredLine.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 {IERC20} from \"openzeppelin/token/ERC20/IERC20.sol\";\nimport {LineLib} from \"../../utils/LineLib.sol\";\nimport {EscrowedLine} from \"./EscrowedLine.sol\";\nimport {SpigotedLine} from \"./SpigotedLine.sol\";\nimport {SpigotedLineLib} from \"../../utils/SpigotedLineLib.sol\";\nimport {LineOfCredit} from \"./LineOfCredit.sol\";\nimport {ILineOfCredit} from \"../../interfaces/ILineOfCredit.sol\";\nimport {ISecuredLine} from \"../../interfaces/ISecuredLine.sol\";\n\n/**\n * @title  - Credit Cooperative Secured Line of Credit\n * @notice - The SecuredLine combines both collateral modules (SpigotedLine + EscrowedLine) with core lending functionality from LineOfCredit\n *         - to create a fully secured lending facility backed by revenue via Spigot or tokens via Escrow.\n * @dev    - modifies _liquidate(), _healthcheck(), _init(), and _declareInsolvent() functionality\n */\ncontract SecuredLine is SpigotedLine, EscrowedLine, ISecuredLine {\n    constructor(\n        address oracle_,\n        address arbiter_,\n        address borrower_,\n        address payable swapTarget_,\n        address spigot_,\n        address escrow_,\n        uint ttl_,\n        uint8 defaultSplit_\n    ) SpigotedLine(oracle_, arbiter_, borrower_, spigot_, swapTarget_, ttl_, defaultSplit_) EscrowedLine(escrow_) {}\n\n    /**\n     * @dev requires both Spigot and Escrow to pass _init to succeed\n     */\n    function _init() internal virtual override(SpigotedLine, EscrowedLine) {\n        SpigotedLine._init();\n        EscrowedLine._init();\n    }\n\n    /// see ISecuredLine.rollover\n    function rollover(address newLine) external override onlyBorrower {\n        // require all debt successfully paid already\n        if (status != LineLib.STATUS.REPAID) {\n            revert DebtOwed();\n        }\n        // require new line isn't activated yet\n        if (ILineOfCredit(newLine).status() != LineLib.STATUS.UNINITIALIZED) {\n            revert BadNewLine();\n        }\n        // we dont check borrower is same on both lines because borrower might want new address managing new line\n        EscrowedLine._rollover(newLine);\n        SpigotedLineLib.rollover(address(spigot), newLine);\n\n        // ensure that line we are sending can accept them. There is no recovery option.\n        try ILineOfCredit(newLine).init() {} catch {\n            revert BadRollover();\n        }\n    }\n\n    //  see IEscrowedLine.liquidate\n    function liquidate(uint256 amount, address targetToken) external returns (uint256) {\n        if (msg.sender != arbiter) {\n            revert CallerAccessDenied();\n        }\n        if (_updateStatus(_healthcheck()) != LineLib.STATUS.LIQUIDATABLE) {\n            revert NotLiquidatable();\n        }\n\n        // send tokens to arbiter for OTC sales\n        return _liquidate(ids[0], amount, targetToken, msg.sender);\n    }\n\n    function _healthcheck() internal override(EscrowedLine, LineOfCredit) returns (LineLib.STATUS) {\n        // check core (also cheap & internal) covenants before checking collateral conditions\n        LineLib.STATUS s = LineOfCredit._healthcheck();\n        if (s != LineLib.STATUS.ACTIVE) {\n            // return early if non-default answer\n            return s;\n        }\n\n        // check collateral ratio and return ACTIVE\n        return EscrowedLine._healthcheck();\n    }\n\n    /**\n     * @notice Wrapper for SpigotedLine and EscrowedLine internal functions\n     * @dev - both underlying calls MUST return true for Line status to change to INSOLVENT\n     * @return isInsolvent - if the entire Line including all collateral sources is fuly insolvent.\n     */\n    function _canDeclareInsolvent() internal virtual override(EscrowedLine, SpigotedLine) returns (bool) {\n        return (EscrowedLine._canDeclareInsolvent() && SpigotedLine._canDeclareInsolvent());\n    }\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"
      },
      "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"
      },
      "contracts/modules/credit/EscrowedLine.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 {IEscrow} from \"../../interfaces/IEscrow.sol\";\nimport {LineLib} from \"../../utils/LineLib.sol\";\nimport {IEscrowedLine} from \"../../interfaces/IEscrowedLine.sol\";\nimport {ILineOfCredit} from \"../../interfaces/ILineOfCredit.sol\";\n\n// used for importing NATSPEC docs, not used\nimport {LineOfCredit} from \"./LineOfCredit.sol\";\n\n// import { SecuredLine } from \"./SecuredLine.sol\";\n\nabstract contract EscrowedLine is IEscrowedLine, ILineOfCredit {\n    // contract holding all collateral for borrower\n    IEscrow public immutable escrow;\n\n    constructor(address _escrow) {\n        escrow = IEscrow(_escrow);\n    }\n\n    /**\n     * see LineOfCredit._init and SecuredLine.init\n     * @notice requires this Line is owner of the Escrowed collateral else Line will not init\n     */\n    function _init() internal virtual {\n        if (escrow.line() != address(this)) revert BadModule(address(escrow));\n    }\n\n    /**\n     * see LineOfCredit._healthcheck and SecuredLine._healthcheck\n     * @notice returns LIQUIDATABLE if Escrow contract is undercollateralized, else returns ACTIVE\n     */\n    function _healthcheck() internal virtual returns (LineLib.STATUS) {\n        if (escrow.isLiquidatable()) {\n            return LineLib.STATUS.LIQUIDATABLE;\n        }\n\n        return LineLib.STATUS.ACTIVE;\n    }\n\n    /**\n     * see SecuredlLine.liquidate\n     * @notice sends escrowed tokens to liquidation.\n     * @dev priviliegad function. Do checks before calling.\n     *\n     * @param id - The credit line being repaid via the liquidation\n     * @param amount - amount of tokens to take from escrow and liquidate\n     * @param targetToken - the token to take from escrow\n     * @param to - the liquidator to send tokens to. could be OTC address or smart contract\n     *\n     * @return amount - the total amount of `targetToken` sold to repay credit\n     */\n    function _liquidate(\n        bytes32 id,\n        uint256 amount,\n        address targetToken,\n        address to\n    ) internal virtual returns (uint256) {\n        IEscrow escrow_ = escrow; // gas savings\n        require(escrow_.liquidate(amount, targetToken, to));\n\n        emit Liquidate(id, amount, targetToken, address(escrow_));\n\n        return amount;\n    }\n\n    /**\n     * see SecuredLine.declareInsolvent\n     * @notice require all collateral sold off before declaring insolvent\n     *(@dev priviliegad internal function.\n     * @return isInsolvent - if Escrow contract is currently insolvent or not\n     */\n    function _canDeclareInsolvent() internal virtual returns (bool) {\n        if (escrow.getCollateralValue() != 0) {\n            revert NotInsolvent(address(escrow));\n        }\n        return true;\n    }\n\n    /**\n     * see SecuredlLine.rollover\n     * @notice helper function to allow borrower to easily swithc collateral to a new Line after repyment\n     *(@dev priviliegad internal function.\n     * @dev MUST only be callable if line is REPAID\n     * @return - if function successfully executed\n     */\n    function _rollover(address newLine) internal virtual returns (bool) {\n        require(escrow.updateLine(newLine));\n        return true;\n    }\n}\n"
      },
      "contracts/modules/credit/SpigotedLine.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 {Denominations} from \"chainlink/Denominations.sol\";\nimport {LineOfCredit} from \"./LineOfCredit.sol\";\nimport {LineLib} from \"../../utils/LineLib.sol\";\nimport {CreditLib} from \"../../utils/CreditLib.sol\";\nimport {SpigotedLineLib} from \"../../utils/SpigotedLineLib.sol\";\nimport {MutualConsent} from \"../../utils/MutualConsent.sol\";\nimport {ISpigot} from \"../../interfaces/ISpigot.sol\";\nimport {ISpigotedLine} from \"../../interfaces/ISpigotedLine.sol\";\nimport {IERC20} from \"openzeppelin/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"openzeppelin/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n  * @title  - Credit Cooperative Spigoted Line of Credit\n  * @notice - Line of Credit contract with additional functionality for integrating with a Spigot and revenue based collateral.\n            - Allows Arbiter to repay debt using collateralized revenue streams onbehalf of Borrower and Lender(s)\n  * @dev    - Inherits LineOfCredit functionality\n */\ncontract SpigotedLine is ISpigotedLine, LineOfCredit {\n    using SafeERC20 for IERC20;\n\n    /// @notice see Spigot\n    ISpigot public immutable spigot;\n\n    /// @notice - maximum revenue we want to be able to take from spigots if Line is in default\n    uint8 constant MAX_SPLIT = 100;\n\n    /// @notice % of revenue tokens to take from Spigot if the Line of Credit is healthy. 0 decimals\n    uint8 public immutable defaultRevenueSplit;\n\n    /// @notice exchange aggregator (mainly 0x router) to trade revenue tokens from a Spigot for credit tokens owed to lenders\n    address payable public immutable swapTarget;\n\n    /**\n     * @notice - excess unsold revenue claimed from Spigot to be sold later or excess credit tokens bought from revenue but not yet used to repay debt\n     *         - needed because the Line of Credit might have the same token being lent/borrower as being bought/sold so need to separate accounting.\n     * @dev    - private variable so other Line modules do not interfer with Spigot functionality\n     */\n    mapping(address => uint256) private unusedTokens;\n\n    /**\n     * @notice - The SpigotedLine is a LineofCredit contract with additional functionality for integrating with a Spigot.\n               - allows Borrower or Lender to repay debt using collateralized revenue streams\n     * @param oracle_ - price oracle to use for getting all token values\n     * @param arbiter_ - neutral party with some special priviliges on behalf of borrower and lender\n     * @param borrower_ - the debitor for all credit positions in this contract\n     * @param spigot_ - Spigot smart contract that is owned by this Line\n     * @param swapTarget_ - 0x protocol exchange address to send calldata for trades to exchange revenue tokens for credit tokens\n     * @param ttl_ - time to live for line of credit contract across all lenders set at deployment in order to set the term/expiry date\n     * @param defaultRevenueSplit_ - The % of Revenue Tokens that the Spigot escrows for debt repayment if the Line is healthy.\n     */\n    constructor(\n        address oracle_,\n        address arbiter_,\n        address borrower_,\n        address spigot_,\n        address payable swapTarget_,\n        uint256 ttl_,\n        uint8 defaultRevenueSplit_\n    ) LineOfCredit(oracle_, arbiter_, borrower_, ttl_) {\n        require(defaultRevenueSplit_ <= MAX_SPLIT);\n\n        spigot = ISpigot(spigot_);\n        defaultRevenueSplit = defaultRevenueSplit_;\n        swapTarget = swapTarget_;\n    }\n\n    /**\n     * see LineOfCredit._init and Securedline.init\n     * @notice requires this Line is owner of the Escrowed collateral else Line will not init\n     */\n    function _init() internal virtual override(LineOfCredit) {\n        if (spigot.owner() != address(this)) revert BadModule(address(spigot));\n    }\n\n    /**\n     * see SecuredLine.declareInsolvent\n     * @notice requires Spigot contract itselgf to be transfered to Arbiter and sold off to a 3rd party before declaring insolvent\n     *(@dev priviliegad internal function.\n     * @return isInsolvent - if Spigot contract is currently insolvent or not\n     */\n    function _canDeclareInsolvent() internal virtual override returns (bool) {\n        return SpigotedLineLib.canDeclareInsolvent(address(spigot), arbiter);\n    }\n\n    /// see ISpigotedLine.claimAndRepay\n    function claimAndRepay(\n        address claimToken,\n        bytes calldata zeroExTradeData\n    ) external whileBorrowing nonReentrant returns (uint256) {\n        bytes32 id = ids[0];\n        Credit memory credit = _accrue(credits[id], id);\n\n        if (msg.sender != arbiter) {\n            revert CallerAccessDenied();\n        }\n\n        uint256 newTokens = _claimAndTrade(claimToken, credit.token, zeroExTradeData);\n\n        uint256 repaid = newTokens + unusedTokens[credit.token];\n        uint256 debt = credit.interestAccrued + credit.principal;\n\n        // cap payment to debt value\n        if (repaid > debt) repaid = debt;\n\n        // update reserves based on usage\n        if (repaid > newTokens) {\n            // if using `unusedTokens` to repay line, reduce reserves\n            uint256 diff = repaid - newTokens;\n            emit ReservesChanged(credit.token, -int256(diff), 1);\n            unusedTokens[credit.token] -= diff;\n        } else {\n            // else high revenue and bought more credit tokens than owed, fill reserves\n            uint256 diff = newTokens - repaid;\n            emit ReservesChanged(credit.token, int256(diff), 1);\n            unusedTokens[credit.token] += diff;\n        }\n\n        credits[id] = _repay(credit, id, repaid, address(0)); // no payer, we already have funds\n\n        emit RevenuePayment(claimToken, repaid);\n\n        return newTokens;\n    }\n\n    /// see ISpigotedLine.useAndRepay\n    function useAndRepay(uint256 amount) external whileBorrowing returns (bool) {\n        bytes32 id = ids[0];\n        Credit memory credit = credits[id];\n\n        if (msg.sender != borrower && msg.sender != credit.lender) {\n            revert CallerAccessDenied();\n        }\n\n        if (amount > credit.principal + credit.interestAccrued) {\n            revert RepayAmountExceedsDebt(credit.principal + credit.interestAccrued);\n        }\n\n        if (amount > unusedTokens[credit.token]) {\n            revert ReservesOverdrawn(credit.token, unusedTokens[credit.token]);\n        }\n\n        // reduce reserves before _repay calls token to prevent reentrancy\n        unusedTokens[credit.token] -= amount;\n        emit ReservesChanged(credit.token, -int256(amount), 0);\n\n        credits[id] = _repay(_accrue(credit, id), id, amount, address(0)); // no payer, we already have funds\n\n        emit RevenuePayment(credit.token, amount);\n\n        return true;\n    }\n\n    /// see ISpigotedLine.claimAndTrade\n    function claimAndTrade(\n        address claimToken,\n        bytes calldata zeroExTradeData\n    ) external whileBorrowing nonReentrant returns (uint256) {\n        if (msg.sender != arbiter) {\n            revert CallerAccessDenied();\n        }\n\n        address targetToken = credits[ids[0]].token;\n        uint256 newTokens = _claimAndTrade(claimToken, targetToken, zeroExTradeData);\n\n        // add bought tokens to unused balance\n        unusedTokens[targetToken] += newTokens;\n        emit ReservesChanged(targetToken, int256(newTokens), 1);\n\n        return newTokens;\n    }\n\n    /**\n     * @notice  - Claims revenue tokens escrowed in Spigot and trades them for credit tokens.\n     *          - MUST trade all available claim tokens to target credit token.\n     *          - Excess credit tokens not used to repay dent are stored in `unused`\n     * @dev     - priviliged internal function\n     * @param claimToken - The revenue token escrowed in the Spigot to sell in trade\n     * @param targetToken - The credit token that needs to be bought in order to pat down debt. Always `credits[ids[0]].token`\n     * @param zeroExTradeData - 0x API data to use in trade to sell `claimToken` for target\n     *\n     * @return - amount of target tokens bought\n     */\n    function _claimAndTrade(\n        address claimToken,\n        address targetToken,\n        bytes calldata zeroExTradeData\n    ) internal returns (uint256) {\n        if (claimToken == targetToken) {\n            // same asset. dont trade\n            return spigot.claimOwnerTokens(claimToken);\n        } else {\n            // trade revenue token for debt obligation\n            (uint256 tokensBought, uint256 totalUnused) = SpigotedLineLib.claimAndTrade(\n                claimToken,\n                targetToken,\n                swapTarget,\n                address(spigot),\n                unusedTokens[claimToken],\n                zeroExTradeData\n            );\n\n            // we dont use revenue after this so can store now\n            /// @dev ReservesChanged event for claim token is emitted in SpigotedLineLib.claimAndTrade\n            unusedTokens[claimToken] = totalUnused;\n\n            // the target tokens purchased\n            return tokensBought;\n        }\n    }\n\n    //  SPIGOT OWNER FUNCTIONS\n\n    /// see ISpigotedLine.updateOwnerSplit\n    function updateOwnerSplit(address revenueContract) external returns (bool) {\n        return\n            SpigotedLineLib.updateSplit(\n                address(spigot),\n                revenueContract,\n                _updateStatus(_healthcheck()),\n                defaultRevenueSplit\n            );\n    }\n\n    /// see ISpigotedLine.addSpigot\n    function addSpigot(address revenueContract, ISpigot.Setting calldata setting) external returns (bool) {\n        if (msg.sender != arbiter) {\n            revert CallerAccessDenied();\n        }\n        return spigot.addSpigot(revenueContract, setting);\n    }\n\n    /// see ISpigotedLine.updateWhitelist\n    function updateWhitelist(bytes4 func, bool allowed) external returns (bool) {\n        if (msg.sender != arbiter) {\n            revert CallerAccessDenied();\n        }\n        return spigot.updateWhitelistedFunction(func, allowed);\n    }\n\n    /// see ISpigotedLine.releaseSpigot\n    function releaseSpigot(address to) external returns (bool) {\n        return SpigotedLineLib.releaseSpigot(address(spigot), _updateStatus(_healthcheck()), borrower, arbiter, to);\n    }\n\n    /// see ISpigotedLine.sweep\n    function sweep(address to, address token, uint256 amount) external nonReentrant returns (uint256) {\n        uint256 swept = SpigotedLineLib.sweep(\n            to,\n            token,\n            amount,\n            unusedTokens[token],\n            _updateStatus(_healthcheck()),\n            borrower,\n            arbiter\n        );\n\n        if (swept != 0) {\n            unusedTokens[token] -= swept;\n            emit ReservesChanged(token, -int256(swept), 1);\n        }\n\n        return swept;\n    }\n\n    /// see ILineOfCredit.tradeable\n    function tradeable(address token) external view returns (uint256) {\n        return unusedTokens[token] + spigot.getOwnerTokens(token);\n    }\n\n    /// see ILineOfCredit.unused\n    function unused(address token) external view returns (uint256) {\n        return unusedTokens[token];\n    }\n\n    // allow claiming/trading in ETH\n    receive() external payable {}\n}\n"
      },
      "contracts/utils/SpigotedLineLib.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 {ISpigot} from \"../interfaces/ISpigot.sol\";\nimport {ISpigotedLine} from \"../interfaces/ISpigotedLine.sol\";\nimport {LineLib} from \"../utils/LineLib.sol\";\nimport {SpigotLib} from \"../utils/SpigotLib.sol\";\nimport {IERC20} from \"openzeppelin/token/ERC20/IERC20.sol\";\n\nimport {Denominations} from \"chainlink/Denominations.sol\";\n\nlibrary SpigotedLineLib {\n    /// @notice - maximum revenue we want to be able to take from spigots if Line is in default\n    uint8 constant MAX_SPLIT = 100;\n\n    error NoSpigot();\n\n    error TradeFailed();\n\n    error BadTradingPair();\n\n    error CallerAccessDenied();\n\n    error ReleaseSpigotFailed();\n\n    error NotInsolvent(address module);\n\n    error ReservesOverdrawn(address token, uint256 amountAvailable);\n\n    event TradeSpigotRevenue(\n        address indexed revenueToken,\n        uint256 revenueTokenAmount,\n        address indexed debtToken,\n        uint256 indexed debtTokensBought\n    );\n\n    event ReservesChanged(\n        address indexed token,\n        int256 indexed diff,\n        uint256 tokenType // 0 for revenue token, 1 for credit token\n    );\n\n    /**\n     * @dev                 - priviliged internal function!\n     * @notice              - Allows revenue tokens in 'escrowed' to be traded for credit tokens that aren't yet used to repay debt.\n                            - The newly exchanged credit tokens are held in 'unusedTokens' ready for a Lender to withdraw using useAndRepay\n                            - This feature allows a Borrower to take advantage of an increase in the value of the revenue token compared\n                            - to the credit token and to in effect use less revenue tokens to be later used to repay the same amount of debt.\n     * @dev                 - MUST trade all available claimTokens (unused + claimed) to targetTokens\n     * @param claimToken    - The revenue token escrowed in the Spigot to sell in trade\n     * @param targetToken   - The credit token that needs to be bought in order to pay down debt. Always `credits[ids[0]].token`\n     * @param swapTarget    - The 0x exchange router address to call for trades\n     * @param spigot        - The Spigot to claim from. Must be owned by adddress(this)\n     * @param unused        - Current amount of unused claimTokens\n     * @param zeroExTradeData - 0x API data to use in trade to sell `claimToken` for target\n     * @return (uint, uint) - amount of targetTokens bought, total unused claimTokens after trade\n     */\n    function claimAndTrade(\n        address claimToken,\n        address targetToken,\n        address payable swapTarget,\n        address spigot,\n        uint256 unused,\n        bytes calldata zeroExTradeData\n    ) external returns (uint256, uint256) {\n        // can't trade into same token. causes double count for unused tokens\n        if (claimToken == targetToken) {\n            revert BadTradingPair();\n        }\n\n        // snapshot token balances now to diff after trade executes\n        uint256 oldClaimTokens = LineLib.getBalance(claimToken);\n\n        uint256 oldTargetTokens = LineLib.getBalance(targetToken);\n\n        // @dev claim has to be called after we get balance\n        // reverts if there are no tokens to claim\n        uint256 claimed = ISpigot(spigot).claimOwnerTokens(claimToken);\n\n        trade(claimed + unused, claimToken, swapTarget, zeroExTradeData);\n\n        // underflow revert ensures we have more tokens than we started with\n        uint256 tokensBought = LineLib.getBalance(targetToken) - oldTargetTokens;\n\n        if (tokensBought == 0) {\n            revert TradeFailed();\n        } // ensure tokens bought\n\n        uint256 newClaimTokens = LineLib.getBalance(claimToken);\n\n        // ideally we could use oracle here to calculate # of tokens to receive\n        // but sellToken might not have oracle. buyToken must have oracle\n\n        emit TradeSpigotRevenue(claimToken, claimed, targetToken, tokensBought);\n\n        // used reserve revenue to repay debt\n        if (oldClaimTokens > newClaimTokens) {\n            unchecked {\n                // we check all values before math so can use unchecked\n                uint256 diff = oldClaimTokens - newClaimTokens;\n\n                emit ReservesChanged(claimToken, -int256(diff), 0);\n\n                // used more tokens than we had in revenue reserves.\n                // prevent borrower from pulling idle lender funds to repay other lenders\n                if (diff > unused) revert ReservesOverdrawn(claimToken, unused);\n                // reduce reserves by consumed amount\n                else return (tokensBought, unused - diff);\n            }\n        } else {\n            unchecked {\n                // `unused` unlikely to overflow\n                // excess revenue in trade. store in reserves\n                uint256 diff = newClaimTokens - oldClaimTokens;\n\n                emit ReservesChanged(claimToken, int256(diff), 0);\n\n                return (tokensBought, unused + diff);\n            }\n        }\n    }\n\n    /**\n     * @dev                     - priviliged internal function!\n     * @notice                  - dumb func that executes arbitry code against a target contract\n     * @param amount            - amount of revenue tokens to sell\n     * @param sellToken         - revenue token being sold\n     * @param swapTarget        - exchange aggregator to trade against\n     * @param zeroExTradeData   - Trade data to execute against exchange for target token/amount\n     * @return bool             - if trade was successful\n     */\n    function trade(\n        uint256 amount,\n        address sellToken,\n        address payable swapTarget,\n        bytes calldata zeroExTradeData\n    ) public returns (bool) {\n        if (sellToken == Denominations.ETH) {\n            // if claiming/trading eth send as msg.value to dex\n            (bool success, ) = swapTarget.call{value: amount}(zeroExTradeData); // TODO: test with 0x api data on mainnet fork\n            if (!success) {\n                revert TradeFailed();\n            }\n        } else {\n            IERC20(sellToken).approve(swapTarget, amount);\n            (bool success, ) = swapTarget.call(zeroExTradeData);\n            if (!success) {\n                revert TradeFailed();\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @notice          - cleanup function when a Line of Credit facility has expired. Called in SecuredLine.rollover\n     *                  - Reuse a Spigot across a single borrower's Line contracts\n     * @param spigot    - The spigot address owned by this SpigotedLine\n     * @param newLine   - The new line to transfer Spigot ownership to\n     * @return bool     - if Spigot ownership was transferred or not\n     */\n    function rollover(address spigot, address newLine) external returns (bool) {\n        require(ISpigot(spigot).updateOwner(newLine));\n        return true;\n    }\n\n    function canDeclareInsolvent(address spigot, address arbiter) external view returns (bool) {\n        // Must have called releaseSpigot() and sold off protocol / revenue streams already\n        address owner_ = ISpigot(spigot).owner();\n        if (address(this) == owner_ || arbiter == owner_) {\n            revert NotInsolvent(spigot);\n        }\n\n        return true;\n    }\n\n    /**\n     * @notice                  - Changes the revenue split between a Borrower's treasury and the LineOfCredit based on line health, runs with updateOwnerSplit()\n     * @dev                     - callable by anyone\n     * @param revenueContract   - spigoted contract to update\n     * @return sucesss          - whether or not split was updated\n     */\n    function updateSplit(\n        address spigot,\n        address revenueContract,\n        LineLib.STATUS status,\n        uint8 defaultSplit\n    ) external returns (bool) {\n        (uint8 split, , bytes4 transferFunc) = ISpigot(spigot).getSetting(revenueContract);\n\n        if (transferFunc == bytes4(0)) {\n            revert NoSpigot();\n        }\n\n        if (status == LineLib.STATUS.ACTIVE && split != defaultSplit) {\n            // if Line of Credit is healthy then set the split to the prior agreed default split of revenue tokens\n            return ISpigot(spigot).updateOwnerSplit(revenueContract, defaultSplit);\n        } else if (status == LineLib.STATUS.LIQUIDATABLE && split != MAX_SPLIT) {\n            // if the Line of Credit is in distress then take all revenue to repay debt\n            return ISpigot(spigot).updateOwnerSplit(revenueContract, MAX_SPLIT);\n        }\n\n        return false;\n    }\n\n    /**\n   * @notice - Transfers ownership of the entire Spigot and its revenuw streams from its then Owner to either\n             - the Borrower (if a Line of Credit has been been fully repaid) or\n             - to the Arbiter (if the Line of Credit is liquidatable).\n   * @dev    - callable by `borrower` or `arbiter`\n   * @return - whether or not Spigot was released\n  */\n    function releaseSpigot(\n        address spigot,\n        LineLib.STATUS status,\n        address borrower,\n        address arbiter,\n        address to\n    ) external returns (bool) {\n        if (status == LineLib.STATUS.REPAID && msg.sender == borrower) {\n            if (!ISpigot(spigot).updateOwner(to)) {\n                revert ReleaseSpigotFailed();\n            }\n            return true;\n        }\n\n        if (status == LineLib.STATUS.LIQUIDATABLE && msg.sender == arbiter) {\n            if (!ISpigot(spigot).updateOwner(to)) {\n                revert ReleaseSpigotFailed();\n            }\n            return true;\n        }\n\n        revert CallerAccessDenied();\n    }\n\n    /**\n      * @notice -  Sends any remaining tokens (revenue or credit tokens) in the Spigot to the Borrower after the loan has been repaid.\n                  -  In case of a Borrower default (loan status = liquidatable), this is a fallback mechanism to withdraw all the tokens and send them to the Arbiter\n                  -  Does not transfer anything if line is healthy\n      * @dev    - callable by `borrower` or `arbiter`\n      * @return - whether or not spigot was released\n    */\n    function sweep(\n        address to,\n        address token,\n        uint256 amount,\n        uint256 available,\n        LineLib.STATUS status,\n        address borrower,\n        address arbiter\n    ) external returns (uint256) {\n        if (available == 0) {\n            return 0;\n        }\n        if (amount == 0) {\n            // use all tokens if no amount specified specified\n            amount = available;\n        } else {\n            if (amount > available) {\n                revert ReservesOverdrawn(token, available);\n            }\n        }\n\n        if (status == LineLib.STATUS.REPAID && msg.sender == borrower) {\n            LineLib.sendOutTokenOrETH(token, to, amount);\n            return amount;\n        }\n\n        if ((status == LineLib.STATUS.LIQUIDATABLE || status == LineLib.STATUS.INSOLVENT) && msg.sender == arbiter) {\n            LineLib.sendOutTokenOrETH(token, to, amount);\n            return amount;\n        }\n\n        revert CallerAccessDenied();\n    }\n}\n"
      },
      "contracts/modules/credit/LineOfCredit.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 {Denominations} from \"chainlink/Denominations.sol\";\nimport {IERC20} from \"openzeppelin/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"openzeppelin/token/ERC20/utils/SafeERC20.sol\";\nimport {ReentrancyGuard} from \"openzeppelin/utils/ReentrancyGuard.sol\";\n\nimport {LineLib} from \"../../utils/LineLib.sol\";\nimport {CreditLib} from \"../../utils/CreditLib.sol\";\nimport {CreditListLib} from \"../../utils/CreditListLib.sol\";\nimport {MutualConsent} from \"../../utils/MutualConsent.sol\";\nimport {InterestRateCredit} from \"../interest-rate/InterestRateCredit.sol\";\n\nimport {IOracle} from \"../../interfaces/IOracle.sol\";\nimport {ILineOfCredit} from \"../../interfaces/ILineOfCredit.sol\";\n\n/**\n * @title  - Credit Cooperative Unsecured Line of Credit\n * @notice - Core credit facility logic for proposing, depositing, borrowing, and repaying debt.\n *         - Contains core financial covnenants around term length (`deadline`), collateral ratios, liquidations, etc.\n * @dev    - contains internal functions overwritten by SecuredLine, SpigotedLine, and EscrowedLine\n */\ncontract LineOfCredit is ILineOfCredit, MutualConsent, ReentrancyGuard {\n    using SafeERC20 for IERC20;\n\n    using CreditListLib for bytes32[];\n\n    /// @notice - the timestamp that all creditors must be repaid by\n    uint256 public immutable deadline;\n\n    /// @notice - the account that can drawdown and manage debt positions\n    address public immutable borrower;\n\n    /// @notice - neutral 3rd party that mediates btw borrower and all lenders\n    address public immutable arbiter;\n\n    /// @notice - price feed to use for valuing credit tokens\n    IOracle public immutable oracle;\n\n    /// @notice - contract responsible for calculating interest owed on debt positions\n    InterestRateCredit public immutable interestRate;\n\n    /// @notice - current amount of active positions (aka non-null ids) in `ids` list\n    uint256 private count;\n\n    /// @notice - positions ids of all open credit lines.\n    /// @dev    - may contain null elements\n    bytes32[] public ids;\n\n    /// @notice id -> position data\n    mapping(bytes32 => Credit) public credits;\n\n    /// @notice - current health status of line\n    LineLib.STATUS public status;\n\n    /**\n     * @notice            - How to deploy a Line of Credit\n     * @dev               - A Borrower and a first Lender agree on terms. Then the Borrower deploys the contract using the constructor below.\n     *                      Later, both Lender and Borrower must call _mutualConsent() during addCredit() to actually enable funds to be deposited.\n     * @param oracle_     - The price oracle to use for getting all token values.\n     * @param arbiter_    - A neutral party with some special priviliges on behalf of Borrower and Lender.\n     * @param borrower_   - The debitor for all credit lines in this contract.\n     * @param ttl_        - The time to live for all credit lines for the Line of Credit facility (sets the maturity/term of the Line of Credit)\n     */\n    constructor(address oracle_, address arbiter_, address borrower_, uint256 ttl_) {\n        oracle = IOracle(oracle_);\n        arbiter = arbiter_;\n        borrower = borrower_;\n        deadline = block.timestamp + ttl_; //the deadline is the term/maturity/expiry date of the Line of Credit facility\n        interestRate = new InterestRateCredit();\n\n        emit DeployLine(oracle_, arbiter_, borrower_);\n    }\n\n    function init() external virtual {\n        if (status != LineLib.STATUS.UNINITIALIZED) {\n            revert AlreadyInitialized();\n        }\n        _init();\n        _updateStatus(LineLib.STATUS.ACTIVE);\n    }\n\n    function _init() internal virtual {\n        // If no collateral or Spigot then Line of Credit is immediately active\n        return;\n    }\n\n    ///////////////\n    // MODIFIERS //\n    ///////////////\n\n    modifier whileActive() {\n        if (status != LineLib.STATUS.ACTIVE) {\n            revert NotActive();\n        }\n        _;\n    }\n\n    modifier whileBorrowing() {\n        if (count == 0 || credits[ids[0]].principal == 0) {\n            revert NotBorrowing();\n        }\n        _;\n    }\n\n    modifier onlyBorrower() {\n        if (msg.sender != borrower) {\n            revert CallerAccessDenied();\n        }\n        _;\n    }\n\n    /**\n     * @notice - mutualConsent() but hardcodes borrower address and uses the position id to\n                 get Lender address instead of passing it in directly\n     * @param id - position to pull lender address from for mutual consent agreement\n    */\n    modifier mutualConsentById(bytes32 id) {\n        if (_mutualConsent(borrower, credits[id].lender)) {\n            // Run whatever code is needed for the 2/2 consent\n            _;\n        }\n    }\n\n    /**\n     * @notice - evaluates all covenants encoded in _healthcheck from different Line variants\n     * @dev - updates `status` variable in storage if current status is diferent from existing status\n     * @return - current health status of Line\n     */\n    function healthcheck() external returns (LineLib.STATUS) {\n        // can only check if the line has been initialized\n        require(uint256(status) >= uint256(LineLib.STATUS.ACTIVE));\n        return _updateStatus(_healthcheck());\n    }\n\n    function _healthcheck() internal virtual returns (LineLib.STATUS) {\n        // if line is in a final end state then do not run _healthcheck()\n        LineLib.STATUS s = status;\n        if (\n            s == LineLib.STATUS.REPAID || // end state - good\n            s == LineLib.STATUS.INSOLVENT // end state - bad\n        ) {\n            return s;\n        }\n\n        // Liquidate if all credit lines aren't closed by deadline\n        if (block.timestamp >= deadline && count != 0) {\n            emit Default(ids[0]); // can query all defaulted positions offchain once event picked up\n            return LineLib.STATUS.LIQUIDATABLE;\n        }\n\n        // if nothing wrong, return to healthy ACTIVE state\n        return LineLib.STATUS.ACTIVE;\n    }\n\n    /// see ILineOfCredit.declareInsolvent\n    function declareInsolvent() external {\n        if (arbiter != msg.sender) {\n            revert CallerAccessDenied();\n        }\n        if (LineLib.STATUS.LIQUIDATABLE != _updateStatus(_healthcheck())) {\n            revert NotLiquidatable();\n        }\n\n        if (_canDeclareInsolvent()) {\n            _updateStatus(LineLib.STATUS.INSOLVENT);\n        }\n    }\n\n    function _canDeclareInsolvent() internal virtual returns (bool) {\n        // logic updated in Spigoted and Escrowed lines\n        return true;\n    }\n\n    /// see ILineOfCredit.updateOutstandingDebt\n    function updateOutstandingDebt() external override returns (uint256, uint256) {\n        return _updateOutstandingDebt();\n    }\n\n    function _updateOutstandingDebt() internal returns (uint256 principal, uint256 interest) {\n        // use full length not count because positions might not be packed in order\n        uint256 len = ids.length;\n        if (len == 0) return (0, 0);\n\n        bytes32 id;\n        for (uint256 i; i < len; ++i) {\n            id = ids[i];\n\n            // null element in array from closing a position. skip for gas savings\n            if (id == bytes32(0)) {\n                continue;\n            }\n\n            (Credit memory c, uint256 _p, uint256 _i) = CreditLib.getOutstandingDebt(\n                credits[id],\n                id,\n                address(oracle),\n                address(interestRate)\n            );\n\n            // update total outstanding debt\n            principal += _p;\n            interest += _i;\n            // save changes to storage\n            credits[id] = c;\n        }\n    }\n\n    /// see ILineOfCredit.accrueInterest\n    function accrueInterest() external override {\n        uint256 len = ids.length;\n        bytes32 id;\n        for (uint256 i; i < len; ++i) {\n            id = ids[i];\n            Credit memory credit = credits[id];\n            credits[id] = _accrue(credit, id);\n        }\n    }\n\n    /// see ILineOfCredit.addCredit\n    function addCredit(\n        uint128 drate,\n        uint128 frate,\n        uint256 amount,\n        address token,\n        address lender\n    ) external payable override nonReentrant whileActive mutualConsent(lender, borrower) returns (bytes32) {\n        bytes32 id = _createCredit(lender, token, amount);\n\n        _setRates(id, drate, frate);\n\n        LineLib.receiveTokenOrETH(token, lender, amount);\n\n        return id;\n    }\n\n    /// see ILineOfCredit.setRates\n    function setRates(bytes32 id, uint128 drate, uint128 frate) external override mutualConsentById(id) {\n        credits[id] = _accrue(credits[id], id);\n        _setRates(id, drate, frate);\n    }\n\n    /// see ILineOfCredit.setRates\n    function _setRates(bytes32 id, uint128 drate, uint128 frate) internal {\n        interestRate.setRate(id, drate, frate);\n        emit SetRates(id, drate, frate);\n    }\n\n    /// see ILineOfCredit.increaseCredit\n    function increaseCredit(\n        bytes32 id,\n        uint256 amount\n    ) external payable override nonReentrant whileActive mutualConsentById(id) {\n        Credit memory credit = _accrue(credits[id], id);\n\n        credit.deposit += amount;\n\n        credits[id] = credit;\n\n        LineLib.receiveTokenOrETH(credit.token, credit.lender, amount);\n\n        emit IncreaseCredit(id, amount);\n    }\n\n    ///////////////\n    // REPAYMENT //\n    ///////////////\n\n    /// see ILineOfCredit.depositAndClose\n    function depositAndClose() external payable override nonReentrant whileBorrowing onlyBorrower {\n        bytes32 id = ids[0];\n        Credit memory credit = _accrue(credits[id], id);\n\n        // Borrower deposits the outstanding balance not already repaid\n        uint256 totalOwed = credit.principal + credit.interestAccrued;\n\n        // Borrower clears the debt then closes the credit line\n        credits[id] = _close(_repay(credit, id, totalOwed, borrower), id);\n    }\n\n    /// see ILineOfCredit.close\n    function close(bytes32 id) external payable override nonReentrant onlyBorrower {\n        Credit memory credit = _accrue(credits[id], id);\n\n        uint256 facilityFee = credit.interestAccrued;\n\n        // clear facility fees and close position\n        credits[id] = _close(_repay(credit, id, facilityFee, borrower), id);\n    }\n\n    /// see ILineOfCredit.depositAndRepay\n    function depositAndRepay(uint256 amount) external payable override nonReentrant whileBorrowing {\n        bytes32 id = ids[0];\n        Credit memory credit = _accrue(credits[id], id);\n\n        if (amount > credit.principal + credit.interestAccrued) {\n            revert RepayAmountExceedsDebt(credit.principal + credit.interestAccrued);\n        }\n\n        credits[id] = _repay(credit, id, amount, msg.sender);\n    }\n\n    ////////////////////\n    // FUND TRANSFERS //\n    ////////////////////\n\n    /// see ILineOfCredit.borrow\n    function borrow(bytes32 id, uint256 amount) external override nonReentrant whileActive onlyBorrower {\n        Credit memory credit = _accrue(credits[id], id);\n\n        if (!credit.isOpen) {\n            revert PositionIsClosed();\n        }\n\n        if (amount > credit.deposit - credit.principal) {\n            revert NoLiquidity();\n        }\n\n        credit.principal += amount;\n\n        // save new debt before healthcheck and token transfer\n        credits[id] = credit;\n\n        // ensure that borrowing doesnt cause Line to be LIQUIDATABLE\n        if (_updateStatus(_healthcheck()) != LineLib.STATUS.ACTIVE) {\n            revert BorrowFailed();\n        }\n\n        LineLib.sendOutTokenOrETH(credit.token, borrower, amount);\n\n        emit Borrow(id, amount);\n\n        _sortIntoQ(id);\n    }\n\n    /// see ILineOfCredit.withdraw\n    function withdraw(bytes32 id, uint256 amount) external override nonReentrant {\n        // accrues interest and transfer funds to Lender addres\n        credits[id] = CreditLib.withdraw(_accrue(credits[id], id), id, msg.sender, amount);\n    }\n\n    /**\n     * @notice  - Steps the Queue be replacing the first element with the next valid credit line's ID\n     * @dev     - Only works if the first element in the queue is null\n     */\n    function stepQ() external {\n        ids.stepQ();\n    }\n\n    //////////////////////\n    //  Internal  funcs //\n    //////////////////////\n\n    /**\n     * @notice - updates `status` variable in storage if current status is diferent from existing status.\n     * @dev - privileged internal function. MUST check params and logic flow before calling\n     * @dev - does not save new status if it is the same as current status\n     * @return status - the current status of the line after updating\n     */\n    function _updateStatus(LineLib.STATUS status_) internal returns (LineLib.STATUS) {\n        if (status == status_) return status_;\n        emit UpdateStatus(uint256(status_));\n        return (status = status_);\n    }\n\n    /**\n     * @notice - Generates position id and stores lender's position\n     * @dev - positions have unique composite-index on [lineAddress, lenderAddress, tokenAddress]\n     * @dev - privileged internal function. MUST check params and logic flow before calling\n     * @param lender - address that will own and manage position\n     * @param token - ERC20 token that is being lent and borrower\n     * @param amount - amount of tokens lender will initially deposit\n     */\n    function _createCredit(address lender, address token, uint256 amount) internal returns (bytes32 id) {\n        id = CreditLib.computeId(address(this), lender, token);\n\n        // MUST not double add the credit line. once lender is set it cant be deleted even if position is closed.\n        if (credits[id].lender != address(0)) {\n            revert PositionExists();\n        }\n\n        credits[id] = CreditLib.create(id, amount, lender, token, address(oracle));\n\n        ids.push(id); // add lender to end of repayment queue\n\n        unchecked {\n            ++count;\n        }\n\n        return id;\n    }\n\n    /**\n    * @dev - Reduces `principal` and/or `interestAccrued` on a credit line.\n                Expects checks for conditions of repaying and param sanitizing before calling\n                e.g. early repayment of principal, tokens have actually been paid by borrower, etc.\n    * @dev - privileged internal function. MUST check params and logic flow before calling\n    * @dev syntatic sugar\n    * @param id - position id with all data pertaining to line\n    * @param amount - amount of Credit Token being repaid on credit line\n    * @return credit - position struct in memory with updated values\n    */\n    function _repay(Credit memory credit, bytes32 id, uint256 amount, address payer) internal returns (Credit memory) {\n        return CreditLib.repay(credit, id, amount, payer);\n    }\n\n    /**\n     * @notice - accrues token demoninated interest on a lender's position.\n     * @dev MUST call any time a position balance or interest rate changes\n     * @dev syntatic sugar\n     * @param credit - the lender position that is accruing interest\n     * @param id - the position id for credit position\n     */\n    function _accrue(Credit memory credit, bytes32 id) internal returns (Credit memory) {\n        return CreditLib.accrue(credit, id, address(interestRate));\n    }\n\n    /**\n     * @notice - checks that a credit line is fully repaid and removes it\n     * @dev deletes credit storage. Store any data u might need later in call before _close()\n     * @dev - privileged internal function. MUST check params and logic flow before calling\n     * @dev - when the line being closed is at the 0-index in the ids array, the null index is replaced using `.stepQ`\n     * @return credit - position struct in memory with updated values\n     */\n    function _close(Credit memory credit, bytes32 id) internal virtual returns (Credit memory) {\n        // update position data in state\n        if (!credit.isOpen) {\n            revert PositionIsClosed();\n        }\n        if (credit.principal != 0) {\n            revert CloseFailedWithPrincipal();\n        }\n\n        credit.isOpen = false;\n\n        // nullify the element for `id`\n        ids.removePosition(id);\n\n        // if positions was 1st in Q, cycle to next valid position\n        if (ids[0] == bytes32(0)) ids.stepQ();\n\n        unchecked {\n            --count;\n        }\n\n        // If all credit lines are closed the the overall Line of Credit facility is declared 'repaid'.\n        if (count == 0) {\n            _updateStatus(LineLib.STATUS.REPAID);\n        }\n\n        emit CloseCreditPosition(id);\n\n        return credit;\n    }\n\n    /**\n     * @notice - Insert `p` into the next availble FIFO position in the repayment queue\n               - once earliest slot is found, swap places with `p` and position in slot.\n     * @dev - privileged internal function. MUST check params and logic flow before calling\n     * @param p - position id that we are trying to find appropriate place for\n     */\n    function _sortIntoQ(bytes32 p) internal {\n        uint256 lastSpot = ids.length - 1;\n        uint256 nextQSpot = lastSpot;\n        bytes32 id;\n        for (uint256 i; i <= lastSpot; ++i) {\n            id = ids[i];\n            if (p != id) {\n                if (\n                    id == bytes32(0) || // deleted element. In the middle of the q because it was closed.\n                    nextQSpot != lastSpot || // position already found. skip to find `p` asap\n                    credits[id].principal != 0 //`id` should be placed before `p`\n                ) continue;\n                nextQSpot = i; // index of first undrawn line found\n            } else {\n                // nothing to update\n                if (nextQSpot == lastSpot) return; // nothing to update\n                // get id value being swapped with `p`\n                bytes32 oldPositionId = ids[nextQSpot];\n                // swap positions\n                ids[i] = oldPositionId; // id put into old `p` position\n                ids[nextQSpot] = p; // p put at target index\n\n                emit SortedIntoQ(p, nextQSpot, i, oldPositionId);\n            }\n        }\n    }\n\n    /* GETTERS */\n\n    /// see ILineOfCredit.interestAccrued\n    function interestAccrued(bytes32 id) external view returns (uint256) {\n        return CreditLib.interestAccrued(credits[id], id, address(interestRate));\n    }\n\n    /// see ILineOfCredit.counts\n    function counts() external view returns (uint256, uint256) {\n        return (count, ids.length);\n    }\n\n    /// see ILineOfCredit.available\n    function available(bytes32 id) external view returns (uint256, uint256) {\n        return (credits[id].deposit - credits[id].principal, credits[id].interestRepaid);\n    }\n\n    function nextInQ() external view returns (bytes32, address, address, uint256, uint256, uint256, uint128, uint128) {\n        bytes32 next = ids[0];\n        Credit memory credit = credits[next];\n        // Add to docs that this view revertts if no queue\n        (uint128 dRate, uint128 fRate) = CreditLib.getNextRateInQ(credit.principal, next, address(interestRate));\n        return (\n            next,\n            credit.lender,\n            credit.token,\n            credit.principal,\n            credit.deposit,\n            CreditLib.interestAccrued(credit, next, address(interestRate)),\n            dRate,\n            fRate\n        );\n    }\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/ISecuredLine.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 {IEscrowedLine} from \"./IEscrowedLine.sol\";\nimport {ISpigotedLine} from \"./ISpigotedLine.sol\";\n\ninterface ISecuredLine is IEscrowedLine, ISpigotedLine {\n    // Rollover\n    error DebtOwed();\n    error BadNewLine();\n    error BadRollover();\n\n    // Borrower functions\n\n    /**\n     * @notice - helper function to allow Borrower to easily transfer settings and collateral from this line to a new line\n     *         - usefull after ttl has expired and want to renew Line with minimal effort\n     * @dev    - transfers Spigot and Escrow ownership to newLine. Arbiter functions on this Line will no longer work\n     * @param newLine - the new, uninitialized Line deployed by borrower\n     */\n    function rollover(address newLine) external;\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"
      },
      "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"
      },
      "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"
      },
      "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"
      },
      "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/interfaces/IEscrowedLine.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 {IEscrow} from \"./IEscrow.sol\";\n\ninterface IEscrowedLine {\n    event Liquidate(bytes32 indexed id, uint256 indexed amount, address indexed token, address escrow);\n\n    /**\n     * @notice - Forcefully take collateral from Escrow and repay debt for lender\n     *          - current implementation just sends \"liquidated\" tokens to Arbiter to sell off how the deem fit and then manually repay with DepositAndRepay\n     * @dev - only callable by Arbiter\n     * @dev - Line status MUST be LIQUIDATABLE\n     * @dev - callable by `arbiter`\n     * @param amount - amount of `targetToken` expected to be sold off in  _liquidate\n     * @param targetToken - token in escrow that will be sold of to repay position\n     */\n    function liquidate(uint256 amount, address targetToken) external returns (uint256);\n\n    /// @notice the escrow contract backing this Line\n    function escrow() external returns (IEscrow);\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/MutualConsent.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\n// Copyright: https://github.com/credit-cooperative/Line-Of-Credit/blob/master/COPYRIGHT.md\n\n// forked from https://github.com/IndexCoop/index-coop-smart-contracts/blob/master/contracts/lib/MutualConsent.sol\n\n pragma solidity ^0.8.16;\n\n/**\n * @title MutualConsent\n * @author Set Protocol\n *\n * The MutualConsent contract contains a modifier for handling mutual consents between two parties\n */\nabstract contract MutualConsent {\n    /* ============ State Variables ============ */\n\n    // equivalent to longest msg.data bytes, ie addCredit\n    uint256 constant MAX_DATA_LENGTH_BYTES = 164;\n\n    // equivalent to any fn with no args, ie just a fn selector\n    uint256 constant MIN_DATA_LENGTH_BYTES = 4;\n\n    // Mapping of upgradable units and if consent has been initialized by other party\n    mapping(bytes32 => address) public mutualConsentProposals;\n\n    error Unauthorized();\n    error InvalidConsent();\n    error NotUserConsent();\n    error NonZeroEthValue();\n\n    // causes revert when the msg.data passed in has more data (ie arguments) than the largest known fn signature\n    error UnsupportedMutualConsentFunction();\n\n    /* ============ Events ============ */\n\n    event MutualConsentRegistered(bytes32 proposalId, address taker);\n    event MutualConsentRevoked(bytes32 proposalId);\n    event MutualConsentAccepted(bytes32 proposalId);\n\n    /* ============ Modifiers ============ */\n\n    /**\n     * @notice - allows a function to be called if only two specific stakeholders signoff on the tx data\n     *         - signers can be anyone. only two signers per contract or dynamic signers per tx.\n     */\n    modifier mutualConsent(address _signerOne, address _signerTwo) {\n        if (_mutualConsent(_signerOne, _signerTwo)) {\n            // Run whatever code needed 2/2 consent\n            _;\n        }\n    }\n\n    /**\n     *  @notice - allows a caller to revoke a previously created consent\n     *  @dev    - MAX_DATA_LENGTH_BYTES is set at 164 bytes, which is the length of the msg.data\n     *          - for the addCredit function. Anything over that is not valid and might be used in\n     *          - an attempt to create a hash collision\n     *  @param  _reconstrucedMsgData The reconstructed msg.data for the function call for which the\n     *          original consent was created - comprised of the fn selector (bytes4) and abi.encoded\n     *          function arguments.\n     *\n     */\n    function revokeConsent(bytes calldata _reconstrucedMsgData) external {\n        if (\n            _reconstrucedMsgData.length > MAX_DATA_LENGTH_BYTES || _reconstrucedMsgData.length < MIN_DATA_LENGTH_BYTES\n        ) {\n            revert UnsupportedMutualConsentFunction();\n        }\n\n        bytes32 proposalIdToDelete = keccak256(abi.encodePacked(_reconstrucedMsgData, msg.sender));\n\n        address consentor = mutualConsentProposals[proposalIdToDelete];\n\n        if (consentor == address(0)) {\n            revert InvalidConsent();\n        }\n        if (consentor != msg.sender) {\n            revert NotUserConsent();\n        } // note: cannot test, as no way to know what data (+msg.sender) would cause hash collision\n\n        delete mutualConsentProposals[proposalIdToDelete];\n\n        emit MutualConsentRevoked(proposalIdToDelete);\n    }\n\n    /* ============ Internal Functions ============ */\n\n    function _mutualConsent(address _signerOne, address _signerTwo) internal returns (bool) {\n        if (msg.sender != _signerOne && msg.sender != _signerTwo) {\n            revert Unauthorized();\n        }\n\n        address nonCaller = _getNonCaller(_signerOne, _signerTwo);\n\n        // The consent hash is defined by the hash of the transaction call data and sender of msg,\n        // which uniquely identifies the function, arguments, and sender.\n        bytes32 expectedProposalId = keccak256(abi.encodePacked(msg.data, nonCaller));\n\n        if (mutualConsentProposals[expectedProposalId] == address(0)) {\n            bytes32 newProposalId = keccak256(abi.encodePacked(msg.data, msg.sender));\n\n            mutualConsentProposals[newProposalId] = msg.sender; // save caller's consent for nonCaller to accept\n\n            emit MutualConsentRegistered(newProposalId, nonCaller);\n\n            return false;\n        }\n\n        delete mutualConsentProposals[expectedProposalId];\n\n        emit MutualConsentAccepted(expectedProposalId);\n\n        return true;\n    }\n\n    function _getNonCaller(address _signerOne, address _signerTwo) internal view returns (address) {\n        return msg.sender == _signerOne ? _signerTwo : _signerOne;\n    }\n}\n"
      },
      "contracts/interfaces/ISpigot.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 ISpigot {\n    struct Setting {\n        uint8 ownerSplit; // x/100 % to Owner, rest to Operator\n        bytes4 claimFunction; // function signature on contract to call and claim revenue\n        bytes4 transferOwnerFunction; // function signature on contract to call and transfer ownership\n    }\n\n    // Spigot Events\n    event AddSpigot(address indexed revenueContract, uint256 ownerSplit, bytes4 claimFnSig, bytes4 trsfrFnSig);\n\n    event RemoveSpigot(address indexed revenueContract, address token);\n\n    event UpdateWhitelistFunction(bytes4 indexed func, bool indexed allowed);\n\n    event UpdateOwnerSplit(address indexed revenueContract, uint8 indexed split);\n\n    event ClaimRevenue(address indexed token, uint256 indexed amount, uint256 escrowed, address revenueContract);\n\n    event ClaimOwnerTokens(address indexed token, uint256 indexed amount, address owner);\n\n    event ClaimOperatorTokens(address indexed token, uint256 indexed amount, address operator);\n\n    // Stakeholder Events\n\n    event UpdateOwner(address indexed newOwner);\n\n    event UpdateOperator(address indexed newOperator);\n\n    // Errors\n    error BadFunction();\n\n    error OperatorFnNotWhitelisted();\n\n    error OperatorFnNotValid();\n\n    error OperatorFnCallFailed();\n\n    error ClaimFailed();\n\n    error NoRevenue();\n\n    error UnclaimedRevenue();\n\n    error CallerAccessDenied();\n\n    error BadSetting();\n\n    error InvalidRevenueContract();\n\n    // ops funcs\n\n    function claimRevenue(\n        address revenueContract,\n        address token,\n        bytes calldata data\n    ) external returns (uint256 claimed);\n\n    function operate(address revenueContract, bytes calldata data) external returns (bool);\n\n    // owner funcs\n\n    function claimOwnerTokens(address token) external returns (uint256 claimed);\n\n    function claimOperatorTokens(address token) external returns (uint256 claimed);\n\n    function addSpigot(address revenueContract, Setting memory setting) external returns (bool);\n\n    function removeSpigot(address revenueContract) external returns (bool);\n\n    // stakeholder funcs\n\n    function updateOwnerSplit(address revenueContract, uint8 ownerSplit) external returns (bool);\n\n    function updateOwner(address newOwner) external returns (bool);\n\n    function updateOperator(address newOperator) external returns (bool);\n\n    function updateWhitelistedFunction(bytes4 func, bool allowed) external returns (bool);\n\n    // Getters\n    function owner() external view returns (address);\n\n    function operator() external view returns (address);\n\n    function isWhitelisted(bytes4 func) external view returns (bool);\n\n    function getOwnerTokens(address token) external view returns (uint256);\n\n    function getOperatorTokens(address token) external view returns (uint256);\n\n    function getSetting(\n        address revenueContract\n    ) external view returns (uint8 split, bytes4 claimFunc, bytes4 transferFunc);\n}\n"
      },
      "contracts/interfaces/ISpigotedLine.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 {ISpigot} from \"./ISpigot.sol\";\n\ninterface ISpigotedLine {\n    /**\n     * @notice - Log how many revenue tokens are used to repay debt after claimAndRepay\n     *         - dont need to track value like other events because _repay already emits that\n     *         - Mainly used to log debt that is paid via Spigot directly vs other sources. Without this event it's a lot harder to parse that offchain.\n     */\n    event RevenuePayment(address indexed token, uint256 indexed amount);\n\n    error ReservesOverdrawn(address token, uint256 amountAvailable);\n\n    /**\n     * @notice - Log how many revenue tokens were traded for credit tokens.\n     *         - Differs from RevenuePayment because we trade revenue at different times from repaying with revenue\n     * @dev    - Can you use to figure out price of revenue tokens offchain since we only have an oracle for credit tokens\n     * @dev    - Revenue tokens may be from reserves or from Spigot revenue.\n     */\n    event TradeSpigotRevenue(\n        address indexed revenueToken,\n        uint256 revenueTokenAmount,\n        address indexed debtToken,\n        uint256 indexed debtTokensBought\n    );\n\n    event ReservesChanged(\n        address indexed token,\n        int256 indexed diff,\n        uint256 tokenType // 0 for revenue token, 1 for credit token\n    );\n\n    // Borrower functions\n\n    /**\n     * @notice - Directly repays a Lender using unused tokens already held by Line with no trading\n     * @dev    - callable by `borrower` or first lender in repayment queue\n     * @param amount       - amount of unused tokens to use to repay Lender\n     * @return             - if function executed successfully\n     */\n    function useAndRepay(uint256 amount) external returns (bool);\n\n    /**\n     * @notice  - Claims revenue tokens from the Spigot, trades them for credit tokens via a Dex aggregator (Ox protocol) and uses the bought credit tokens to repay debt.\n     *          - see SpigotedLine._claimAndTrade and SpigotedLineLib.claimAndTrade for more details on Spigot and trading logic\n     *          - see LineOfCredit._repay() for more details on repayment logic\n     * @dev     - does not trade asset if claimToken = credit.token\n     * @dev     - callable by `arbiter`\n     * @param claimToken       - The Revenue Token escrowed by Spigot to claim and use to repay debt\n     * @param zeroExTradeData  - data generated by the 0x dex API to trade `claimToken` against their exchange contract\n     * @return newTokens       - amount of credit tokens claimed or bought during call\n     */\n    function claimAndRepay(address claimToken, bytes calldata zeroExTradeData) external returns (uint256);\n\n    /**\n     *\n     * @notice - allows borrower to trade revenue to credit tokens at a favorable price without repaying debt\n     *         - sends all bought tokens to `unused` to be repaid later\n     *         - see SpigotedLine._claimAndTrade and SpigotedLineLib.claimAndTrade for more details\n     * @dev    - ensures first token in repayment queue is being bought\n     * @dev    - callable by `arbiter`\n     * @param claimToken      - The revenue token escrowed in the Spigot to sell in trade\n     * @param zeroExTradeData - 0x API data to use in trade to sell `claimToken` for `credits[ids[0]]`\n     * @return tokensBought   - amount of credit tokens bought\n     */\n    function claimAndTrade(address claimToken, bytes calldata zeroExTradeData) external returns (uint256 tokensBought);\n\n    // Spigot management functions\n\n    /**\n     * @notice - allow Line (aka Owner on Spigot) to add new revenue streams to repay credit\n     * @dev    - see Spigot.addSpigot()\n     * @dev    - callable `arbiter` ONLY\n     * @return            - if function call was successful\n     */\n    function addSpigot(address revenueContract, ISpigot.Setting calldata setting) external returns (bool);\n\n    /**\n     * @notice - Sets or resets the whitelisted functions that a Borrower [Operator] is allowed to perform on the revenue generating contracts\n     * @dev    - see Spigot.updateWhitelistedFunction()\n     * @dev    - callable `arbiter` ONLY\n     * @return           - if function call was successful\n     */\n    function updateWhitelist(bytes4 func, bool allowed) external returns (bool);\n\n    /**\n     * @notice - Changes the revenue split between the Treasury and the Line (Owner) based upon the status of the Line of Credit\n     * @dev    - callable by anyone\n     * @param revenueContract   - spigot to update\n     * @return didUpdate        - whether or not split was updated\n     */\n    function updateOwnerSplit(address revenueContract) external returns (bool);\n\n    /**\n     * @notice  - Transfers ownership of the entire Spigot from its then Owner to either the Borrower (if a Line of Credit has been been fully repaid)\n     *          - or to the Arbiter (if the Line of Credit is liquidatable).\n     * @dev     - callable by borrower + arbiter\n     * @param to          - address that caller wants to transfer Spigot ownership to\n     * @return bool       - whether or not a Spigot was released\n     */\n    function releaseSpigot(address to) external returns (bool);\n\n    /**\n     * @notice   - sends unused tokens to borrower if REPAID or arbiter if LIQUIDATABLE or INSOLVENT\n     *           -  does not send tokens out if line is ACTIVE\n     * @dev      - callable by `borrower` or `arbiter`\n     * @param to           - address to send swept tokens to\n     * @param token        - revenue or credit token to sweep\n     * @param amount       - amount of reserve tokens to withdraw/liquidate\n     */\n    function sweep(address to, address token, uint256 amount) external returns (uint256);\n\n    // getters\n\n    /**\n     * @notice - getter for `unusedTokens` mapping which is a private var\n     * @param token      - address for an ERC20\n     * @return amount    - amount of revenue tokens available to trade for credit tokens or credit tokens availble to repay debt with\n     */\n    function unused(address token) external returns (uint256);\n\n    /**\n     * @notice - Looksup `unusedTokens` + spigot.getOwnerTokens` for how many tokens arbiter must sell in claimAndTrade/Repay\n     * @param token      - address for an ERC20 earned as revenue\n     * @return amount    - amount of unused + claimable revenue tokens available to trade for credit tokens or credit tokens availble to repay debt with\n     */\n    function tradeable(address token) external returns (uint256);\n\n    function spigot() external returns (ISpigot);\n}\n"
      },
      "contracts/utils/SpigotLib.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 {ReentrancyGuard} from \"openzeppelin/utils/ReentrancyGuard.sol\";\nimport {LineLib} from \"../utils/LineLib.sol\";\nimport {ISpigot} from \"../interfaces/ISpigot.sol\";\n\nstruct SpigotState {\n    /// @notice Economic owner of Spigot revenue streams\n    address owner;\n    /// @notice account in charge of running onchain ops of spigoted contracts on behalf of owner\n    address operator;\n    /// @notice Total amount of revenue tokens help by the Spigot and available to be claimed by owner\n    mapping(address => uint256) ownerTokens; // token -> claimable\n    /// @notice Total amount of revenue tokens help by the Spigot and available to be claimed by operator\n    mapping(address => uint256) operatorTokens; // token -> claimable\n    /// @notice Functions that the operator is allowed to run on all revenue contracts controlled by the Spigot\n    mapping(bytes4 => bool) whitelistedFunctions; // function -> allowed\n    /// @notice Configurations for revenue contracts related to the split of revenue, access control to claiming revenue tokens and transfer of Spigot ownership\n    mapping(address => ISpigot.Setting) settings; // revenue contract -> settings\n}\n\n/**\n * @notice - helper lib for Spigot\n * @dev see Spigot docs\n */\nlibrary SpigotLib {\n    // Maximum numerator for Setting.ownerSplit param to ensure that the Owner can't claim more than 100% of revenue\n    uint8 constant MAX_SPLIT = 100;\n    // cap revenue per claim to avoid overflows on multiplication when calculating percentages\n    uint256 constant MAX_REVENUE = type(uint256).max / MAX_SPLIT;\n\n    function _claimRevenue(\n        SpigotState storage self,\n        address revenueContract,\n        address token,\n        bytes calldata data\n    ) public returns (uint256 claimed) {\n        if (self.settings[revenueContract].transferOwnerFunction == bytes4(0)) {\n            revert InvalidRevenueContract();\n        }\n\n        uint256 existingBalance = LineLib.getBalance(token);\n\n        if (self.settings[revenueContract].claimFunction == bytes4(0)) {\n            // push payments\n\n            // claimed = total balance - already accounted for balance\n            claimed = existingBalance - self.ownerTokens[token] - self.operatorTokens[token];\n\n            // underflow revert ensures we have more tokens than we started with and actually claimed revenue\n        } else {\n            // pull payments\n            if (bytes4(data) != self.settings[revenueContract].claimFunction) {\n                revert BadFunction();\n            }\n            (bool claimSuccess, ) = revenueContract.call(data);\n            if (!claimSuccess) {\n                revert ClaimFailed();\n            }\n\n            // claimed = total balance - existing balance\n            claimed = LineLib.getBalance(token) - existingBalance;\n            // underflow revert ensures we have more tokens than we started with and actually claimed revenue\n        }\n\n        if (claimed == 0) {\n            revert NoRevenue();\n        }\n\n        // cap so uint doesnt overflow in split calculations.\n        // can sweep by \"attaching\" a push payment spigot with same token\n        if (claimed > MAX_REVENUE) claimed = MAX_REVENUE;\n\n        return claimed;\n    }\n\n    /** see Spigot.claimRevenue */\n    function claimRevenue(\n        SpigotState storage self,\n        address revenueContract,\n        address token,\n        bytes calldata data\n    ) external returns (uint256 claimed) {\n        claimed = _claimRevenue(self, revenueContract, token, data);\n\n        // splits revenue stream according to Spigot settings\n        uint256 ownerTokens = (claimed * self.settings[revenueContract].ownerSplit) / 100;\n        // update escrowed balance\n        self.ownerTokens[token] = self.ownerTokens[token] + ownerTokens;\n\n        // update operator amount\n        if (claimed > ownerTokens) {\n            self.operatorTokens[token] = self.operatorTokens[token] + (claimed - ownerTokens);\n        }\n\n        emit ClaimRevenue(token, claimed, ownerTokens, revenueContract);\n\n        return claimed;\n    }\n\n    /** see Spigot.operate */\n    function operate(SpigotState storage self, address revenueContract, bytes calldata data) external returns (bool) {\n        if (msg.sender != self.operator) {\n            revert CallerAccessDenied();\n        }\n\n        // extract function signature from tx data and check whitelist\n        bytes4 func = bytes4(data);\n\n        if (!self.whitelistedFunctions[func]) {\n            revert OperatorFnNotWhitelisted();\n        }\n\n        // cant claim revenue via operate() because that fucks up accounting logic. Owner shouldn't whitelist it anyway but just in case\n        // also can't transfer ownership so Owner retains control of revenue contract\n        if (\n            func == self.settings[revenueContract].claimFunction ||\n            func == self.settings[revenueContract].transferOwnerFunction\n        ) {\n            revert OperatorFnNotValid();\n        }\n\n        (bool success, ) = revenueContract.call(data);\n        if (!success) {\n            revert OperatorFnCallFailed();\n        }\n\n        return true;\n    }\n\n    /** see Spigot.claimOwnerTokens */\n    function claimOwnerTokens(SpigotState storage self, address token) external returns (uint256 claimed) {\n        if (msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n\n        claimed = self.ownerTokens[token];\n\n        if (claimed == 0) {\n            revert ClaimFailed();\n        }\n\n        self.ownerTokens[token] = 0; // reset before send to prevent reentrancy\n\n        LineLib.sendOutTokenOrETH(token, self.owner, claimed);\n\n        emit ClaimOwnerTokens(token, claimed, self.owner);\n\n        return claimed;\n    }\n\n    /** see Spigot.claimOperatorTokens */\n    function claimOperatorTokens(SpigotState storage self, address token) external returns (uint256 claimed) {\n        if (msg.sender != self.operator) {\n            revert CallerAccessDenied();\n        }\n\n        claimed = self.operatorTokens[token];\n\n        if (claimed == 0) {\n            revert ClaimFailed();\n        }\n\n        self.operatorTokens[token] = 0; // reset before send to prevent reentrancy\n\n        LineLib.sendOutTokenOrETH(token, self.operator, claimed);\n\n        emit ClaimOperatorTokens(token, claimed, self.operator);\n\n        return claimed;\n    }\n\n    /** see Spigot.addSpigot */\n    function addSpigot(\n        SpigotState storage self,\n        address revenueContract,\n        ISpigot.Setting memory setting\n    ) external returns (bool) {\n        if (msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n\n        if (revenueContract == address(this)) {\n            revert InvalidRevenueContract();\n        }\n\n        // spigot setting already exists\n        if (self.settings[revenueContract].transferOwnerFunction != bytes4(0)) {\n            revert SpigotSettingsExist();\n        }\n\n        // must set transfer func\n        if (setting.transferOwnerFunction == bytes4(0)) {\n            revert BadSetting();\n        }\n        if (setting.ownerSplit > MAX_SPLIT) {\n            revert BadSetting();\n        }\n\n        self.settings[revenueContract] = setting;\n        emit AddSpigot(revenueContract, setting.ownerSplit, setting.claimFunction, setting.transferOwnerFunction);\n\n        return true;\n    }\n\n    /** see Spigot.removeSpigot */\n    function removeSpigot(SpigotState storage self, address revenueContract) external returns (bool) {\n        if (msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n\n        (bool success, ) = revenueContract.call(\n            abi.encodeWithSelector(\n                self.settings[revenueContract].transferOwnerFunction,\n                self.operator // assume function only takes one param that is new owner address\n            )\n        );\n        require(success);\n\n        delete self.settings[revenueContract];\n        emit RemoveSpigot(revenueContract);\n\n        return true;\n    }\n\n    /** see Spigot.updateOwnerSplit */\n    function updateOwnerSplit(\n        SpigotState storage self,\n        address revenueContract,\n        uint8 ownerSplit\n    ) external returns (bool) {\n        if (msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n        if (ownerSplit > MAX_SPLIT) {\n            revert BadSetting();\n        }\n\n        self.settings[revenueContract].ownerSplit = ownerSplit;\n        emit UpdateOwnerSplit(revenueContract, ownerSplit);\n\n        return true;\n    }\n\n    /** see Spigot.updateOwner */\n    function updateOwner(SpigotState storage self, address newOwner) external returns (bool) {\n        if (msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n        require(newOwner != address(0));\n        self.owner = newOwner;\n        emit UpdateOwner(newOwner);\n        return true;\n    }\n\n    /** see Spigot.updateOperator */\n    function updateOperator(SpigotState storage self, address newOperator) external returns (bool) {\n        if (msg.sender != self.operator && msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n        require(newOperator != address(0));\n        self.operator = newOperator;\n        emit UpdateOperator(newOperator);\n        return true;\n    }\n\n    /** see Spigot.updateWhitelistedFunction*/\n    function updateWhitelistedFunction(SpigotState storage self, bytes4 func, bool allowed) external returns (bool) {\n        if (msg.sender != self.owner) {\n            revert CallerAccessDenied();\n        }\n        self.whitelistedFunctions[func] = allowed;\n        emit UpdateWhitelistFunction(func, allowed);\n        return true;\n    }\n\n    /** see Spigot.isWhitelisted*/\n    function isWhitelisted(SpigotState storage self, bytes4 func) external view returns (bool) {\n        return self.whitelistedFunctions[func];\n    }\n\n    /** see Spigot.getSetting*/\n    function getSetting(\n        SpigotState storage self,\n        address revenueContract\n    ) external view returns (uint8, bytes4, bytes4) {\n        return (\n            self.settings[revenueContract].ownerSplit,\n            self.settings[revenueContract].claimFunction,\n            self.settings[revenueContract].transferOwnerFunction\n        );\n    }\n\n    // Spigot Events\n    event AddSpigot(address indexed revenueContract, uint256 ownerSplit, bytes4 claimFnSig, bytes4 trsfrFnSig);\n\n    event RemoveSpigot(address indexed revenueContract);\n\n    event UpdateWhitelistFunction(bytes4 indexed func, bool indexed allowed);\n\n    event UpdateOwnerSplit(address indexed revenueContract, uint8 indexed split);\n\n    event ClaimRevenue(address indexed token, uint256 indexed amount, uint256 ownerTokens, address revenueContract);\n\n    event ClaimOwnerTokens(address indexed token, uint256 indexed amount, address owner);\n\n    event ClaimOperatorTokens(address indexed token, uint256 indexed amount, address ooperator);\n\n    // Stakeholder Events\n\n    event UpdateOwner(address indexed newOwner);\n\n    event UpdateOperator(address indexed newOperator);\n\n    event UpdateTreasury(address indexed newTreasury);\n\n    // Errors\n\n    error BadFunction();\n\n    error OperatorFnNotWhitelisted();\n\n    error OperatorFnNotValid();\n\n    error OperatorFnCallFailed();\n\n    error ClaimFailed();\n\n    error NoRevenue();\n\n    error UnclaimedRevenue();\n\n    error CallerAccessDenied();\n\n    error BadSetting();\n\n    error InvalidRevenueContract();\n\n    error SpigotSettingsExist();\n}\n"
      },
      "lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == ENTERED;\n    }\n}\n"
      },
      "contracts/utils/CreditListLib.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 {ILineOfCredit} from \"../interfaces/ILineOfCredit.sol\";\nimport {IOracle} from \"../interfaces/IOracle.sol\";\nimport {CreditLib} from \"./CreditLib.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 CreditListLib {\n    event QueueCleared();\n    event SortedIntoQ(bytes32 indexed id, uint256 indexed newIdx, uint256 indexed oldIdx, bytes32 oldId);\n    error CantStepQ();\n\n    /**\n     * @notice  - Removes a position id from the active list of open positions.\n     * @dev     - assumes `id` is stored only once in the `positions` array. if `id` occurs twice, debt would be double counted.\n     * @param ids           - all current credit lines on the Line of Credit facility\n     * @param id            - the hash id of the credit line to be removed from active ids after removePosition() has run\n     * @return newPositions - all active credit lines on the Line of Credit facility after the `id` has been removed [Bob - consider renaming to newIds\n     */\n    function removePosition(bytes32[] storage ids, bytes32 id) external returns (bool) {\n        uint256 len = ids.length;\n\n        for (uint256 i; i < len; ++i) {\n            if (ids[i] == id) {\n                delete ids[i];\n                return true;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @notice  - swap the first element in the queue, provided it is null, with the next available valid(non-null) id\n     * @dev     - Must perform check for ids[0] being valid (non-zero) before calling\n     * @param ids       - all current credit lines on the Line of Credit facility\n     * @return swapped  - returns true if the swap has occurred\n     */\n    function stepQ(bytes32[] storage ids) external returns (bool) {\n        if (ids[0] != bytes32(0)) {\n            revert CantStepQ();\n        }\n\n        uint256 len = ids.length;\n        if (len <= 1) return false;\n\n        // skip the loop if we don't need\n        if (len == 2 && ids[1] != bytes32(0)) {\n            (ids[0], ids[1]) = (ids[1], ids[0]);\n            emit SortedIntoQ(ids[0], 0, 1, ids[1]);\n            return true;\n        }\n\n        // we never check the first id, because we already know it's null\n        for (uint i = 1; i < len; ) {\n            if (ids[i] != bytes32(0)) {\n                (ids[0], ids[i]) = (ids[i], ids[0]); // swap the ids in storage\n                emit SortedIntoQ(ids[0], 0, i, ids[i]);\n                return true; // if we make the swap, return early\n            }\n            unchecked {\n                ++i;\n            }\n        }\n        emit QueueCleared();\n        return false;\n    }\n}\n"
      },
      "contracts/modules/interest-rate/InterestRateCredit.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 {IInterestRateCredit} from \"../../interfaces/IInterestRateCredit.sol\";\n\ncontract InterestRateCredit is IInterestRateCredit {\n    // 1 Julian astronomical year in seconds to use in calculations for rates = 31557600 seconds\n    uint256 constant ONE_YEAR = 365.25 days;\n    // Must divide by 100 too offset bps in numerator and divide by another 100 to offset % and get actual token amount\n    uint256 constant BASE_DENOMINATOR = 10000;\n    // = 31557600 * 10000 = 315576000000;\n    uint256 constant INTEREST_DENOMINATOR = ONE_YEAR * BASE_DENOMINATOR;\n\n    address immutable lineContract;\n\n    mapping(bytes32 => Rate) public rates; // position id -> lending rates\n\n    /**\n     * @notice Interest rate / acrrued interest calculation contract for Line of Credit contracts\n     */\n    constructor() {\n        lineContract = msg.sender;\n    }\n\n    ///////////  MODIFIERS  ///////////\n\n    modifier onlyLineContract() {\n        require(msg.sender == lineContract, \"InterestRateCred: only line contract.\");\n        _;\n    }\n\n    /// see IInterestRateCredit.accrueInterest\n    function accrueInterest(\n        bytes32 id,\n        uint256 drawnBalance,\n        uint256 facilityBalance\n    ) external override onlyLineContract returns (uint256 accrued) {\n        accrued = _accrueInterest(id, drawnBalance, facilityBalance);\n        // update last timestamp in storage\n        rates[id].lastAccrued = block.timestamp;\n    }\n\n    function getInterestAccrued(\n        bytes32 id,\n        uint256 drawnBalance,\n        uint256 facilityBalance\n    ) external view returns (uint256) {\n        return _accrueInterest(id, drawnBalance, facilityBalance);\n    }\n\n    function _accrueInterest(\n        bytes32 id,\n        uint256 drawnBalance,\n        uint256 facilityBalance\n    ) internal view returns (uint256) {\n        Rate memory rate = rates[id];\n\n        // get time since interest was last accrued iwth these balances\n        uint256 timespan = block.timestamp - rate.lastAccrued;\n\n        return (_calculateInterestOwed(rate.dRate, drawnBalance, timespan) +\n            _calculateInterestOwed(rate.fRate, (facilityBalance - drawnBalance), timespan));\n    }\n\n    /**\n     * @notice - total interest to accrue based on apr, balance, and length of time\n     * @dev    - r = APR in bps, x = # tokens, t = time\n     *         - interest = (r * x * t) / 1yr / 100\n     * @param  bpsRate  - interest rate (APR) to charge against balance in bps (4 decimals)\n     * @param  balance  - current balance for interest rate tier to charge interest against\n     * @param  timespan - total amount of time that interest should be charged for\n     *\n     * @return interestOwed\n     */\n    function _calculateInterestOwed(\n        uint256 bpsRate,\n        uint256 balance,\n        uint256 timespan\n    ) internal pure returns (uint256) {\n        return (bpsRate * balance * timespan) / INTEREST_DENOMINATOR;\n    }\n\n    /// see IInterestRateCredit.setRate\n    function setRate(bytes32 id, uint128 dRate, uint128 fRate) external onlyLineContract returns (bool) {\n        rates[id] = Rate({dRate: dRate, fRate: fRate, lastAccrued: block.timestamp});\n        return true;\n    }\n\n    function getRates(bytes32 id) external view returns (uint128, uint128) {\n        return (rates[id].dRate, rates[id].fRate);\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"
      }
    },
    "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/CreditListLib.sol": {
          "CreditListLib": "0x9cbe9741b3503a790e69e1587b5d51c0056154dc"
        },
        "contracts/utils/EscrowLib.sol": {
          "EscrowLib": "0x9ae9c76276e503105f20c8b452ccd0c4ee3b2df2"
        },
        "contracts/utils/LineFactoryLib.sol": {
          "LineFactoryLib": "0x2b721a999b83cbcc1DBD697A27199d5b4Be70102"
        },
        "contracts/utils/LineLib.sol": {
          "LineLib": "0x73cb72a7efaddd99cdd2d110e2f4b8b65bf3b812"
        },
        "contracts/utils/SpigotLib.sol": {
          "SpigotLib": "0x05b4180e2ee77a04f3f0dc833e36b7d9f1141e02"
        },
        "contracts/utils/SpigotedLineLib.sol": {
          "SpigotedLineLib": "0x274946031D204567281F7616718b4aBB940Ef784"
        }
      }
    }
  }}