creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    /**\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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\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        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease 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 safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\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. Compatible with tokens that require the approval to be set to\n     * 0 before setting it to a non-zero value.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * 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\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SignedMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\nimport \"./math/SignedMath.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `int256` to its ASCII `string` decimal representation.\n     */\n    function toString(int256 value) internal pure returns (string memory) {\n        return string(abi.encodePacked(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value))));\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n\n    /**\n     * @dev Returns true if the two strings are equal.\n     */\n    function equal(string memory a, string memory b) internal pure returns (bool) {\n        return keccak256(bytes(a)) == keccak256(bytes(b));\n    }\n}\n"
      },
      "contracts/facets/AccessControlFacet.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\nimport {LibDiamond} from \"../libraries/LibDiamond.sol\";\r\n\r\nerror AccessControlIsInitialized();\r\nerror AccessDenied(address executor, uint256 deniedForRole);\r\n\r\n/// @title Access Control Library\r\nlibrary AccessControlLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.accesscontrol.storage\");\r\n    uint256 constant FULL_PRIVILEGES_MASK = type(uint256).max;\r\n    uint256 constant ROLE_ACCESS_MANAGER = 0x8000000000000000000000000000000000000000000000000000000000000000;\r\n    uint32 constant ROLE_CREATE_MANAGER = 0x0001_0000;\r\n    uint32 constant ROLE_DELETE_MANAGER = 0x0002_0000;\r\n    uint32 constant ROLE_EDIT_MANAGER = 0x0004_0000;\r\n    uint32 constant ROLE_CONFIG_MANAGER = 0x0008_0000;\r\n    uint32 constant ROLE_INVEST_MANAGER = 0x0010_0000;\r\n    uint32 constant ROLE_WITHDRAW_MANAGER = 0x0020_0000;\r\n    uint32 constant ROLE_DISTRIBUTE_MANAGER = 0x0040_0000;\r\n    uint32 constant ROLE_FEE_MANAGER = 0x0080_0000;\r\n\r\n    struct AccessControlState {\r\n        mapping(address => uint256) userRoles;\r\n        bool isInitialized;\r\n    }\r\n\r\n    event RoleUpdated(address indexed by, address indexed to, uint256 requested, uint256 actual);\r\n\r\n    /// @dev Returns storage position of access control library inside diamond\r\n    function diamondStorage() internal pure returns (AccessControlState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Checks if role `actual` contains all the permissions required `required`\r\n    /// @param _actual Existent role\r\n    /// @param _required Required role\r\n    /// @return true If actual has required role (all permissions), false otherwise\r\n\tfunction hasRole(uint256 _actual, uint256 _required) internal pure returns(bool) {\r\n\t\treturn _actual & _required == _required;\r\n\t}\r\n    \r\n    /// @dev Effectively reads userRoles role for the contract itself\r\n    /// @notice Retrieves globally set of features enabled\r\n    /// @return 256-bit bitmask of the features enabled\r\n    function features() internal view returns(uint256) {\r\n\t\tAccessControlState storage accessControlState = diamondStorage();\r\n        return accessControlState.userRoles[address(this)];\r\n\t}\r\n\r\n    /// @dev Checks if requested set of features is enabled globally on the contract\r\n    /// @param _required Set of features to check against\r\n    /// @return true If all the features requested are enabled, false otherwise\r\n    function isFeatureEnabled(uint256 _required) internal view returns(bool) {\r\n\t\treturn hasRole(features(), _required);\r\n\t}\r\n\r\n    /// @dev Checks if operator has all the permissions (role) required\r\n    /// @param _operator Address of the user to check role for\r\n    /// @param _required Set of permissions (role) to check\r\n    /// @return true If all the permissions requested are enabled, false otherwise\r\n    function isOperatorInRole(address _operator, uint256 _required) internal view returns(bool) {\r\n\t\tAccessControlState storage accessControlState = diamondStorage();\r\n        return hasRole(accessControlState.userRoles[_operator], _required);\r\n\t}\r\n\r\n    /// @dev Checks if transaction sender `msg.sender` has all the permissions required\r\n    /// @param _required Set of permissions (role) to check against\r\n    /// @return true If all the permissions requested are enabled, false otherwise\r\n\tfunction isSenderInRole(uint256 _required) internal view returns(bool) {\r\n\t\treturn isOperatorInRole(msg.sender, _required);\r\n\t}\r\n\r\n    /// @notice Determines the permission bitmask an operator can set on the target permission set\r\n    /// @notice Used to calculate the permission bitmask to be set when requested\r\n    //          in `updateRole` and `updateFeatures` functions\r\n    //\r\n    /// @dev Calculated based on:\r\n    //       1) operator's own permission set read from userRoles[operator]\r\n    //       2) target permission set - what is already set on the target\r\n    //       3) desired permission set - what do we want set target to\r\n    //\r\n    /// @dev Corner cases:\r\n    //       1) Operator is super admin and its permission set is `FULL_PRIVILEGES_MASK`:\r\n    //        `desired` bitset is returned regardless of the `target` permission set value\r\n    //        (what operator sets is what they get)\r\n    //       2) Operator with no permissions (zero bitset):\r\n    //        `target` bitset is returned regardless of the `desired` value\r\n    //        (operator has no authority and cannot modify anything)\r\n    //\r\n    /// @dev Example:\r\n    //       Consider an operator with the permissions bitmask     00001111\r\n    //       is about to modify the target permission set          01010101\r\n    //       Operator wants to set that permission set to          00110011\r\n    //       Based on their role, an operator has the permissions\r\n    //       to update only lowest 4 bits on the target, meaning that\r\n    //       high 4 bits of the target set in this example is left\r\n    //       unchanged and low 4 bits get changed as desired:      01010011\r\n    //\r\n    /// @param _operator Address of the contract operator which is about to set the permissions\r\n    /// @param _target Input set of permissions to operator is going to modify\r\n    /// @param _desired Desired set of permissions operator would like to set\r\n    /// @return Set of permissions given operator will set\r\n    function evaluateBy(address _operator, uint256 _target, uint256 _desired) internal view returns(uint256) {\r\n\t\tAccessControlState storage accessControlState = diamondStorage();\r\n\t\tuint256 p = accessControlState.userRoles[_operator];\r\n        _target |= p & _desired;\r\n\t\t_target &= FULL_PRIVILEGES_MASK ^ (p & (FULL_PRIVILEGES_MASK ^ _desired));\r\n\t\treturn _target;\r\n\t}\r\n\r\n    /// @dev Initializes access control by assigning full privileges to contract owner\r\n    /// @notice Restricted access function, should be called by owner only\r\n    function initializeAccessControl() internal {\r\n        LibDiamond.enforceIsContractOwner();\r\n        AccessControlState storage accessControlState = diamondStorage();\r\n        if(accessControlState.isInitialized) {\r\n            revert AccessControlIsInitialized();\r\n        }\r\n        accessControlState.userRoles[LibDiamond.contractOwner()] = FULL_PRIVILEGES_MASK;\r\n        accessControlState.isInitialized = true;\r\n    }\r\n\r\n    /// @dev Updates set of permissions (role) for a given user, \r\n    //       taking into account sender's permissions\r\n    /// @notice Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\r\n    /// @param _operator Address of a user to alter permissions for or zero\r\n    //         to alter global features of the smart contract\r\n    /// @param _role Bitmask representing a set of permissions to enable/disable for a user specified\r\n\tfunction updateRole(address _operator, uint256 _role) internal {\r\n\t\tAccessControlState storage accessControlState = diamondStorage();\r\n        if(!isSenderInRole(ROLE_ACCESS_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_ACCESS_MANAGER);\r\n        }\r\n\t\taccessControlState.userRoles[_operator] = evaluateBy(msg.sender, accessControlState.userRoles[_operator], _role);\r\n        emit RoleUpdated(msg.sender, _operator, _role, accessControlState.userRoles[_operator]);\r\n    }\r\n\r\n    /// @dev Updates set of the globally enabled features (`features`)\r\n    /// @notice Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\r\n    /// @param _mask Bitmask representing a set of features to enable/disable\r\n    function updateFeatures(uint256 _mask) internal {\r\n\t\tupdateRole(address(this), _mask);\r\n\t}\r\n\r\n    /// @dev Throws error if sender do not have create manager role\r\n    function enforceIsCreateManager() internal view {\r\n        if(!isSenderInRole(ROLE_CREATE_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_CREATE_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have delete manager role\r\n    function enforceIsDeleteManager() internal view {\r\n        if(!isSenderInRole(ROLE_DELETE_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_DELETE_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have edit manager role\r\n    function enforceIsEditManager() internal view {\r\n        if(!isSenderInRole(ROLE_EDIT_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_EDIT_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have config manager role\r\n    function enforceIsConfigManager() internal view {\r\n        if(!isSenderInRole(ROLE_CONFIG_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_CONFIG_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have invest manager role\r\n    function enforceIsInvestManager() internal view {\r\n        if(!isSenderInRole(ROLE_INVEST_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_INVEST_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have withdraw manager role\r\n    function enforceIsWithdrawManager() internal view {\r\n        if(!isSenderInRole(ROLE_WITHDRAW_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_WITHDRAW_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have distribute manager role\r\n    function enforceIsDistributeManager() internal view {\r\n        if(!isSenderInRole(ROLE_DISTRIBUTE_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_DISTRIBUTE_MANAGER);\r\n        }        \r\n    }\r\n\r\n    /// @dev Throws error if sender do not have fee manager role\r\n    function enforceIsFeeManager() internal view {\r\n        if(!isSenderInRole(ROLE_FEE_MANAGER)) {\r\n            revert AccessDenied(msg.sender, ROLE_FEE_MANAGER);\r\n        }        \r\n    }\r\n}\r\n\r\n/// @title Access Control Facet\r\ncontract AccessControlFacet {\r\n    /// @dev Effectively reads userRoles role for the contract itself\r\n    /// @notice Retrieves globally set of features enabled\r\n    /// @return 256-bit bitmask of the features enabled\r\n    function features() external view returns(uint256) {\r\n\t\treturn AccessControlLib.features();\r\n\t}\r\n\r\n    /// @dev Checks if requested set of features is enabled globally on the contract\r\n    /// @param _required Set of features to check against\r\n    /// @return true If all the features requested are enabled, false otherwise\r\n    function isFeatureEnabled(uint256 _required) external view returns(bool) {\r\n\t\treturn AccessControlLib.isFeatureEnabled(_required);\r\n\t}\r\n\r\n    /// @dev Checks if operator has all the permissions (role) required\r\n    /// @param _operator Address of the user to check role for\r\n    /// @param _required Set of permissions (role) to check\r\n    /// @return true If all the permissions requested are enabled, false otherwise\r\n    function isOperatorInRole(address _operator, uint256 _required) external view returns(bool) {\r\n\t\treturn AccessControlLib.isOperatorInRole(_operator, _required);\r\n\t}\r\n\r\n    /// @dev Checks if transaction sender `msg.sender` has all the permissions required\r\n    /// @param _required Set of permissions (role) to check against\r\n    /// @return true If all the permissions requested are enabled, false otherwise\r\n\tfunction isSenderInRole(uint256 _required) external view returns(bool) {\r\n\t\treturn AccessControlLib.isSenderInRole(_required);\r\n\t}\r\n\r\n    /// @dev Initializes access control by assigning full privileges to contract owner\r\n    /// @notice Restricted access function, should be called by owner only\r\n    function initializeAccessControl() external {\r\n        AccessControlLib.initializeAccessControl();\r\n    }\r\n    \r\n    /// @dev Updates set of permissions (role) for a given user, \r\n    //       taking into account sender's permissions\r\n    /// @notice Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\r\n    /// @param _operator Address of a user to alter permissions for or zero\r\n    //         to alter global features of the smart contract\r\n    /// @param _role Bitmask representing a set of permissions to enable/disable for a user specified\r\n\tfunction updateRole(address _operator, uint256 _role) external {\r\n\t\tAccessControlLib.updateRole(_operator, _role);\r\n\t}\r\n\r\n    /// @dev Updates set of the globally enabled features (`features`)\r\n    /// @notice Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission\r\n    /// @param _mask Bitmask representing a set of features to enable/disable\r\n    function updateFeatures(uint256 _mask) external {\r\n\t\treturn AccessControlLib.updateRole(address(this), _mask);\r\n\t}\r\n}"
      },
      "contracts/facets/CreditPoolFacet.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {PoolManagerLib} from \"./PoolManagerFacet.sol\";\r\nimport {LenderLib} from \"./LenderFacet.sol\";\r\nimport {VaultLib} from \"./VaultFacet.sol\";\r\nimport {MetadataLib} from \"./MetadataFacet.sol\";\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\nimport {StableCoinLib} from \"./StableCoinExtension.sol\";\r\n\r\nerror CreditPoolIdExist(string _id);\r\nerror NotCreditPoolCall();\r\nerror PoolIsNotActive(string _id);\r\nerror PoolIsExpired(string _id);\r\nerror LenderIdsExist(uint256 _length);\r\nerror InvalidRoleOrPoolId(string roleId, string poolId);\r\nerror InvalidLenderOrPoolId(string roleId, string poolId);\r\nerror LenderBoundWithPool(string roleId, string poolId);\r\nerror InvalidPoolId(string poolId);\r\nerror InvalidAmount(uint256 amount);\r\n\r\n/// @title Credit Pool Library\r\nlibrary CreditPoolLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.creditpool.storage\");\r\n\r\n    struct CreditPoolState {\r\n        mapping(string => CreditPool) creditPools;\r\n        mapping(string => mapping(string => Binding)) lenderBinding;\r\n        bool isCreditPoolCall;\r\n    }\r\n\r\n    struct CreditPool {\r\n        string creditPoolId;\r\n        string poolManagerId;\r\n        string metaHash;\r\n        uint256 borrowingAmount;\r\n        uint64 inceptionTime;\r\n        uint64 expiryTime;\r\n        uint32 curingPeriod;\r\n        CreditRatings ratings;\r\n        uint16 bindingIndex;\r\n        CreditPoolStatus status;\r\n        string[] lenderIds;\r\n        string[] paymentIds;\r\n    }\r\n\r\n    struct Binding {\r\n        bool isBound;\r\n        uint16 lenderIndexInPool;\r\n        uint16 poolIndexInLender;\r\n    }\r\n\r\n    enum CreditRatings {PENDING, AAA, AA, A, BBB, BB, B, CCC, CC, C}\r\n\r\n    enum CreditPoolStatus {PENDING, ACTIVE, INACTIVE}\r\n\r\n    /// @dev Returns storage position of credit pool library inside diamond\r\n    function diamondStorage() internal pure returns (CreditPoolState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns on-chain attributes of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool \r\n    function getCreditPool(string calldata _poolId) internal view returns (CreditPool memory) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId];\r\n    }\r\n\r\n    /// @dev Returns PoolManagerId of the manager who owns given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolManagerId(string calldata _poolId) internal view returns (string memory) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].poolManagerId;\r\n    }\r\n\r\n    /// @dev Returns IPFS hash of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolMetaHash(string calldata _poolId) internal view returns (string memory) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].metaHash;\r\n    }\r\n\r\n    /// @dev Returns pool size of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolBorrowingAmount(string memory _poolId) internal view returns (uint256) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].borrowingAmount;\r\n    }\r\n\r\n    /// @dev Returns credit pool inception time (Unix timestamp)\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolInceptionTime(string calldata _poolId) internal view returns (uint64) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].inceptionTime;\r\n    }\r\n\r\n    /// @dev Returns credit pool cut-off time (Unix timestamp)\r\n    ///      beyond which pool won't accept new investment from lenders\r\n    /// @param _poolId PoolId associated with given credit pool  \r\n    function getCreditPoolExpiryTime(string calldata _poolId) internal view returns (uint64) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].expiryTime;\r\n    }\r\n\r\n    /// @dev Returns curing period (in seconds) of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool \r\n    function getCreditPoolCuringPeriod(string calldata _poolId) internal view returns (uint32) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].curingPeriod;\r\n    }\r\n\r\n    /// @dev Returns credit ratings of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolRatings(string calldata _poolId) internal view returns (CreditRatings) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].ratings;\r\n    }\r\n\r\n    /// @dev Returns index of given credit pool in pool manager's pool list\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolBindingIndex(string calldata _poolId) internal view returns (uint16) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].bindingIndex;\r\n    }\r\n\r\n    /// @dev Returns credit pool status\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolStatus(string calldata _poolId) internal view returns (CreditPoolStatus) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].status;\r\n    }\r\n\r\n    /// @dev Returns number of active lenders associated with given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getLenderIdsLength(string calldata _poolId) internal view returns (uint256) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].lenderIds.length;\r\n    }\r\n\r\n    /// @dev Returns LenderId that is associated with given credit pool based on given index\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    /// @param _index Index number to query\r\n    function getLenderId(string calldata _poolId, uint256 _index) internal view returns (string memory) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].lenderIds[_index];\r\n    }\r\n\r\n    /// @dev Returns number if payments associated with given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getPaymentIdsLength(string calldata _poolId) internal view returns (uint256) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].paymentIds.length;\r\n    }\r\n\r\n    /// @dev Returns PaymentId that is associated with given credit pool based on given index\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    /// @param _index Index number to query\r\n    function getPaymentId(string calldata _poolId, uint256 _index) internal view returns (string memory) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.creditPools[_poolId].paymentIds[_index];\r\n    }\r\n\r\n    /// @dev Returns index of given credit pool in lender's pool list\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getLenderBinding(string calldata _lenderId, string calldata _poolId) internal view returns (Binding memory) {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        return creditPoolState.lenderBinding[_lenderId][_poolId];\r\n    }\r\n\r\n    /// @dev Returns IPFS URL of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getMetadataURI(string calldata _poolId) internal view returns (string memory) {\r\n        enforceIsCreditPoolIdExist(_poolId);\r\n        string memory _baseURI = MetadataLib.getBaseURI();\r\n        string memory _metaHash = getCreditPoolMetaHash(_poolId);\r\n        return bytes(_baseURI).length > 0 ? string(string.concat(bytes(_baseURI), bytes(_metaHash))) : \"\";\r\n    }\r\n\r\n    /// @dev Creates a new credit pool\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _creditPoolId Id associated with credit pool\r\n    /// @param _poolManagerId PoolManagerId of manager who owns the pool\r\n    /// @param _metaHash IPFS hash of credit pool\r\n    /// @param _borrowingAmount Pool size\r\n    /// @param _inceptionTime Credit pool inception time (Unix timestamp)\r\n    /// @param _expiryTime Credit pool cut-off time (Unix timestamp)\r\n    /// @param _curingPeriod Curing period of credit pool in seconds\r\n    /// @param _status Status of cresit pool\r\n    function createCreditPool(\r\n        string calldata _creditPoolId,\r\n        string calldata _poolManagerId,\r\n        string calldata _metaHash,\r\n        uint256 _borrowingAmount,\r\n        uint64 _inceptionTime,\r\n        uint64 _expiryTime,\r\n        uint32 _curingPeriod,\r\n        CreditPoolStatus _status\r\n    ) internal returns (CreditPool memory) {\r\n        AccessControlLib.enforceIsCreateManager();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(keccak256(bytes(_creditPoolId)) == keccak256(bytes(creditPoolState.creditPools[_creditPoolId].creditPoolId))) {\r\n            revert CreditPoolIdExist(_creditPoolId);\r\n        }\r\n        PoolManagerLib.enforceIsPoolManagerKYBVerified(_poolManagerId);\r\n        creditPoolState.creditPools[_creditPoolId] = CreditPool(\r\n            _creditPoolId,\r\n            _poolManagerId,\r\n            _metaHash,\r\n            _borrowingAmount,\r\n            _inceptionTime,\r\n            _expiryTime,\r\n            _curingPeriod,\r\n            CreditRatings.PENDING,\r\n            uint16(PoolManagerLib.getPoolIdsLength(_poolManagerId)),\r\n            _status,\r\n            new string[](0),\r\n            new string[](0)\r\n        );\r\n        creditPoolState.isCreditPoolCall = true;\r\n        PoolManagerLib.addPoolId(_poolManagerId, _creditPoolId);\r\n        creditPoolState.isCreditPoolCall = false;\r\n        return creditPoolState.creditPools[_creditPoolId];\r\n    }\r\n\r\n    /// @dev Deletes existing credit pool\r\n    /// @notice Restricted access function, should be called by an address with delete manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    function removeCreditPool(string calldata _creditPoolId) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(creditPoolState.creditPools[_creditPoolId].lenderIds.length != 0) {\r\n            revert LenderIdsExist(creditPoolState.creditPools[_creditPoolId].lenderIds.length);\r\n        }\r\n        string memory _poolManagerId = creditPoolState.creditPools[_creditPoolId].poolManagerId;\r\n        uint16 _index = creditPoolState.creditPools[_creditPoolId].bindingIndex;\r\n        creditPoolState.isCreditPoolCall = true;\r\n        PoolManagerLib.removePoolIdByIndex(_poolManagerId, _index);\r\n        StableCoinLib.deletePoolToken(_creditPoolId);\r\n        creditPoolState.isCreditPoolCall = false;\r\n        delete creditPoolState.creditPools[_creditPoolId];\r\n    }\r\n\r\n    /// @dev Updates IPFS hash of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _hash IPFS hash of credit pool\r\n    function updateCreditPoolHash(string calldata _creditPoolId, string calldata _hash) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsCreditPoolIdExist(_creditPoolId);\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.creditPools[_creditPoolId].metaHash = _hash;\r\n    }\r\n\r\n    /// @dev Updates pool size of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _borrowingAmount Pool size of given credit pool\r\n    function updateCreditPoolBorrowingAmount(string calldata _creditPoolId, uint256 _borrowingAmount) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsCreditPoolIdExist(_creditPoolId);\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(_borrowingAmount < VaultLib.getBorrowedAmount(_creditPoolId)) {\r\n            revert InvalidAmount(_borrowingAmount);\r\n        }\r\n        creditPoolState.creditPools[_creditPoolId].borrowingAmount = _borrowingAmount;\r\n    }\r\n\r\n    /// @dev Updates inception time of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _inceptionTime Inception time (Unix timestamp) of credit pool\r\n    function updateCreditPoolInceptionTime(string calldata _creditPoolId, uint64 _inceptionTime) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsCreditPoolIdExist(_creditPoolId);\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.creditPools[_creditPoolId].inceptionTime = _inceptionTime;\r\n    }\r\n\r\n    /// @dev Updates expiry time of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _expiryTime Cut-off time (Unix timestamp) of credit pool\r\n    function updateCreditPoolExpiryTime(string calldata _creditPoolId, uint64 _expiryTime) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsCreditPoolIdExist(_creditPoolId);\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.creditPools[_creditPoolId].expiryTime = _expiryTime;\r\n    }\r\n\r\n    /// @dev Updates curing period of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _curingPeriod Curing period (In seconds) of credit pool \r\n    function updateCreditPoolCuringPeriod(string calldata _creditPoolId, uint32 _curingPeriod) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsCreditPoolIdExist(_creditPoolId);\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.creditPools[_creditPoolId].curingPeriod = _curingPeriod;\r\n    }\r\n\r\n    /// @dev Updates index of credit pool in pool manager's pool list\r\n    /// @notice Called internally when pool list of pool manager gets updated\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _bindingIndex Index of credit pool to assign in pool manager's pool list\r\n    function updateBindingIndexOfPool(string memory _creditPoolId, uint256 _bindingIndex) internal {\r\n        enforceIsCreditPool();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.creditPools[_creditPoolId].bindingIndex = uint16(_bindingIndex);\r\n    }\r\n\r\n    /// @dev Updates credit ratings of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _ratings Credit ratings of given credit pool\r\n    function updateCreditRatings(string calldata _creditPoolId, CreditRatings _ratings) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(creditPoolState.creditPools[_creditPoolId].status != CreditPoolStatus.ACTIVE) {\r\n            revert PoolIsNotActive(_creditPoolId);\r\n        }\r\n        creditPoolState.creditPools[_creditPoolId].ratings = _ratings;\r\n    }\r\n\r\n    /// @dev Updates status of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _status Status of given credit pool\r\n    function updateCreditPoolStatus(string calldata _creditPoolId, CreditPoolStatus _status) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsCreditPoolIdExist(_creditPoolId);\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.creditPools[_creditPoolId].status = _status;\r\n    }\r\n\r\n    /// @dev Updates index of credit pool in lender's pool list\r\n    /// @notice Called internally when pool list of lender gets updated\r\n    /// @param _lenderId LenderId of lender whose pool list gets updated\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _poolIndexInLender Index of credit pool to assign in lender's pool list\r\n    function updatePoolIndexInLender(\r\n        string memory _lenderId,\r\n        string memory _creditPoolId,\r\n        uint256 _poolIndexInLender\r\n    ) internal {\r\n        enforceIsCreditPool();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        creditPoolState.lenderBinding[_lenderId][_creditPoolId].poolIndexInLender = uint16(_poolIndexInLender);\r\n    }\r\n\r\n    /// @dev Adds LenderId to given credit pool's lender list\r\n    /// @notice Called internally when lender makes a new investment\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _lenderId LenderId of lender who invested in given credit pool\r\n    function addLenderId(string memory _creditPoolId, string memory _lenderId) internal {\r\n        VaultLib.enforceIsVault();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(creditPoolState.creditPools[_creditPoolId].status != CreditPoolStatus.ACTIVE) {\r\n            revert PoolIsNotActive(_creditPoolId);\r\n        }\r\n        if(!creditPoolState.lenderBinding[_lenderId][_creditPoolId].isBound) {\r\n            uint16 _lenderIndexInPool = uint16(creditPoolState.creditPools[_creditPoolId].lenderIds.length);\r\n            uint16 _poolIndexInLender = uint16(LenderLib.getPoolIdsLength(_lenderId));\r\n            creditPoolState.isCreditPoolCall = true;\r\n            LenderLib.addPoolId(_lenderId, _creditPoolId);\r\n            creditPoolState.isCreditPoolCall = false;\r\n            creditPoolState.creditPools[_creditPoolId].lenderIds.push(_lenderId);\r\n            creditPoolState.lenderBinding[_lenderId][_creditPoolId] = Binding(true, _lenderIndexInPool, _poolIndexInLender);\r\n        }\r\n    }\r\n\r\n    /// @dev Removes LenderId from given credit pool's lender list\r\n    /// @notice Called internally when lender exits the pool\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _lenderId LenderId of lender who exited from given credit pool\r\n    function removeLenderId(string memory _creditPoolId, string memory _lenderId) internal {\r\n        VaultLib.enforceIsVault();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(creditPoolState.lenderBinding[_lenderId][_creditPoolId].isBound) {\r\n            uint16 _lastLenderIndexInPool = uint16(creditPoolState.creditPools[_creditPoolId].lenderIds.length - 1);\r\n            uint16 _lenderIndexInPool = creditPoolState.lenderBinding[_lenderId][_creditPoolId].lenderIndexInPool;\r\n            uint16 _poolIndexInLender = creditPoolState.lenderBinding[_lenderId][_creditPoolId].poolIndexInLender;\r\n            creditPoolState.isCreditPoolCall = true;\r\n            LenderLib.removePoolIdByIndex(_lenderId, _poolIndexInLender);\r\n            creditPoolState.isCreditPoolCall = false;\r\n            if(_lenderIndexInPool != _lastLenderIndexInPool) {\r\n                creditPoolState.creditPools[_creditPoolId].lenderIds[_lenderIndexInPool] = creditPoolState.creditPools[_creditPoolId].lenderIds[_lastLenderIndexInPool];\r\n                string memory _lastLenderId = creditPoolState.creditPools[_creditPoolId].lenderIds[_lenderIndexInPool];\r\n                creditPoolState.lenderBinding[_lastLenderId][_creditPoolId].lenderIndexInPool = uint16(_lenderIndexInPool);\r\n            }\r\n            creditPoolState.creditPools[_creditPoolId].lenderIds.pop();\r\n            delete creditPoolState.lenderBinding[_lenderId][_creditPoolId];\r\n        }\r\n    }\r\n\r\n    /// @dev Adds PaymentId associated with given credit pool\r\n    /// @notice Called internally whenever a new payment registered to given credit pool \r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _paymentId PaymentId associated with a new payment\r\n    function addPaymentId(string memory _creditPoolId, string memory _paymentId) internal {\r\n        VaultLib.enforceIsVault();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        CreditPool storage creditPool = creditPoolState.creditPools[_creditPoolId];\r\n        creditPool.paymentIds.push(_paymentId);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given credit pool\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _paymentId PaymentId to remove\r\n    function removePaymentId(string calldata _creditPoolId, string calldata _paymentId) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        CreditPool storage creditPool = creditPoolState.creditPools[_creditPoolId];\r\n        uint256 index;\r\n        for (uint256 i = 0; i < creditPool.paymentIds.length; i++) {\r\n            if (keccak256(bytes(creditPool.paymentIds[i])) == keccak256(bytes(_paymentId))) {\r\n                index = i;\r\n                break;\r\n            }\r\n        }\r\n        creditPool.paymentIds[index] = creditPool.paymentIds[creditPool.paymentIds.length - 1];\r\n        creditPool.paymentIds.pop();\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given credit pool\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _paymentIndex Index of PaymentId to remove\r\n    function removePaymentIdByIndex(string calldata _creditPoolId, uint256 _paymentIndex) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        CreditPool storage creditPool = creditPoolState.creditPools[_creditPoolId];\r\n        if(_paymentIndex != creditPool.paymentIds.length - 1) {\r\n            creditPool.paymentIds[_paymentIndex] = creditPool.paymentIds[creditPool.paymentIds.length - 1];\r\n        }\r\n        creditPool.paymentIds.pop();\r\n    }\r\n\r\n    /// @dev Throws error if called by other than credit pool library\r\n    function enforceIsCreditPool() internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(!creditPoolState.isCreditPoolCall) {\r\n            revert NotCreditPoolCall();\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if pool is not active\r\n    function enforceIsActivePool(string memory _creditPoolId) internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(creditPoolState.creditPools[_creditPoolId].status != CreditPoolStatus.ACTIVE) {\r\n            revert PoolIsNotActive(_creditPoolId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if pool cut-off time reached\r\n    function enforcePoolIsNotExpired(string memory _creditPoolId) internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(block.timestamp > creditPoolState.creditPools[_creditPoolId].expiryTime) {\r\n            revert PoolIsExpired(_creditPoolId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if lender is not active investor of given pool\r\n    function enforceIsLenderBoundWithPool(string calldata _lenderId, string calldata _creditPoolId) internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(!creditPoolState.lenderBinding[_lenderId][_creditPoolId].isBound) {\r\n            revert InvalidLenderOrPoolId(_lenderId, _creditPoolId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if lender is active investor of given pool\r\n    function enforceLenderIsNotBoundWithPool(string calldata _lenderId, string calldata _creditPoolId) internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(creditPoolState.lenderBinding[_lenderId][_creditPoolId].isBound) {\r\n            revert LenderBoundWithPool(_lenderId, _creditPoolId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if pool manager is not owner of the pool\r\n    function enforceIsPoolManagerBoundWithPool(string calldata _poolManagerId, string calldata _creditPoolId) internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(keccak256(bytes(_poolManagerId)) != keccak256(bytes(creditPoolState.creditPools[_creditPoolId].poolManagerId))) {\r\n            revert InvalidRoleOrPoolId(_poolManagerId, _creditPoolId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if credit pool not exist\r\n    function enforceIsCreditPoolIdExist(string calldata _creditPoolId) internal view {\r\n        CreditPoolState storage creditPoolState = diamondStorage();\r\n        if(bytes(creditPoolState.creditPools[_creditPoolId].creditPoolId).length == 0) {\r\n            revert InvalidPoolId(_creditPoolId);\r\n        }\r\n    }\r\n}\r\n\r\n// @title Credit Pool Facet\r\ncontract CreditPoolFacet {\r\n    event CreateCreditPoolEvent(CreditPoolLib.CreditPool creditPool);\r\n    event DeleteCreditPoolEvent(string indexed poolId);\r\n    event UpdateCreditPoolHashEvent(string indexed poolId, string prevHash, string newHash);\r\n    event UpdateCreditPoolBorrowingAmountEvent(string indexed poolId, uint256 prevAmount, uint256 newAmount);\r\n    event UpdateCreditPoolInceptionTimeEvent(string indexed poolId, uint64 prevTime, uint64 newTime);\r\n    event UpdateCreditPoolExpiryTimeEvent(string indexed poolId, uint64 prevTime, uint64 newTime);\r\n    event UpdateCreditPoolCuringPeriodEvent(string indexed poolId, uint32 prevPeriod, uint32 newPeriod);\r\n    event UpdateCreditRatingsEvent(\r\n        string indexed poolId,\r\n        CreditPoolLib.CreditRatings prevRatings,\r\n        CreditPoolLib.CreditRatings newRatings\r\n    );\r\n    event UpdateCreditPoolStatusEvent(\r\n        string indexed poolId,\r\n        CreditPoolLib.CreditPoolStatus prevStatus,\r\n        CreditPoolLib.CreditPoolStatus newStatus\r\n    );\r\n\r\n    /// @dev Returns on-chain attributes of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool \r\n    function getCreditPool(string calldata _poolId) external view returns (CreditPoolLib.CreditPool memory) {\r\n        return CreditPoolLib.getCreditPool(_poolId);\r\n    }\r\n\r\n    /// @dev Returns PoolManagerId of the manager who owns given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolManagerId(string calldata _poolId) external view returns (string memory) {\r\n        return CreditPoolLib.getCreditPoolManagerId(_poolId);\r\n    }\r\n\r\n    /// @dev Returns IPFS hash of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolMetaHash(string calldata _poolId) external view returns (string memory) {\r\n        return CreditPoolLib.getCreditPoolMetaHash(_poolId);\r\n    }\r\n\r\n    /// @dev Returns pool size of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolBorrowingAmount(string calldata _poolId) external view returns (uint256) {\r\n        return CreditPoolLib.getCreditPoolBorrowingAmount(_poolId);\r\n    }\r\n\r\n    /// @dev Returns credit pool inception time (Unix timestamp)\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolInceptionTime(string calldata _poolId) external view returns (uint64) {\r\n        return CreditPoolLib.getCreditPoolInceptionTime(_poolId);\r\n    }\r\n\r\n    /// @dev Returns credit pool cut-off time (Unix timestamp)\r\n    ///      beyond which pool won't accept new investment from lenders\r\n    /// @param _poolId PoolId associated with given credit pool  \r\n    function getCreditPoolExpiryTime(string calldata _poolId) external view returns (uint64) {\r\n        return CreditPoolLib.getCreditPoolExpiryTime(_poolId);\r\n    }\r\n\r\n    /// @dev Returns curing period (in seconds) of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool \r\n    function getCreditPoolCuringPeriod(string calldata _poolId) external view returns (uint32) {\r\n        return CreditPoolLib.getCreditPoolCuringPeriod(_poolId);\r\n    }\r\n\r\n    /// @dev Returns credit ratings of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolRatings(string calldata _poolId) external view returns (CreditPoolLib.CreditRatings) {\r\n        return CreditPoolLib.getCreditPoolRatings(_poolId);\r\n    }\r\n\r\n    /// @dev Returns index of given credit pool in pool manager's pool list\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolBindingIndex(string calldata _poolId) external view returns (uint16) {\r\n        return CreditPoolLib.getCreditPoolBindingIndex(_poolId);\r\n    }\r\n\r\n    /// @dev Returns credit pool status\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolStatus(string calldata _poolId) external view returns (CreditPoolLib.CreditPoolStatus) {\r\n        return CreditPoolLib.getCreditPoolStatus(_poolId);\r\n    }\r\n\r\n    /// @dev Returns number of active lenders associated with given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolLenderIdsLength(string calldata _poolId) external view returns (uint256) {\r\n        return CreditPoolLib.getLenderIdsLength(_poolId);\r\n    }\r\n\r\n    /// @dev Returns LenderId that is associated with given credit pool based on given index\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    /// @param _index Index number to query\r\n    function getCreditPoolLenderId(string calldata _poolId, uint256 _index) external view returns (string memory) {\r\n        return CreditPoolLib.getLenderId(_poolId, _index);\r\n    }\r\n\r\n    /// @dev Returns number if payments associated with given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolPaymentIdsLength(string calldata _poolId) external view returns (uint256) {\r\n        return CreditPoolLib.getPaymentIdsLength(_poolId);\r\n    }\r\n\r\n    /// @dev Returns PaymentId that is associated with given credit pool based on given index\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    /// @param _index Index number to query\r\n    function getCreditPoolPaymentId(string calldata _poolId, uint256 _index) external view returns (string memory) {\r\n        return CreditPoolLib.getPaymentId(_poolId, _index);\r\n    }\r\n\r\n    /// @dev Returns index of given credit pool in lender's pool list\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getLenderBinding(string calldata _lenderId, string calldata _poolId) external view returns (CreditPoolLib.Binding memory) {\r\n        return CreditPoolLib.getLenderBinding(_lenderId, _poolId);\r\n    }\r\n\r\n    /// @dev Returns IPFS URL of given credit pool\r\n    /// @param _poolId PoolId associated with given credit pool\r\n    function getCreditPoolMetadataURI(string calldata _poolId) external view returns (string memory) {\r\n        return CreditPoolLib.getMetadataURI(_poolId);\r\n    }\r\n\r\n    /// @dev Creates a new credit pool\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _creditPoolId Id associated with credit pool\r\n    /// @param _poolManagerId PoolManagerId of manager who owns the pool\r\n    /// @param _metaHash IPFS hash of credit pool\r\n    /// @param _borrowingAmount Pool size\r\n    /// @param _inceptionTime Credit pool inception time (Unix timestamp)\r\n    /// @param _expiryTime Credit pool cut-off time (Unix timestamp)\r\n    /// @param _curingPeriod Curing period of credit pool in seconds\r\n    /// @param _status Status of cresit pool\r\n    function createCreditPool(\r\n        string calldata _creditPoolId,\r\n        string calldata _poolManagerId,\r\n        string calldata _metaHash,\r\n        uint256 _borrowingAmount,\r\n        uint64 _inceptionTime,\r\n        uint64 _expiryTime,\r\n        uint32 _curingPeriod,\r\n        CreditPoolLib.CreditPoolStatus _status\r\n    ) external {\r\n        CreditPoolLib.CreditPool memory creditPool = CreditPoolLib.createCreditPool(_creditPoolId, _poolManagerId, _metaHash, _borrowingAmount, _inceptionTime, _expiryTime, _curingPeriod, _status);\r\n        emit CreateCreditPoolEvent(creditPool);\r\n    }\r\n\r\n    /// @dev Deletes existing credit pool\r\n    /// @notice Restricted access function, should be called by an address with delete manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    function deleteCreditPool(string calldata _creditPoolId) external {\r\n        CreditPoolLib.removeCreditPool(_creditPoolId);\r\n        emit DeleteCreditPoolEvent(_creditPoolId);\r\n    }\r\n\r\n    /// @dev Updates IPFS hash of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _hash IPFS hash of credit pool\r\n    function updateCreditPoolHash(string calldata _creditPoolId, string calldata _hash) external {\r\n        string memory _prevHash = CreditPoolLib.getCreditPoolMetaHash(_creditPoolId);\r\n        CreditPoolLib.updateCreditPoolHash(_creditPoolId, _hash);\r\n        emit UpdateCreditPoolHashEvent(_creditPoolId, _prevHash, _hash);\r\n    }\r\n\r\n    /// @dev Updates pool size of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _amount Pool size of given credit pool\r\n    function updateCreditPoolBorrowingAmount(string calldata _creditPoolId, uint256 _amount) external {\r\n        uint256 _prevAmount = CreditPoolLib.getCreditPoolBorrowingAmount(_creditPoolId);\r\n        CreditPoolLib.updateCreditPoolBorrowingAmount(_creditPoolId, _amount);\r\n        emit UpdateCreditPoolBorrowingAmountEvent(_creditPoolId, _prevAmount, _amount);\r\n    }\r\n\r\n    /// @dev Updates inception time of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _time Inception time (Unix timestamp) of credit pool\r\n    function updateCreditPoolInceptionTime(string calldata _creditPoolId, uint64 _time) external {\r\n        uint64 _prevTime = CreditPoolLib.getCreditPoolInceptionTime(_creditPoolId);\r\n        CreditPoolLib.updateCreditPoolInceptionTime(_creditPoolId, _time);\r\n        emit UpdateCreditPoolInceptionTimeEvent(_creditPoolId, _prevTime, _time);\r\n    }\r\n\r\n    /// @dev Updates expiry time of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _time Cut-off time (Unix timestamp) of credit pool\r\n    function updateCreditPoolExpiryTime(string calldata _creditPoolId, uint64 _time) external {\r\n        uint64 _prevTime = CreditPoolLib.getCreditPoolExpiryTime(_creditPoolId);\r\n        CreditPoolLib.updateCreditPoolExpiryTime(_creditPoolId, _time);\r\n        emit UpdateCreditPoolExpiryTimeEvent(_creditPoolId, _prevTime, _time);\r\n    }\r\n\r\n    /// @dev Updates curing period of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _curingPeriod Curing period (In seconds) of credit pool \r\n    function updateCreditPoolCuringPeriod(string calldata _creditPoolId, uint32 _curingPeriod) external {\r\n        uint32 _prevPeriod = CreditPoolLib.getCreditPoolCuringPeriod(_creditPoolId);\r\n        CreditPoolLib.updateCreditPoolCuringPeriod(_creditPoolId, _curingPeriod);\r\n        emit UpdateCreditPoolCuringPeriodEvent(_creditPoolId, _prevPeriod, _curingPeriod);\r\n    }\r\n\r\n    /// @dev Updates credit ratings of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _ratings Credit ratings of given credit pool\r\n    function updateCreditRatings(string calldata _creditPoolId, CreditPoolLib.CreditRatings _ratings) external {\r\n        CreditPoolLib.CreditRatings _prevRatings = CreditPoolLib.getCreditPoolRatings(_creditPoolId);\r\n        CreditPoolLib.updateCreditRatings(_creditPoolId, _ratings);\r\n        emit UpdateCreditRatingsEvent(_creditPoolId, _prevRatings, _ratings);\r\n    }\r\n\r\n    /// @dev Updates status of given credit pool\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _status Status of given credit pool\r\n    function updateCreditPoolStatus(string calldata _creditPoolId, CreditPoolLib.CreditPoolStatus _status) external {\r\n        CreditPoolLib.CreditPoolStatus _prevStatus = CreditPoolLib.getCreditPoolStatus(_creditPoolId);\r\n        CreditPoolLib.updateCreditPoolStatus(_creditPoolId, _status);\r\n        emit UpdateCreditPoolStatusEvent(_creditPoolId, _prevStatus, _status);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given credit pool\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _paymentId PaymentId to remove\r\n    function removeCreditPoolPaymentId(string calldata _creditPoolId, string calldata _paymentId) external {\r\n        CreditPoolLib.removePaymentId(_creditPoolId, _paymentId);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given credit pool\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _paymentIndex Index of PaymentId to remove\r\n    function removeCreditPoolPaymentIdByIndex(string calldata _creditPoolId, uint256 _paymentIndex) external {\r\n        CreditPoolLib.removePaymentIdByIndex(_creditPoolId, _paymentIndex);\r\n    }\r\n}"
      },
      "contracts/facets/DistributeExtension.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\nimport {VaultLib} from \"./VaultFacet.sol\";\r\n\r\nerror InvalidSigner(address signer, uint256 deniedForRole);\r\nerror NonceUsed(address signer, uint256 nonce);\r\nerror NotDistributeCall();\r\n\r\n/// @title Distribute Library\r\nlibrary DistributeLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.distribute.storage\");\r\n    bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256(\r\n        \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\r\n    );\r\n    bytes32 constant PAYMENT_INFO_TYPEHASH = keccak256(\r\n        \"PaymentInfo(uint256 amount,uint8 paymentType)\"\r\n    );\r\n    bytes32 constant REQUEST_TYPEHASH = keccak256(\r\n        \"Request(uint256 nonce,string roleId,string poolId,PaymentInfo[] paymentInfo)PaymentInfo(uint256 amount,uint8 paymentType)\"\r\n    );\r\n\r\n    struct DistributeState {\r\n        mapping(address => mapping(uint256 => bool)) usedNonces;\r\n        bytes32 domainSeperator;\r\n        bool isDistributeCall;   \r\n    }\r\n\r\n    struct Request {\r\n        uint256 nonce;\r\n        string roleId;\r\n        string poolId;\r\n        VaultLib.PaymentInfo[] paymentInfo;\r\n    }\r\n\r\n    event AuthorizationUsed(address indexed authorizer, Request request);\r\n\r\n    /// @dev Returns storage position of distribute library inside diamond\r\n    function diamondStorage() internal pure returns (DistributeState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n    \r\n    /// @dev Internal function to return encoded data of given payment information struct\r\n    /// @param _paymentInfo Payment information \r\n    function encodePaymentInfo(VaultLib.PaymentInfo calldata _paymentInfo) internal pure returns (bytes memory) {\r\n        return abi.encode(PAYMENT_INFO_TYPEHASH, _paymentInfo.amount, _paymentInfo.paymentType);\r\n    }\r\n\r\n    /// @dev Internal function to return hash of given request\r\n    /// @param _request Request information\r\n    function hashStruct(Request calldata _request) internal pure returns (bytes32) {\r\n        bytes32[] memory encodedPaymentInfo = new bytes32[](_request.paymentInfo.length);\r\n        for (uint256 i = 0; i < _request.paymentInfo.length; i++) {\r\n            encodedPaymentInfo[i] = keccak256(encodePaymentInfo(_request.paymentInfo[i]));\r\n        }\r\n        return\r\n            keccak256(\r\n                abi.encode(\r\n                    REQUEST_TYPEHASH,\r\n                    _request.nonce,\r\n                    keccak256(abi.encodePacked(_request.roleId)),\r\n                    keccak256(abi.encodePacked(_request.poolId)),\r\n                    keccak256(abi.encodePacked(encodedPaymentInfo))\r\n                )\r\n            );\r\n    }\r\n\r\n    /// @dev Returns the state of an authorization,\r\n    //       more specifically if the specified nonce was already used by the address specified\r\n    /// @param _signer Signer's address\r\n    /// @param _nonce Nonce of the authorization\r\n    /// @return true if nonce is used\r\n    function authorizationState(address _signer, uint256 _nonce) internal view returns (bool) {\r\n        DistributeState storage distributeState = diamondStorage();\r\n        return distributeState.usedNonces[_signer][_nonce];\r\n    }\r\n\r\n    /// @dev Returns EIP-712 contract's domain separator\r\n    /// @notice see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator\r\n    function getDomainSeperator() internal view returns (bytes32) {\r\n        DistributeState storage distributeState = diamondStorage();\r\n        return distributeState.domainSeperator;\r\n    }\r\n\r\n    /// @dev Returns chain id to construct domain seperator\r\n    function getChainId() internal view returns (uint256) {\r\n        uint256 id;\r\n        assembly {\r\n            id := chainid()\r\n        }\r\n        return id;\r\n    }\r\n\r\n    /// @dev Accept message hash and returns hash message in EIP712 compatible form,\r\n    //       So that it can be used to recover signer from signature signed using EIP712 formatted data \r\n    function toTypedMessageHash(bytes32 _messageHash) internal view returns (bytes32) {\r\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", getDomainSeperator(), _messageHash));\r\n    }\r\n\r\n    /// @dev Sets the EIP-712 contract domain separator\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    function setDomainSeperator() internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        DistributeState storage distributeState = diamondStorage();\r\n        distributeState.domainSeperator = keccak256(\r\n            abi.encode(\r\n                EIP712_DOMAIN_TYPEHASH,\r\n                keccak256(bytes(\"cSigmaDiamond\")),\r\n                keccak256(bytes(\"1\")),\r\n                getChainId(),\r\n                address(this)\r\n            )\r\n        );\r\n    }\r\n\r\n    /// @dev Withdraws undistributed paid amount into the vault account of given lender\r\n    /// @notice Throws error if signer do not have ROLE_DISTRIBUTE_MANAGER permission\r\n    /// @param _request Request struct\r\n    /// @param _sigR Half of the ECDSA signature pair\r\n    /// @param _sigS Half of the ECDSA signature pair\r\n    /// @param _sigV The recovery byte of the signature \r\n    function withdrawPoolPaymentIntoVault(\r\n        Request calldata _request,\r\n        bytes32 _sigR,\r\n        bytes32 _sigS,\r\n        uint8 _sigV\r\n    ) internal {\r\n        DistributeState storage distributeState = diamondStorage();\r\n        address _signer = ecrecover(toTypedMessageHash(hashStruct(_request)), _sigV, _sigR, _sigS);\r\n        if(!AccessControlLib.isOperatorInRole(_signer, AccessControlLib.ROLE_DISTRIBUTE_MANAGER)) {\r\n            revert InvalidSigner(_signer, AccessControlLib.ROLE_DISTRIBUTE_MANAGER);\r\n        }\r\n        if(distributeState.usedNonces[_signer][_request.nonce]) {\r\n            revert NonceUsed(_signer, _request.nonce);\r\n        }\r\n        distributeState.usedNonces[_signer][_request.nonce] = true;\r\n        distributeState.isDistributeCall = true;\r\n        VaultLib.distribute(_request.roleId, _request.poolId, _request.paymentInfo);\r\n        distributeState.isDistributeCall = false;\r\n        emit AuthorizationUsed(_signer, _request);\r\n    }\r\n\r\n    /// @dev Throws error if called by other than distribute library\r\n    function enforceIsDistribute() internal view {\r\n        DistributeState storage distributeState = diamondStorage();\r\n        if(!distributeState.isDistributeCall) {\r\n            revert NotDistributeCall();\r\n        }\r\n    }\r\n}\r\n\r\n/// @title Distribute facet\r\ncontract DistributeFacet {\r\n    event Distribute(string indexed roleId, string poolId, VaultLib.PaymentInfo[] paymentInfo);\r\n    event Withdraw(string indexed roleId, uint256 amount);\r\n    event WithdrawStableCoin(string indexed roleId, address token, uint256 amount);\r\n    event WithdrawRequest(string roleId, address token, uint256 amount);\r\n    \r\n    /// @dev Returns the state of an authorization,\r\n    //       more specifically if the specified nonce was already used by the address specified\r\n    /// @param _signer Signer's address\r\n    /// @param _nonce Nonce of the authorization\r\n    /// @return true if nonce is used\r\n    function authorizationState(address _signer, uint256 _nonce) external view returns (bool) {\r\n        return DistributeLib.authorizationState(_signer, _nonce);\r\n    }\r\n\r\n    /// @dev Returns EIP-712 contract's domain separator\r\n    /// @notice see https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator\r\n    function getDomainSeperator() external view returns (bytes32) {\r\n        return DistributeLib.getDomainSeperator();\r\n    }\r\n\r\n    /// @dev Sets the EIP-712 contract domain separator\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    function setDomainSeperator() external {\r\n        return DistributeLib.setDomainSeperator();\r\n    }\r\n\r\n    /// @dev Withdraws undistributed paid amount into the vault account of given lender\r\n    /// @notice Throws error if signer do not have ROLE_DISTRIBUTE_MANAGER permission\r\n    /// @param _request Request struct\r\n    /// @param _sigR Half of the ECDSA signature pair\r\n    /// @param _sigS Half of the ECDSA signature pair\r\n    /// @param _sigV The recovery byte of the signature \r\n    function withdrawPoolPaymentIntoVault(\r\n        DistributeLib.Request calldata _request,\r\n        bytes32 _sigR,\r\n        bytes32 _sigS,\r\n        uint8 _sigV\r\n    ) external { \r\n        DistributeLib.withdrawPoolPaymentIntoVault(_request, _sigR, _sigS, _sigV);\r\n        emit Distribute(_request.roleId, _request.poolId, _request.paymentInfo);\r\n    }\r\n\r\n    /// @dev Withdraws undistributed paid amount into the vault account of given lender,\r\n    //       Submits withdraw request to withdraw given amount into the wallet\r\n    /// @notice Throws error if signer do not have ROLE_DISTRIBUTE_MANAGER permission\r\n    /// @param _request Request struct\r\n    /// @param _sigR Half of the ECDSA signature pair\r\n    /// @param _sigS Half of the ECDSA signature pair\r\n    /// @param _sigV The recovery byte of the signature\r\n    /// @param _token Address of token to withdraw from vault\r\n    /// @param _amount Amount of token to withdraw from vault  \r\n    function withdrawPoolPaymentIntoWallet(\r\n        DistributeLib.Request calldata _request,\r\n        bytes32 _sigR,\r\n        bytes32 _sigS,\r\n        uint8 _sigV,\r\n        address _token,\r\n        uint256 _amount\r\n    ) external {\r\n        DistributeLib.withdrawPoolPaymentIntoVault(_request, _sigR, _sigS, _sigV);\r\n        emit Distribute(_request.roleId, _request.poolId, _request.paymentInfo);\r\n        bool _isWithdrawn = VaultLib.withdrawRequest(_request.roleId, _token, _amount);\r\n        if(_isWithdrawn) {\r\n            if(_token == VaultLib.getPaymentToken()) {\r\n                emit Withdraw(_request.roleId, _amount);\r\n            } else {\r\n                emit WithdrawStableCoin(_request.roleId, _token, _amount);\r\n            }\r\n        } else {\r\n            emit WithdrawRequest(_request.roleId, _token, _amount);\r\n        }\r\n    }\r\n}"
      },
      "contracts/facets/LenderFacet.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {CreditPoolLib} from \"./CreditPoolFacet.sol\";\r\nimport {VaultLib} from \"./VaultFacet.sol\";\r\nimport {MetadataLib} from \"./MetadataFacet.sol\";\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\n\r\nerror NotLender(address _user, address _lender);\r\nerror LenderIdExist(string _id);\r\nerror PoolIdsExist(uint256 _length);\r\nerror NotVerifiedLender(string _id);\r\nerror InvalidLenderId(string _id);\r\n\r\n/// @title Lender library\r\nlibrary LenderLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.lender.storage\");\r\n\r\n    struct LenderState {\r\n        mapping(string => Lender) lenders;\r\n    }\r\n\r\n    struct Lender {\r\n        string lenderId;\r\n        string userId;\r\n        string metaHash;\r\n        string country;\r\n        uint64 onBoardTime;\r\n        address wallet;\r\n        KYBStatus status;\r\n        string[] poolIds;\r\n        string[] paymentIds;\r\n    }\r\n\r\n    enum KYBStatus {PENDING, VERIFIED, REJECTED}\r\n\r\n    /// @dev Returns storage position of lender library inside diamond\r\n    function diamondStorage() internal pure returns (LenderState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns on-chain attributes of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLender(string calldata _lenderId) internal view returns (Lender memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId];\r\n    }\r\n\r\n    /// @dev Returns userId of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderUserId(string calldata _lenderId) internal view returns (string memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].userId;\r\n    }\r\n\r\n    /// @dev Returns IPFS hash of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderMetaHash(string calldata _lenderId) internal view returns (string memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].metaHash;\r\n    }\r\n\r\n    /// @dev Returns country of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderCountry(string calldata _lenderId) internal view returns (string memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].country;\r\n    }\r\n\r\n    /// @dev Returns onboarding time (Unix timestamp) of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderOnBoardTime(string calldata _lenderId) internal view returns (uint64) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].onBoardTime;\r\n    }\r\n\r\n    /// @dev Returns wallet address of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderWallet(string calldata _lenderId) internal view returns (address) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].wallet;\r\n    }\r\n\r\n    /// @dev Returns KYB status of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderKYBStatus(string calldata _lenderId) internal view returns (KYBStatus) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].status;\r\n    }\r\n\r\n    /// @dev Returns number of active pools for given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getPoolIdsLength(string memory _lenderId) internal view returns (uint256) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].poolIds.length;\r\n    }\r\n\r\n    /// @dev Returns PoolId associated with given lender at given index\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _index Index number to query\r\n    function getPoolId(string calldata _lenderId, uint256 _index) internal view returns (string memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].poolIds[_index];\r\n    }\r\n\r\n    /// @dev Returns all PoolIds associated with given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getPoolIds(string calldata _lenderId) internal view returns (string[] memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].poolIds;\r\n    }\r\n\r\n    /// @dev Returns number of payments associated with given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getPaymentIdsLength(string calldata _lenderId) internal view returns (uint256) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].paymentIds.length;\r\n    }\r\n\r\n    /// @dev Returns PaymentId that is associated with given lender at given index\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _index Index number to query\r\n    function getPaymentId(string calldata _lenderId, uint256 _index) internal view returns (string memory) {\r\n        LenderState storage lenderState = diamondStorage();\r\n        return lenderState.lenders[_lenderId].paymentIds[_index];\r\n    }\r\n\r\n    /// @dev Returns IPFS URL of given Lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getMetadataURI(string calldata _lenderId) internal view returns (string memory) {\r\n        enforceIsLenderIdExist(_lenderId);\r\n        string memory _baseURI = MetadataLib.getBaseURI();\r\n        string memory _metaHash = getLenderMetaHash(_lenderId);\r\n        return bytes(_baseURI).length > 0 ? string(string.concat(bytes(_baseURI), bytes(_metaHash))) : \"\";\r\n    }\r\n\r\n    /// @dev Creates a new lender\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _lenderId RoleId associated with lender\r\n    /// @param _userId UserId associated with lender\r\n    /// @param _metaHash IPFS has of lender\r\n    /// @param _country Country code of lender\r\n    /// @param _onBoardTime On-boarding time (Unix timestamp) of lender\r\n    /// @param _wallet Wallet address of lender\r\n    /// @param _status KYB status of lender \r\n    function createLender(\r\n        string calldata _lenderId,\r\n        string calldata _userId,\r\n        string calldata _metaHash,\r\n        string calldata _country,\r\n        uint64 _onBoardTime,\r\n        address _wallet,\r\n        KYBStatus _status\r\n    ) internal returns (Lender memory) {\r\n        AccessControlLib.enforceIsCreateManager();\r\n        LenderState storage lenderState = diamondStorage();\r\n        if(keccak256(bytes(_lenderId)) == keccak256(bytes(lenderState.lenders[_lenderId].lenderId))) {\r\n            revert LenderIdExist(_lenderId);\r\n        }\r\n        lenderState.lenders[_lenderId] = Lender(_lenderId, _userId, _metaHash, _country, _onBoardTime, _wallet, _status, new string[](0), new string[](0));\r\n        return lenderState.lenders[_lenderId];\r\n    }\r\n\r\n    /// @dev Deletes existing lender\r\n    /// @notice Restricted access function, should be called by an address with delete manager role\r\n    /// @param _lenderId LenderId to delete\r\n    function removeLender(string calldata _lenderId) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        LenderState storage lenderState = diamondStorage();\r\n        if(lenderState.lenders[_lenderId].poolIds.length != 0) {\r\n            revert PoolIdsExist(lenderState.lenders[_lenderId].poolIds.length);\r\n        }\r\n        delete lenderState.lenders[_lenderId];\r\n    }\r\n\r\n    /// @dev Updates IPFS hash of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _hash New IPFS hash to set \r\n    function updateLenderHash(string calldata _lenderId, string calldata _hash) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsLenderIdExist(_lenderId);\r\n        LenderState storage lenderState = diamondStorage();\r\n        lenderState.lenders[_lenderId].metaHash = _hash;\r\n    }\r\n\r\n    /// @dev Updates country of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _country New country to set\r\n    function updateLenderCountry(string calldata _lenderId, string calldata _country) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsLenderIdExist(_lenderId);\r\n        LenderState storage lenderState = diamondStorage();\r\n        lenderState.lenders[_lenderId].country = _country;\r\n    }\r\n\r\n    /// @dev Updates on-boarding time (Unix timestamp) of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _onBoardTime New on-board time (Unix timestamp) to set\r\n    function updateLenderOnBoardTime(string calldata _lenderId, uint64 _onBoardTime) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsLenderIdExist(_lenderId);\r\n        LenderState storage lenderState = diamondStorage();\r\n        lenderState.lenders[_lenderId].onBoardTime = _onBoardTime;\r\n    }\r\n\r\n    /// @dev Updates wallet address of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _wallet New wallet address to set\r\n    function updateLenderWallet(string calldata _lenderId, address _wallet) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsLenderIdExist(_lenderId);\r\n        LenderState storage lenderState = diamondStorage();\r\n        lenderState.lenders[_lenderId].wallet = _wallet;\r\n    }\r\n\r\n    /// @dev Updates KYB status of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _status KYB status to set  \r\n    function updateLenderKYB(string calldata _lenderId, KYBStatus _status) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsLenderIdExist(_lenderId);\r\n        LenderState storage lenderState = diamondStorage();\r\n        lenderState.lenders[_lenderId].status = _status;\r\n    }\r\n\r\n    /// @dev Adds PoolId to given lender's pool list\r\n    /// @notice Called internally whenever lender invests for first time in given pool\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _poolId PoolId in which lender has invested for first time\r\n    function addPoolId(string memory _lenderId, string memory _poolId) internal {\r\n        CreditPoolLib.enforceIsCreditPool();\r\n        LenderState storage lenderState = diamondStorage();\r\n        Lender storage lender = lenderState.lenders[_lenderId];\r\n        lender.poolIds.push(_poolId);\r\n    }\r\n\r\n    /// @dev Removes PoolId from given lender's pool list based on given index\r\n    /// @notice Called internally whenever lender exits from given pool\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _poolIndex Index of pool to remove from lender's pool list\r\n    function removePoolIdByIndex(string memory _lenderId, uint256 _poolIndex) internal {\r\n        CreditPoolLib.enforceIsCreditPool();\r\n        LenderState storage lenderState = diamondStorage();\r\n        Lender storage lender = lenderState.lenders[_lenderId];\r\n        if(_poolIndex != lender.poolIds.length - 1) {\r\n            lender.poolIds[_poolIndex] = lender.poolIds[lender.poolIds.length - 1];\r\n            string memory _poolId = lender.poolIds[_poolIndex];\r\n            CreditPoolLib.updatePoolIndexInLender(_lenderId, _poolId, _poolIndex);\r\n        }\r\n        lender.poolIds.pop();\r\n    }\r\n    \r\n    /// @dev Adds PaymentId associated with given lender\r\n    /// @notice Called internally whenever a new payment registered that is associated with given lender \r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _paymentId PaymentId associated with a new payment\r\n    function addPaymentId(string memory _lenderId, string memory _paymentId) internal {\r\n        VaultLib.enforceIsVault();\r\n        LenderState storage lenderState = diamondStorage();\r\n        Lender storage lender = lenderState.lenders[_lenderId];\r\n        lender.paymentIds.push(_paymentId);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given lender\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _paymentId PaymentId to remove\r\n    function removePaymentId(string calldata _lenderId, string calldata _paymentId) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        LenderState storage lenderState = diamondStorage();\r\n        Lender storage lender = lenderState.lenders[_lenderId];\r\n        uint256 index;\r\n        for (uint256 i = 0; i < lender.paymentIds.length; i++) {\r\n            if (keccak256(bytes(lender.paymentIds[i])) == keccak256(bytes(_paymentId))) {\r\n                index = i;\r\n                break;\r\n            }\r\n        }\r\n        lender.paymentIds[index] = lender.paymentIds[lender.paymentIds.length - 1];\r\n        lender.paymentIds.pop();\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given lender based on given index\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _paymentIndex Index of PaymentId to remove\r\n    function removePaymentIdByIndex(string calldata _lenderId, uint256 _paymentIndex) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        LenderState storage lenderState = diamondStorage();\r\n        Lender storage lender = lenderState.lenders[_lenderId];\r\n        if(_paymentIndex != lender.paymentIds.length - 1) {\r\n            lender.paymentIds[_paymentIndex] = lender.paymentIds[lender.paymentIds.length - 1];\r\n        }\r\n        lender.paymentIds.pop();\r\n    }\r\n\r\n    /// @dev Throws error if called by other than lender\r\n    function enforceIsLender(string calldata _lenderId) internal view {\r\n        LenderState storage lenderState = diamondStorage();\r\n        if(msg.sender != lenderState.lenders[_lenderId].wallet) {\r\n            revert NotLender(msg.sender, lenderState.lenders[_lenderId].wallet);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if lender is not KYB verified\r\n    function enforceIsLenderKYBVerified(string memory _lenderId) internal view {\r\n        LenderState storage lenderState = diamondStorage();\r\n        if(lenderState.lenders[_lenderId].status != KYBStatus.VERIFIED) {\r\n            revert NotVerifiedLender(_lenderId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if lender id not exist\r\n    function enforceIsLenderIdExist(string calldata _lenderId) internal view {\r\n        LenderState storage lenderState = diamondStorage();\r\n        if(bytes(lenderState.lenders[_lenderId].lenderId).length == 0) {\r\n            revert InvalidLenderId(_lenderId);\r\n        }\r\n    }\r\n\r\n}\r\n\r\n/// @title Lender Facet\r\ncontract LenderFacet {\r\n    event DeleteLenderEvent(string indexed lenderId);\r\n    event CreateLenderEvent(LenderLib.Lender lender);\r\n    event UpdateLenderHashEvent(string indexed lenderId, string prevHash, string newHash);\r\n    event UpdateLenderCountryEvent(string indexed lenderId, string prevCountry, string newCountry);\r\n    event UpdateLenderOnBoardTimeEvent(string indexed lenderId, uint64 prevTime, uint64 newTime);\r\n    event UpdateLenderWalletEvent(string indexed lenderId, address prevWallet, address newWallet);\r\n    event UpdateLenderKYBEvent(string indexed lenderId, LenderLib.KYBStatus prevStatus, LenderLib.KYBStatus newStatus);\r\n    \r\n    /// @dev Returns on-chain attributes of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLender(string calldata _lenderId) external view returns (LenderLib.Lender memory) {\r\n        return LenderLib.getLender(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns userId of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderUserId(string calldata _lenderId) external view returns (string memory) {\r\n        return LenderLib.getLenderUserId(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns IPFS hash of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderMetaHash(string calldata _lenderId) external view returns (string memory) {\r\n        return LenderLib.getLenderMetaHash(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns country of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderCountry(string calldata _lenderId) external view returns (string memory) {\r\n        return LenderLib.getLenderCountry(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns onboarding time (Unix timestamp) of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderOnBoardTime(string calldata _lenderId) external view returns (uint64) {\r\n        return LenderLib.getLenderOnBoardTime(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns wallet address of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderWallet(string calldata _lenderId) external view returns (address) {\r\n        return LenderLib.getLenderWallet(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns KYB status of given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderKYBStatus(string calldata _lenderId) external view returns (LenderLib.KYBStatus) {\r\n        return LenderLib.getLenderKYBStatus(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns number of active pools for given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderPoolIdsLength(string calldata _lenderId) external view returns (uint256) {\r\n        return LenderLib.getPoolIdsLength(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns PoolId associated with given lender at given index\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _index Index number to query\r\n    function getLenderPoolId(string calldata _lenderId, uint256 _index) external view returns (string memory) {\r\n        return LenderLib.getPoolId(_lenderId, _index);\r\n    }\r\n\r\n    /// @dev Returns all PoolIds associated with given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderPoolIds(string calldata _lenderId) external view returns (string[] memory) {\r\n        return LenderLib.getPoolIds(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns number of payments associated with given lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderPaymentIdsLength(string calldata _lenderId) external view returns (uint256) {\r\n        return LenderLib.getPaymentIdsLength(_lenderId);\r\n    }\r\n\r\n    /// @dev Returns PaymentId that is associated with given lender at given index\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _index Index number to query\r\n    function getLenderPaymentId(string calldata _lenderId, uint256 _index) external view returns (string memory) {\r\n        return LenderLib.getPaymentId(_lenderId, _index);\r\n    }\r\n\r\n    /// @dev Returns IPFS URL of given Lender\r\n    /// @param _lenderId LenderId associated with given lender\r\n    function getLenderMetadataURI(string calldata _lenderId) external view returns (string memory) {\r\n        return LenderLib.getMetadataURI(_lenderId);\r\n    }\r\n\r\n    /// @dev Creates a new lender\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _lenderId RoleId associated with lender\r\n    /// @param _userId UserId associated with lender\r\n    /// @param _metaHash IPFS has of lender\r\n    /// @param _country Country code of lender\r\n    /// @param _onBoardTime On-boarding time (Unix timestamp) of lender\r\n    /// @param _wallet Wallet address of lender\r\n    /// @param _status KYB status of lender \r\n    function createLender(\r\n        string calldata _lenderId,\r\n        string calldata _userId,\r\n        string calldata _metaHash,\r\n        string calldata _country,\r\n        uint64 _onBoardTime,\r\n        address _wallet,\r\n        LenderLib.KYBStatus _status\r\n    ) external {\r\n        LenderLib.Lender memory lender = LenderLib.createLender(_lenderId, _userId, _metaHash, _country, _onBoardTime, _wallet, _status);\r\n        emit CreateLenderEvent(lender);\r\n    }\r\n\r\n    /// @dev Deletes existing lender\r\n    /// @notice Restricted access function, should be called by an address with delete manager role\r\n    /// @param _lenderId LenderId to delete\r\n    function deleteLender(string calldata _lenderId) external {\r\n        LenderLib.removeLender(_lenderId);\r\n        emit DeleteLenderEvent(_lenderId);\r\n    }\r\n\r\n    /// @dev Updates IPFS hash of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _hash New IPFS hash to set \r\n    function updateLenderHash(string calldata _lenderId, string calldata _hash) external {\r\n        string memory _prevHash = LenderLib.getLenderMetaHash(_lenderId);\r\n        LenderLib.updateLenderHash(_lenderId, _hash);\r\n        emit UpdateLenderHashEvent(_lenderId, _prevHash, _hash);\r\n    }\r\n\r\n    /// @dev Updates country of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _country New country to set\r\n    function updateLenderCountry(string calldata _lenderId, string calldata _country) external {\r\n        string memory _prevCountry = LenderLib.getLenderCountry(_lenderId);\r\n        LenderLib.updateLenderCountry(_lenderId, _country);\r\n        emit UpdateLenderCountryEvent(_lenderId, _prevCountry, _country);\r\n    }\r\n\r\n    /// @dev Updates on-boarding time (Unix timestamp) of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _onBoardTime New on-board time (Unix timestamp) to set\r\n    function updateLenderOnBoardTime(string calldata _lenderId, uint64 _onBoardTime) external {\r\n        uint64 _prevTime = LenderLib.getLenderOnBoardTime(_lenderId);\r\n        LenderLib.updateLenderOnBoardTime(_lenderId, _onBoardTime);\r\n        emit UpdateLenderOnBoardTimeEvent(_lenderId, _prevTime, _onBoardTime);\r\n    }\r\n\r\n    /// @dev Updates wallet address of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _wallet New wallet address to set\r\n    function updateLenderWallet(string calldata _lenderId, address _wallet) external {\r\n        address _prevWallet = LenderLib.getLenderWallet(_lenderId);\r\n        LenderLib.updateLenderWallet(_lenderId, _wallet);\r\n        emit UpdateLenderWalletEvent(_lenderId, _prevWallet, _wallet);\r\n    }\r\n\r\n    /// @dev Updates KYB status of given lender\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _status KYB status to set  \r\n    function updateLenderKYB(string calldata _lenderId, LenderLib.KYBStatus _status) external {\r\n        LenderLib.KYBStatus _prevStatus = LenderLib.getLenderKYBStatus(_lenderId);\r\n        LenderLib.updateLenderKYB(_lenderId, _status);\r\n        emit UpdateLenderKYBEvent(_lenderId, _prevStatus, _status);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given lender\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _paymentId PaymentId to remove\r\n    function removeLenderPaymentId(string calldata _lenderId, string calldata _paymentId) external {\r\n        LenderLib.removePaymentId(_lenderId, _paymentId);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given lender based on given index\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _lenderId LenderId associated with given lender\r\n    /// @param _paymentIndex Index of PaymentId to remove\r\n    function removeLenderPaymentIdByIndex(string calldata _lenderId, uint256 _paymentIndex) external {\r\n        LenderLib.removePaymentIdByIndex(_lenderId, _paymentIndex);\r\n    }\r\n}"
      },
      "contracts/facets/MetadataFacet.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\n\r\n/// @title Metadata Library\r\nlibrary MetadataLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.metadata.storage\");\r\n\r\n    struct MetadataState {\r\n        string baseURI;\r\n    }\r\n\r\n    /// @dev Returns storage position of metadata library inside diamond\r\n    function diamondStorage() internal pure returns (MetadataState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns base URI which is used to construct IPFS URL of given hash\r\n    function getBaseURI() internal view returns (string memory) {\r\n        MetadataState storage metadataState = diamondStorage();\r\n        return metadataState.baseURI;\r\n    }\r\n\r\n    /// @dev Updates base URI which is used to construct IPFS URL of given hash\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _baseURI New base URI to set\r\n    function updateBaseURI(string calldata _baseURI) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        MetadataState storage metadataState = diamondStorage();\r\n        metadataState.baseURI = _baseURI;\r\n    }    \r\n}\r\n\r\n/// @title Metadata Facet\r\ncontract MetadataFacet {\r\n    event UpdateBaseURI(string prevBaseURI, string newBaseURI);\r\n\r\n    /// @dev Returns base URI which is used to construct IPFS URL of given hash\r\n    function getBaseURI() external view returns (string memory) {\r\n        return MetadataLib.getBaseURI();\r\n    }\r\n\r\n    /// @dev Updates base URI which is used to construct IPFS URL of given hash\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _baseURI New base URI to set\r\n    function updateBaseURI(string calldata _baseURI) external {\r\n        string memory _prevBaseURI = MetadataLib.getBaseURI();\r\n        MetadataLib.updateBaseURI(_baseURI);\r\n        emit UpdateBaseURI(_prevBaseURI, _baseURI);\r\n    }\r\n}"
      },
      "contracts/facets/PaymentFacet.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {VaultLib} from \"./VaultFacet.sol\";\r\nimport {Strings} from \"@openzeppelin/contracts/utils/Strings.sol\";\r\n\r\n/// @title Payment Library\r\nlibrary PaymentLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.payment.storage\");\r\n\r\n    struct PaymentState {\r\n        mapping(string => Payment) payments;\r\n        uint256 paymentId;\r\n    }\r\n\r\n    struct Payment {\r\n        string roleId;\r\n        string creditPoolId;\r\n        PaymentType paymentType;\r\n        uint64 timeStamp;\r\n        address from;\r\n        address to;\r\n        uint256 amount;\r\n    }\r\n\r\n    enum PaymentType {\r\n        INVESTMENT,\r\n        PANDC,\r\n        DEPOSIT,\r\n        WITHDRAW,\r\n        FEE,\r\n        EXIT,\r\n        PRINCIPAL,\r\n        COUPON,\r\n        PASTDUE\r\n    }\r\n\r\n    event PaymentEvent(PaymentLib.Payment payment);\r\n\r\n    /// @dev Returns storage position of payment library inside diamond\r\n    function diamondStorage() internal pure returns (PaymentState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns payment information of given payment\r\n    /// @param _paymentId PaymentId of given payment\r\n    function getPayment(string calldata _paymentId) internal view returns (Payment memory) {\r\n        PaymentState storage paymentState = diamondStorage();\r\n        return paymentState.payments[_paymentId];\r\n    }\r\n\r\n    /// @dev Returns last PaymentId recorded in payment library\r\n    function getLastPaymentId() internal view returns (uint256) {\r\n        PaymentState storage paymentState = diamondStorage();\r\n        return paymentState.paymentId;\r\n    }\r\n\r\n    /// @dev Adds payment information\r\n    /// @notice Called internally whenever new payment has been recorded by vault\r\n    /// @param _roleId LenderId / PoolManagerId\r\n    /// @param _creditPoolId PoolId associated with credit pool\r\n    /// @param _type Type of payment\r\n    /// @param _from Address from which payment has been made\r\n    /// @param _to Address to which payment has been made\r\n    /// @param _amount Paid amount\r\n    function addPayment(\r\n        string memory _roleId,\r\n        string memory _creditPoolId,\r\n        PaymentType _type,\r\n        address _from,\r\n        address _to,\r\n        uint256 _amount\r\n    ) internal returns (string memory) {\r\n        VaultLib.enforceIsVault();\r\n        PaymentState storage paymentState = diamondStorage();\r\n        paymentState.paymentId++;\r\n        string memory _paymentId = Strings.toString(paymentState.paymentId);\r\n        paymentState.payments[_paymentId] = Payment(_roleId, _creditPoolId, _type, uint64(block.timestamp), _from, _to, _amount);\r\n        emit PaymentEvent(paymentState.payments[_paymentId]);\r\n        return _paymentId;\r\n    }\r\n}\r\n\r\n/// @title Payment Facet\r\ncontract PaymentFacet {\r\n    /// @dev Returns payment information of given payment\r\n    /// @param _paymentId PaymentId of given payment\r\n    function getPayment(string calldata _paymentId) external view returns (PaymentLib.Payment memory) {\r\n        return PaymentLib.getPayment(_paymentId);\r\n    }\r\n\r\n    /// @dev Returns last PaymentId recorded in payment library\r\n    function getLastPaymentId() external view returns (uint256) {\r\n        return PaymentLib.getLastPaymentId();\r\n    }\r\n}\r\n"
      },
      "contracts/facets/PoolManagerFacet.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {CreditPoolLib} from \"./CreditPoolFacet.sol\";\r\nimport {VaultLib} from \"./VaultFacet.sol\";\r\nimport {MetadataLib} from \"./MetadataFacet.sol\";\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\n\r\nerror NotPoolManager(address _user, address _poolManager);\r\nerror PoolManagerIdExist(string _id);\r\nerror PoolIdsExist(uint256 _length);\r\nerror NotVerifiedPoolManager(string _id);\r\nerror InvalidPoolManagerId(string _id);\r\n\r\n// @title Pool Manager Library\r\nlibrary PoolManagerLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.poolmanager.storage\");\r\n\r\n    struct PoolManagerState {\r\n        mapping(string => PoolManager) poolManagers;\r\n    }\r\n\r\n    struct PoolManager {\r\n        string poolManagerId;\r\n        string userId;\r\n        string metaHash;\r\n        string country;\r\n        uint64 onBoardTime;\r\n        address wallet;\r\n        KYBStatus status;\r\n        string[] poolIds;\r\n        string[] paymentIds;\r\n    }\r\n\r\n    enum KYBStatus {PENDING, VERIFIED, REJECTED}\r\n\r\n    /// @dev Returns storage position of pool manager library inside diamond\r\n    function diamondStorage() internal pure returns (PoolManagerState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns on-chain attributes of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManager(string calldata _poolManagerId) internal view returns (PoolManager memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId];\r\n    }\r\n\r\n    /// @dev Returns userId of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerUserId(string calldata _poolManagerId) internal view returns (string memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].userId;\r\n    }\r\n\r\n    /// @dev Returns IPFS hash of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerMetaHash(string calldata _poolManagerId) internal view returns (string memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].metaHash;\r\n    }\r\n\r\n    /// @dev Returns country of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerCountry(string calldata _poolManagerId) internal view returns (string memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].country;\r\n    }\r\n\r\n    /// @dev Returns onboarding time (Unix timestamp) of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerOnBoardTime(string calldata _poolManagerId) internal view returns (uint64) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].onBoardTime;\r\n    }\r\n\r\n    /// @dev Returns wallet address of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerWallet(string calldata _poolManagerId) internal view returns (address) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].wallet;\r\n    }\r\n\r\n    /// @dev Returns KYB status of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerKYBStatus(string calldata _poolManagerId) internal view returns (KYBStatus) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].status;\r\n    }\r\n\r\n    /// @dev Returns number of pools associated with given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolIdsLength(string calldata _poolManagerId) internal view returns (uint256) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].poolIds.length;\r\n    }\r\n\r\n    /// @dev Returns PoolId associated with given pool manager at given index\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _index Index number to query\r\n    function getPoolId(string calldata _poolManagerId, uint256 _index) internal view returns (string memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].poolIds[_index];\r\n    }\r\n\r\n    /// @dev Returns all PoolIds associated with given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolIds(string calldata _poolManagerId) internal view returns (string[] memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].poolIds;\r\n    }\r\n\r\n    /// @dev Returns number of payments associated with given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPaymentIdsLength(string calldata _poolManagerId) internal view returns (uint256) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].paymentIds.length;\r\n    }\r\n\r\n    /// @dev Returns PaymentId that is associated with given pool manager at given index\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _index Index number to query\r\n    function getPaymentId(string calldata _poolManagerId, uint256 _index) internal view returns (string memory) {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        return poolManagerState.poolManagers[_poolManagerId].paymentIds[_index];\r\n    }\r\n\r\n    /// @dev Returns IPFS URL of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getMetadataURI(string calldata _poolManagerId) internal view returns (string memory) {\r\n        enforceIsPoolManagerIdExist(_poolManagerId);\r\n        string memory _baseURI = MetadataLib.getBaseURI();\r\n        string memory _metaHash = getPoolManagerMetaHash(_poolManagerId);\r\n        return bytes(_baseURI).length > 0 ? string(string.concat(bytes(_baseURI), bytes(_metaHash))) : \"\";\r\n    }\r\n\r\n    /// @dev Creates a new pool manager\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _poolManagerId RoleId associated with pool manager\r\n    /// @param _userId UserId associated with pool manager\r\n    /// @param _metaHash IPFS has of pool manager\r\n    /// @param _country Country code of pool manager\r\n    /// @param _onBoardTime On-boarding time (Unix timestamp) of pool manager\r\n    /// @param _wallet Wallet address of pool manager\r\n    /// @param _status KYB status of pool manager\r\n    function createPoolManager(\r\n        string calldata _poolManagerId,\r\n        string calldata _userId,\r\n        string calldata _metaHash,\r\n        string calldata _country,\r\n        uint64 _onBoardTime,\r\n        address _wallet,\r\n        KYBStatus _status\r\n    ) internal returns (PoolManager memory) {\r\n        AccessControlLib.enforceIsCreateManager();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        if(keccak256(bytes(_poolManagerId)) == keccak256(bytes(poolManagerState.poolManagers[_poolManagerId].poolManagerId))) {\r\n            revert PoolManagerIdExist(_poolManagerId);\r\n        }\r\n        poolManagerState.poolManagers[_poolManagerId] = PoolManager(_poolManagerId, _userId, _metaHash, _country, _onBoardTime, _wallet, _status, new string[](0), new string[](0));\r\n        return poolManagerState.poolManagers[_poolManagerId];\r\n    }\r\n\r\n    /// @dev Deletes existing pool manager\r\n    /// @notice Restricted access function, should be called by an address with delete manager role\r\n    /// @param _poolManagerId PoolManagerId to delete\r\n    function removePoolManager(string calldata _poolManagerId) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        if(poolManagerState.poolManagers[_poolManagerId].poolIds.length != 0) {\r\n            revert PoolIdsExist(poolManagerState.poolManagers[_poolManagerId].poolIds.length);\r\n        }\r\n        delete poolManagerState.poolManagers[_poolManagerId];\r\n    }\r\n\r\n    /// @dev Updates IPFS hash of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _hash New IPFS hash to set \r\n    function updatePoolManagerHash(string calldata _poolManagerId, string calldata _hash) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsPoolManagerIdExist(_poolManagerId);\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        poolManagerState.poolManagers[_poolManagerId].metaHash = _hash;\r\n    }\r\n\r\n    /// @dev Updates country of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _country New country to set\r\n    function updatePoolManagerCountry(string calldata _poolManagerId, string calldata _country) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsPoolManagerIdExist(_poolManagerId);\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        poolManagerState.poolManagers[_poolManagerId].country = _country;\r\n    }\r\n\r\n    /// @dev Updates on-boarding time (Unix timestamp) of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _onBoardTime New on-board time (Unix timestamp) to set\r\n    function updatePoolManagerOnBoardTime(string calldata _poolManagerId, uint64 _onBoardTime) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsPoolManagerIdExist(_poolManagerId);\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        poolManagerState.poolManagers[_poolManagerId].onBoardTime = _onBoardTime;\r\n    }\r\n    \r\n    /// @dev Updates wallet address of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _wallet New wallet address to set\r\n    function updatePoolManagerWallet(string calldata _poolManagerId, address _wallet) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsPoolManagerIdExist(_poolManagerId);\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        poolManagerState.poolManagers[_poolManagerId].wallet = _wallet;\r\n    }\r\n\r\n    /// @dev Updates KYB status of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _status KYB status to set  \r\n    function updatePoolManagerKYB(string calldata _poolManagerId, KYBStatus _status) internal {\r\n        AccessControlLib.enforceIsEditManager();\r\n        enforceIsPoolManagerIdExist(_poolManagerId);\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        poolManagerState.poolManagers[_poolManagerId].status = _status;\r\n    }\r\n\r\n    /// @dev Adds PoolId to given pool manager's pool list\r\n    /// @notice Called internally whenever pool manager creates a new pool\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _poolId PoolId associated with credit pool that is created\r\n    function addPoolId(string calldata _poolManagerId, string calldata _poolId) internal {\r\n        CreditPoolLib.enforceIsCreditPool();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        PoolManager storage poolManager = poolManagerState.poolManagers[_poolManagerId];\r\n        poolManager.poolIds.push(_poolId);\r\n    }\r\n\r\n    /// @dev Removes PoolId from given pool manager's pool list based on given index\r\n    /// @notice Called internally whenever delete manager removes a pool \r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _poolIndex Index of pool to remove from pool manager's pool list\r\n    function removePoolIdByIndex(string memory _poolManagerId, uint256 _poolIndex) internal {\r\n        CreditPoolLib.enforceIsCreditPool();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        PoolManager storage poolManager = poolManagerState.poolManagers[_poolManagerId];\r\n        if(_poolIndex != poolManager.poolIds.length - 1) {\r\n            poolManager.poolIds[_poolIndex] = poolManager.poolIds[poolManager.poolIds.length - 1];\r\n            string memory _poolId = poolManager.poolIds[_poolIndex];\r\n            CreditPoolLib.updateBindingIndexOfPool(_poolId, _poolIndex);\r\n        }\r\n        poolManager.poolIds.pop();\r\n    }\r\n    \r\n    /// @dev Adds PaymentId associated with given pool manager\r\n    /// @notice Called internally whenever a new payment registered that is associated with given pool manager \r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _paymentId PaymentId associated with a new payment\r\n    function addPaymentId(string memory _poolManagerId, string memory _paymentId) internal {\r\n        VaultLib.enforceIsVault();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        PoolManager storage poolManager = poolManagerState.poolManagers[_poolManagerId];\r\n        poolManager.paymentIds.push(_paymentId);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given pool manager\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _paymentId PaymentId to remove\r\n    function removePaymentId(string calldata _poolManagerId, string calldata _paymentId) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        PoolManager storage poolManager = poolManagerState.poolManagers[_poolManagerId];\r\n        uint256 index;\r\n        for (uint256 i = 0; i < poolManager.paymentIds.length; i++) {\r\n            if (keccak256(bytes(poolManager.paymentIds[i])) == keccak256(bytes(_paymentId))) {\r\n                index = i;\r\n                break;\r\n            }\r\n        }\r\n        poolManager.paymentIds[index] = poolManager.paymentIds[poolManager.paymentIds.length - 1];\r\n        poolManager.paymentIds.pop();\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given pool manager based on given index\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _paymentIndex Index of PaymentId to remove\r\n    function removePaymentIdByIndex(string calldata _poolManagerId, uint256 _paymentIndex) internal {\r\n        AccessControlLib.enforceIsDeleteManager();\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        PoolManager storage poolManager = poolManagerState.poolManagers[_poolManagerId];\r\n        if(_paymentIndex != poolManager.paymentIds.length - 1) {\r\n            poolManager.paymentIds[_paymentIndex] = poolManager.paymentIds[poolManager.paymentIds.length - 1];\r\n        }\r\n        poolManager.paymentIds.pop();\r\n    }\r\n\r\n    /// @dev Throws error if called by other than pool manager\r\n    function enforceIsPoolManager(string calldata _poolManagerId) internal view {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        if(msg.sender != poolManagerState.poolManagers[_poolManagerId].wallet) {\r\n            revert NotPoolManager(msg.sender, poolManagerState.poolManagers[_poolManagerId].wallet);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if pool manager is not KYB verified\r\n    function enforceIsPoolManagerKYBVerified(string memory _poolManagerId) internal view {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        if(poolManagerState.poolManagers[_poolManagerId].status != KYBStatus.VERIFIED) {\r\n            revert NotVerifiedPoolManager(_poolManagerId);\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if pool manager id not exist\r\n    function enforceIsPoolManagerIdExist(string calldata _poolManagerId) internal view {\r\n        PoolManagerState storage poolManagerState = diamondStorage();\r\n        if(bytes(poolManagerState.poolManagers[_poolManagerId].poolManagerId).length == 0) {\r\n            revert InvalidPoolManagerId(_poolManagerId);\r\n        }\r\n    }\r\n\r\n}\r\n\r\n/// @title Pool Manager Facet\r\ncontract PoolManagerFacet {\r\n    event DeletePoolManagerEvent(string indexed poolManagerId);\r\n    event CreatePoolManagerEvent(PoolManagerLib.PoolManager poolManager);\r\n    event UpdatePoolManagerHashEvent(string indexed poolManagerId, string prevHash, string newHash);\r\n    event UpdatePoolManagerCountryEvent(string indexed poolManagerId, string prevCountry, string newCountry);\r\n    event UpdatePoolManagerOnBoardTimeEvent(string indexed poolManagerId, uint64 prevTime, uint64 newTime);\r\n    event UpdatePoolManagerWalletEvent(string indexed poolManagerId, address prevWallet, address newWallet);\r\n    event UpdatePoolManagerKYBEvent(string indexed poolManagerId, PoolManagerLib.KYBStatus prevStatus, PoolManagerLib.KYBStatus newStatus);\r\n    \r\n    /// @dev Returns on-chain attributes of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManager(string calldata _poolManagerId) external view returns (PoolManagerLib.PoolManager memory) {\r\n        return PoolManagerLib.getPoolManager(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns userId of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerUserId(string calldata _poolManagerId) external view returns (string memory) {\r\n        return PoolManagerLib.getPoolManagerUserId(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns IPFS hash of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerMetaHash(string calldata _poolManagerId) external view returns (string memory) {\r\n        return PoolManagerLib.getPoolManagerMetaHash(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns country of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerCountry(string calldata _poolManagerId) external view returns (string memory) {\r\n        return PoolManagerLib.getPoolManagerCountry(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns onboarding time (Unix timestamp) of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerOnBoardTime(string calldata _poolManagerId) external view returns (uint64) {\r\n        return PoolManagerLib.getPoolManagerOnBoardTime(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns wallet address of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerWallet(string calldata _poolManagerId) external view returns (address) {\r\n        return PoolManagerLib.getPoolManagerWallet(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns KYB status of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerKYBStatus(string calldata _poolManagerId) external view returns (PoolManagerLib.KYBStatus) {\r\n        return PoolManagerLib.getPoolManagerKYBStatus(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns number of pools associated with given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerPoolIdsLength(string calldata _poolManagerId) external view returns (uint256) {\r\n        return PoolManagerLib.getPoolIdsLength(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns PoolId associated with given pool manager at given index\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _index Index number to query\r\n    function getPoolManagerPoolId(string calldata _poolManagerId, uint256 _index) external view returns (string memory) {\r\n        return PoolManagerLib.getPoolId(_poolManagerId, _index);\r\n    }\r\n\r\n    /// @dev Returns all PoolIds associated with given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerPoolIds(string calldata _poolManagerId) external view returns (string[] memory) {\r\n        return PoolManagerLib.getPoolIds(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns number of payments associated with given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerPaymentIdsLength(string calldata _poolManagerId) external view returns (uint256) {\r\n        return PoolManagerLib.getPaymentIdsLength(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Returns PaymentId that is associated with given pool manager at given index\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _index Index number to query\r\n    function getPoolManagerPaymentId(string calldata _poolManagerId, uint256 _index) external view returns (string memory) {\r\n        return PoolManagerLib.getPaymentId(_poolManagerId, _index);\r\n    }\r\n\r\n    /// @dev Returns IPFS URL of given pool manager\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    function getPoolManagerMetadataURI(string calldata _poolManagerId) external view returns (string memory) {\r\n        return PoolManagerLib.getMetadataURI(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Creates a new pool manager\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _poolManagerId RoleId associated with pool manager\r\n    /// @param _userId UserId associated with pool manager\r\n    /// @param _metaHash IPFS has of pool manager\r\n    /// @param _country Country code of pool manager\r\n    /// @param _onBoardTime On-boarding time (Unix timestamp) of pool manager\r\n    /// @param _wallet Wallet address of pool manager\r\n    /// @param _status KYB status of pool manager\r\n    function createPoolManager(\r\n        string calldata _poolManagerId,\r\n        string calldata _userId,\r\n        string calldata _metaHash,\r\n        string calldata _country,\r\n        uint64 _onBoardTime,\r\n        address _wallet,\r\n        PoolManagerLib.KYBStatus _status\r\n    ) external {\r\n        PoolManagerLib.PoolManager memory poolManager = PoolManagerLib.createPoolManager(_poolManagerId, _userId, _metaHash, _country, _onBoardTime, _wallet, _status);\r\n        emit CreatePoolManagerEvent(poolManager);\r\n    }\r\n\r\n    /// @dev Deletes existing pool manager\r\n    /// @notice Restricted access function, should be called by an address with delete manager role\r\n    /// @param _poolManagerId PoolManagerId to delete\r\n    function deletePoolManager(string calldata _poolManagerId) external {\r\n        PoolManagerLib.removePoolManager(_poolManagerId);\r\n        emit DeletePoolManagerEvent(_poolManagerId);\r\n    }\r\n\r\n    /// @dev Updates IPFS hash of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _hash New IPFS hash to set \r\n    function updatePoolManagerHash(string calldata _poolManagerId, string calldata _hash) external {\r\n        string memory _prevHash = PoolManagerLib.getPoolManagerMetaHash(_poolManagerId);\r\n        PoolManagerLib.updatePoolManagerHash(_poolManagerId, _hash);\r\n        emit UpdatePoolManagerHashEvent(_poolManagerId, _prevHash, _hash);\r\n    }\r\n\r\n    /// @dev Updates country of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _country New country to set\r\n    function updatePoolManagerCountry(string calldata _poolManagerId, string calldata _country) external {\r\n        string memory _prevCountry = PoolManagerLib.getPoolManagerCountry(_poolManagerId);\r\n        PoolManagerLib.updatePoolManagerCountry(_poolManagerId, _country);\r\n        emit UpdatePoolManagerCountryEvent(_poolManagerId, _prevCountry, _country);\r\n    }\r\n\r\n    /// @dev Updates on-boarding time (Unix timestamp) of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _onBoardTime New on-board time (Unix timestamp) to set\r\n    function updatePoolManagerOnBoardTime(string calldata _poolManagerId, uint64 _onBoardTime) external {\r\n        uint64 _prevTime = PoolManagerLib.getPoolManagerOnBoardTime(_poolManagerId);\r\n        PoolManagerLib.updatePoolManagerOnBoardTime(_poolManagerId, _onBoardTime);\r\n        emit UpdatePoolManagerOnBoardTimeEvent(_poolManagerId, _prevTime, _onBoardTime);\r\n    }\r\n\r\n    /// @dev Updates wallet address of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _wallet New wallet address to set\r\n    function updatePoolManagerWallet(string calldata _poolManagerId, address _wallet) external {\r\n        address _prevWallet = PoolManagerLib.getPoolManagerWallet(_poolManagerId);\r\n        PoolManagerLib.updatePoolManagerWallet(_poolManagerId, _wallet);\r\n        emit UpdatePoolManagerWalletEvent(_poolManagerId, _prevWallet, _wallet);\r\n    }\r\n\r\n    /// @dev Updates KYB status of given pool manager\r\n    /// @notice Restricted access function, should be called by an address with edit manager role\r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _status KYB status to set  \r\n    function updatePoolManagerKYB(string calldata _poolManagerId, PoolManagerLib.KYBStatus _status) external {\r\n        PoolManagerLib.KYBStatus _prevStatus = PoolManagerLib.getPoolManagerKYBStatus(_poolManagerId);\r\n        PoolManagerLib.updatePoolManagerKYB(_poolManagerId, _status);\r\n        emit UpdatePoolManagerKYBEvent(_poolManagerId, _prevStatus, _status);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given pool manager\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _paymentId PaymentId to remove\r\n    function removePoolManagerPaymentId(string calldata _poolManagerId, string calldata _paymentId) external {\r\n        PoolManagerLib.removePaymentId(_poolManagerId, _paymentId);\r\n    }\r\n\r\n    /// @dev Removes PaymentId associated with given pool manager based on given index\r\n    /// @notice Restricted access function, should be called by an address with delete manager role \r\n    /// @param _poolManagerId PoolManagerId associated with given pool manager\r\n    /// @param _paymentIndex Index of PaymentId to remove\r\n    function removePoolManagerPaymentIdByIndex(string calldata _poolManagerId, uint256 _paymentIndex) external {\r\n        PoolManagerLib.removePaymentIdByIndex(_poolManagerId, _paymentIndex);\r\n    }\r\n}"
      },
      "contracts/facets/StableCoinExtension.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\nimport {CreditPoolLib} from \"./CreditPoolFacet.sol\";\r\nimport {VaultLib} from \"./VaultFacet.sol\";\r\nimport {LenderLib} from \"./LenderFacet.sol\";\r\nimport {PaymentLib} from \"./PaymentFacet.sol\";\r\n\r\nerror PoolTokenInitializedBefore(string poolId);\r\nerror InvalidToken(address poolToken);\r\nerror EnforcedPause();\r\nerror InvalidAmount(uint256 amount);\r\n\r\n/// @title Stable Coin Library\r\nlibrary StableCoinLib {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.stablecoin.storage\");\r\n\r\n    struct StableCoinState {\r\n        mapping (string => address) poolToken;\r\n        mapping (address => bool) isWhitelisted;\r\n        mapping (string => mapping (address => uint256)) stableCoinBalance;\r\n        mapping (string => address) requestedToken;\r\n        mapping (string => address) paymentStableCoin;\r\n        mapping (string => uint256) paidBalance;\r\n        mapping (string => uint64) lastWithdrawalTimeStamp;\r\n        uint64 lenderThreshold;\r\n        uint64 poolThreshold;\r\n        uint64 lenderCoolingTime;\r\n        uint64 poolCoolingTime;\r\n    }\r\n\r\n    /// @dev Returns storage position of stable coin library inside diamond\r\n    function diamondStorage() internal pure returns (StableCoinState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns address of stable coin associated with given credit pool\r\n    /// @param _poolId PoolId of given credit pool \r\n    function getPoolToken(string memory _poolId) internal view returns (address) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.poolToken[_poolId];\r\n    }\r\n\r\n    /// @dev Returns whitelisting status of given stable coin\r\n    /// @param _token Address of given stable coin\r\n    function isWhitelistedToken(address _token) internal view returns (bool) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.isWhitelisted[_token];\r\n    }\r\n\r\n    /// @dev Returns stable coin balance of given vault account\r\n    /// @param _roleId RoleId associated with given vault account\r\n    /// @param _token Address of stable coin\r\n    function getStableCoinBalance(string calldata _roleId, address _token) internal view returns (uint256) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.stableCoinBalance[_roleId][_token];\r\n    }\r\n\r\n    /// @dev Returns address of stable coin requested to be withdrawn by given roleId\r\n    /// @param _roleId RoleId associated with given vault account \r\n    function getRequestedToken(string memory _roleId) internal view returns (address) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.requestedToken[_roleId];\r\n    }\r\n\r\n    /// @dev Returns address of stable coin associated with given payment\r\n    /// @param _paymentId PaymentId of given payment\r\n    function getPaymentStableCoin(string memory _paymentId) internal view returns (address) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.paymentStableCoin[_paymentId];\r\n    }\r\n\r\n    /// @dev Returns threshold amount for lender auto withdrawal\r\n    function getLenderThreshold() internal view returns (uint64) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.lenderThreshold;\r\n    }\r\n    \r\n    /// @dev Returns threshold amount for investment auto withdrawal\r\n    function getPoolThreshold() internal view returns (uint64) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.poolThreshold;\r\n    }\r\n\r\n    /// @dev Returns cooling time in seconds for lender auto withdrawal\r\n    function getLenderCoolingTime() internal view returns (uint64) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.lenderCoolingTime;\r\n    }\r\n\r\n    /// @dev Returns cooling time in seconds for investment auto withdrawal\r\n    function getPoolCoolingTime() internal view returns (uint64) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.poolCoolingTime;\r\n    }\r\n\r\n    /// @dev Returns undistributed amount of given pool\r\n    /// @param _roleId PoolId of given credit pool\r\n    function getPaidBalance(string calldata _roleId) internal view returns (uint256) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.paidBalance[_roleId];\r\n    }\r\n\r\n    /// @dev Returns timestamp of last withdrawal\r\n    /// @param _roleId RoleId / PoolId of given lender / credit pool\r\n    function getLastWithdrawalTimeStamp(string calldata _roleId) internal view returns (uint64) {\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        return stableCoinState.lastWithdrawalTimeStamp[_roleId];\r\n    }\r\n\r\n    /// @dev Initializes stable coin information of given pool\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _poolId PoolId of given credit pool\r\n    /// @param _poolToken Address of stable coin associated with given credit pool\r\n    function initializePoolToken(string calldata _poolId, address _poolToken) internal {\r\n        AccessControlLib.enforceIsCreateManager();\r\n        CreditPoolLib.enforceIsCreditPoolIdExist(_poolId);\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        if(!stableCoinState.isWhitelisted[_poolToken]) {\r\n            revert InvalidToken(_poolToken);\r\n        }\r\n        if(stableCoinState.poolToken[_poolId] == address(0)) {\r\n            stableCoinState.poolToken[_poolId] = _poolToken;\r\n        }\r\n    }\r\n\r\n    /// @dev Removes stable coin information of given pool\r\n    /// @notice Called internally whenever pool has been deleted\r\n    /// @param _poolId PoolId of given credit pool\r\n    function deletePoolToken(string calldata _poolId) internal {\r\n        CreditPoolLib.enforceIsCreditPool();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        delete stableCoinState.poolToken[_poolId];\r\n    }\r\n\r\n    /// @dev Adds / Removes stable coin to/from whitelist\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _token Address of stable coin\r\n    function updateWhitelist(address _token) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.isWhitelisted[_token] = !stableCoinState.isWhitelisted[_token];\r\n    }\r\n\r\n    /// @dev Updates threshold amount for lender auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _threshold New threshold amount to set\r\n    function updateLenderThreshold(uint64 _threshold) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.lenderThreshold = _threshold;\r\n    }\r\n\r\n    /// @dev Updates threshold amount for investment auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _threshold New threshold amount to set\r\n    function updatePoolThreshold(uint64 _threshold) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.poolThreshold = _threshold;\r\n    }\r\n\r\n    /// @dev Updates cooling time in seconds for lender auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _time New cooling time in seconds\r\n    function updateLenderCoolingTime(uint64 _time) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.lenderCoolingTime = _time;\r\n    }\r\n\r\n    /// @dev Updates cooling time in seconds for investment auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _time New cooling time in seconds\r\n    function updatePoolCoolingTime(uint64 _time) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.poolCoolingTime = _time;\r\n    }\r\n\r\n    /// @dev Increases stable coin balance of given lender\r\n    /// @notice Called internally whenever stable coin balance of given lender gets increased\r\n    /// @param _roleId LenderId of given lender\r\n    /// @param _token Address of stable coin\r\n    /// @param _amount Amount of stable coin to be added into lender stable coin balance\r\n    function increaseBalance(string memory _roleId, address _token, uint256 _amount) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.stableCoinBalance[_roleId][_token] += _amount;\r\n    }\r\n\r\n    /// @dev Decreases stable coin balance of given lender\r\n    /// @notice Called internally whenever stable coin balance of given lender gets decreased\r\n    /// @param _roleId LenderId of given lender\r\n    /// @param _token Address of stable coin\r\n    /// @param _amount Amount of stable coin to be subtracted from lender stable coin balance\r\n    function decreaseBalance(string memory _roleId, address _token, uint256 _amount) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.stableCoinBalance[_roleId][_token] -= _amount;\r\n    }\r\n\r\n    /// @dev Increases paid balance of given pool\r\n    /// @notice Called internally whenever paid balance of given pool gets increased\r\n    /// @param _roleId PoolId of given credit pool\r\n    /// @param _amount Amount of stable coin to be added into pool paid balance\r\n    function increasePaidBalance(string memory _roleId, uint256 _amount) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.paidBalance[_roleId] += _amount;\r\n    }\r\n\r\n    /// @dev Decreases paid balance of given pool\r\n    /// @notice Called internally whenever paid balance of given pool gets decreased\r\n    /// @param _roleId PoolId of given credit pool\r\n    /// @param _amount Amount of stable coin to be subtracted from pool paid balance\r\n    function decreasePaidBalance(string memory _roleId, uint256 _amount) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.paidBalance[_roleId] -= _amount;\r\n    }\r\n\r\n    /// @dev Updates last withdrawal time of given lender / pool\r\n    /// @notice Called internally whenever lender / pool withdrawal processed automatically\r\n    /// @param _roleId LenderId / PoolId of given lender / credit pool\r\n    /// @param _timeStamp Timestamp of last withdrawal\r\n    function updateLastWithdrawalTimeStamp(string memory _roleId, uint64 _timeStamp) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.lastWithdrawalTimeStamp[_roleId] = _timeStamp;\r\n    }\r\n\r\n    /// @dev Binds requested stable coin information with given roleId\r\n    /// @notice Called internally whenever given wallet requests to withdraw stable coin\r\n    /// @param _roleId LenderId who requested given tokens to be withdrawn from vault\r\n    /// @param _token Address of requested stable coin\r\n    function addRequestedToken(string calldata _roleId, address _token) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.requestedToken[_roleId] = _token;\r\n    }\r\n\r\n    /// @dev Binds stable coin information with given payment\r\n    /// @notice Called internally whenever a direct payment in given stable coin has been initiated\r\n    /// @param _paymentId PaymentId of given payment\r\n    /// @param _token Address of stable coin\r\n    function addPaymentStableCoin(string memory _paymentId, address _token) internal {\r\n        VaultLib.enforceIsVault();\r\n        StableCoinState storage stableCoinState = diamondStorage();\r\n        stableCoinState.paymentStableCoin[_paymentId] = _token;\r\n    }\r\n}\r\n\r\n/// @title Stable Coin Facet\r\ncontract StableCoinExtension {\r\n    event UpdatePoolToken(string indexed poolId, address poolToken);\r\n    event UpdateWhitelist(address indexed token, bool isWhitelisted);\r\n    event UpdateLenderThreshold(uint64 prevThreshold, uint64 newThreshold);\r\n    event UpdatePoolThreshold(uint64 prevThreshold, uint64 newThreshold);\r\n    event UpdateLenderCoolingTime(uint64 prevTime, uint64 newTime);\r\n    event UpdatePoolCoolingTime(uint64 prevTime, uint64 newTime);\r\n    event CreateCreditPoolEvent(CreditPoolLib.CreditPool creditPool);\r\n    event AdjustStableCoin(string indexed roleId, uint256 amount, address token, PaymentLib.PaymentType paymentType);\r\n    event EmergencyWithdraw(address indexed executor, address token, address receiver, uint256 amount);\r\n\r\n    /// @dev Returns address of stable coin associated with given credit pool\r\n    /// @param _poolId PoolId of given credit pool \r\n    function getPoolToken(string calldata _poolId) external view returns (address) {\r\n        return StableCoinLib.getPoolToken(_poolId);\r\n    }\r\n\r\n    /// @dev Returns whitelisting status of given stable coin\r\n    /// @param _token Address of given stable coin\r\n    function isWhitelistedToken(address _token) external view returns (bool) {\r\n        return StableCoinLib.isWhitelistedToken(_token);\r\n    }\r\n\r\n    /// @dev Returns stable coin balance of given vault account\r\n    /// @param _roleId RoleId associated with given vault account\r\n    /// @param _token Address of stable coin\r\n    function getStableCoinBalance(string calldata _roleId, address _token) external view returns (uint256) {\r\n        return StableCoinLib.getStableCoinBalance(_roleId, _token);\r\n    }\r\n\r\n    /// @dev Returns address of stable coin requested to be withdrawn by given roleId\r\n    /// @param _roleId RoleId associated with given vault account \r\n    function getRequestedToken(string memory _roleId) external view returns (address) {\r\n        return StableCoinLib.getRequestedToken(_roleId);\r\n    }\r\n\r\n    /// @dev Returns address of stable coin associated with given payment\r\n    /// @param _paymentId PaymentId of given payment\r\n    function getPaymentStableCoin(string memory _paymentId) external view returns (address) {\r\n        return StableCoinLib.getPaymentStableCoin(_paymentId);\r\n    }\r\n\r\n    /// @dev Returns threshold amount for lender auto withdrawal\r\n    function getLenderThreshold() external view returns (uint64) {\r\n        return StableCoinLib.getLenderThreshold();\r\n    }\r\n    \r\n    /// @dev Returns threshold amount for investment auto withdrawal\r\n    function getPoolThreshold() external view returns (uint64) {\r\n        return StableCoinLib.getPoolThreshold();\r\n    }\r\n\r\n    /// @dev Returns cooling time in seconds for lender auto withdrawal\r\n    function getLenderCoolingTime() external view returns (uint64) {\r\n        return StableCoinLib.getLenderCoolingTime();\r\n    }\r\n\r\n    /// @dev Returns cooling time in seconds for investment auto withdrawal\r\n    function getPoolCoolingTime() external view returns (uint64) {\r\n        return StableCoinLib.getPoolCoolingTime();\r\n    }\r\n\r\n    /// @dev Returns undistributed amount of given pool\r\n    /// @param _roleId PoolId of given credit pool\r\n    function getPaidBalance(string calldata _roleId) external view returns (uint256) {\r\n        return StableCoinLib.getPaidBalance(_roleId);\r\n    }\r\n\r\n    /// @dev Returns timestamp of last withdrawal\r\n    /// @param _roleId RoleId / PoolId of given lender / credit pool\r\n    function getLastWithdrawalTimeStamp(string calldata _roleId) external view returns (uint64) {\r\n        return StableCoinLib.getLastWithdrawalTimeStamp(_roleId);\r\n    }\r\n\r\n    /// @dev Initializes stable coin information of given pool\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _poolId PoolId of given credit pool\r\n    /// @param _poolToken Address of stable coin associated with given credit pool\r\n    function initializePoolToken(string calldata _poolId, address _poolToken) external {\r\n        StableCoinLib.initializePoolToken(_poolId, _poolToken);\r\n        emit UpdatePoolToken(_poolId, _poolToken);\r\n    }\r\n\r\n    /// @dev Adds / Removes stable coin to/from whitelist\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _token Address of stable coin\r\n    function updateWhitelist(address _token) external {\r\n        StableCoinLib.updateWhitelist(_token);\r\n        bool _isWhitelisted = StableCoinLib.isWhitelistedToken(_token);\r\n        emit UpdateWhitelist(_token, _isWhitelisted);\r\n    }\r\n\r\n    /// @dev Updates threshold amount for lender auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _threshold New threshold amount to set\r\n    function updateLenderThreshold(uint64 _threshold) external {\r\n        uint64 _prev = StableCoinLib.getLenderThreshold();\r\n        emit UpdateLenderThreshold(_prev, _threshold);\r\n        StableCoinLib.updateLenderThreshold(_threshold);\r\n    }\r\n\r\n    /// @dev Updates threshold amount for investment auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _threshold New threshold amount to set\r\n    function updatePoolThreshold(uint64 _threshold) external {\r\n        uint64 _prev = StableCoinLib.getPoolThreshold();\r\n        emit UpdatePoolThreshold(_prev, _threshold);\r\n        StableCoinLib.updatePoolThreshold(_threshold);\r\n    }\r\n\r\n    /// @dev Updates cooling time in seconds for lender auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _time New cooling time in seconds\r\n    function updateLenderCoolingTime(uint64 _time) external {\r\n        uint64 _prev = StableCoinLib.getLenderCoolingTime();\r\n        emit UpdateLenderCoolingTime(_prev, _time);\r\n        StableCoinLib.updateLenderCoolingTime(_time);\r\n    }\r\n\r\n    /// @dev Updates cooling time in seconds for investment auto withdrawal\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _time New cooling time in seconds\r\n    function updatePoolCoolingTime(uint64 _time) external {\r\n        uint64 _prev = StableCoinLib.getPoolCoolingTime();\r\n        emit UpdatePoolCoolingTime(_prev, _time);\r\n        StableCoinLib.updatePoolCoolingTime(_time);\r\n    }\r\n\r\n    /// @dev Creates a new credit pool\r\n    /// @notice Restricted access function, should be called by an address with create manager role\r\n    /// @param _creditPoolId Id associated with credit pool\r\n    /// @param _poolManagerId PoolManagerId of manager who owns the pool\r\n    /// @param _metaHash IPFS hash of credit pool\r\n    /// @param _borrowingAmount Pool size\r\n    /// @param _inceptionTime Credit pool inception time (Unix timestamp)\r\n    /// @param _expiryTime Credit pool cut-off time (Unix timestamp)\r\n    /// @param _curingPeriod Curing period of credit pool in seconds\r\n    /// @param _status Status of cresit pool\r\n    /// @param _poolToken Address of stable coin to be used as payment token\r\n    function createCreditPool(\r\n        string calldata _creditPoolId,\r\n        string calldata _poolManagerId,\r\n        string calldata _metaHash,\r\n        uint256 _borrowingAmount,\r\n        uint64 _inceptionTime,\r\n        uint64 _expiryTime,\r\n        uint32 _curingPeriod,\r\n        CreditPoolLib.CreditPoolStatus _status,\r\n        address _poolToken\r\n    ) external {\r\n        CreditPoolLib.CreditPool memory creditPool = CreditPoolLib.createCreditPool(_creditPoolId, _poolManagerId, _metaHash, _borrowingAmount, _inceptionTime, _expiryTime, _curingPeriod, _status);\r\n        emit CreateCreditPoolEvent(creditPool);\r\n        StableCoinLib.initializePoolToken(_creditPoolId, _poolToken);\r\n        emit UpdatePoolToken(_creditPoolId, _poolToken);       \r\n    }\r\n\r\n    /// @dev Adjusts balance of lender account in case of correction\r\n    /// @notice Restricted access function, should be called by an owner only\r\n    /// @param _roleId LenderId of a vault account\r\n    /// @param _amount Amount of payment token to adjust\r\n    /// @param _token Address of stable coin\r\n    /// @param _type Type of adjustment (deposit / withdraw) \r\n    function adjustStableCoinBalance(\r\n        string calldata _roleId,\r\n        uint256 _amount,\r\n        address _token,\r\n        PaymentLib.PaymentType _type\r\n    ) external {\r\n        VaultLib.adjustStableCoinBalance(_roleId, _amount, _token, _type);\r\n        emit AdjustStableCoin(_roleId, _amount, _token, _type);\r\n    }\r\n\r\n    /// @dev Withdraws ERC20 token from contract in case of emergency\r\n    /// @notice Restricted access function, should be called by an owner only\r\n    /// @param _token Address of ERC20 token to withdraw\r\n    /// @param _to Address of receiver\r\n    /// @param _amount Amount of ERC20 token to withdraw from contract \r\n    function emergencyWithdraw(address _token, address _to, uint256 _amount) external {\r\n        VaultLib.emergencyWithdraw(_token, _to, _amount);\r\n        emit EmergencyWithdraw(msg.sender, _token, _to, _amount);\r\n    }\r\n}"
      },
      "contracts/facets/VaultFacet.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\r\n// @author cSigma Finance Inc., a Delaware company, for its Real World Credit tokenization protocol\r\npragma solidity ^0.8.0;\r\n\r\nimport {LibDiamond} from \"../libraries/LibDiamond.sol\";\r\nimport {LenderLib} from \"./LenderFacet.sol\";\r\nimport {CreditPoolLib} from \"./CreditPoolFacet.sol\";\r\nimport {PoolManagerLib} from \"./PoolManagerFacet.sol\";\r\nimport {PaymentLib} from \"./PaymentFacet.sol\";\r\nimport {AccessControlLib} from \"./AccessControlFacet.sol\";\r\nimport {StableCoinLib} from \"./StableCoinExtension.sol\";\r\nimport {DistributeLib} from \"./DistributeExtension.sol\";\r\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\r\nimport {IERC20Metadata} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\r\n\r\nerror NotVaultCall();\r\nerror PaymentTokenIsInitialized(address token);\r\nerror InvalidAmount(uint256 amount);\r\nerror InvalidPaymentType(PaymentLib.PaymentType paymentType);\r\nerror CuringPeriodIsNotOver(string roleId);\r\nerror PendingRequestExist(string roleId);\r\nerror InvalidRequestIndex(uint256 index);\r\nerror EnforcedPause();\r\nerror ExpectedPause();\r\nerror InvalidPoolToken(address poolToken);\r\nerror InvalidFunction();\r\n\r\n/// @title Vault library\r\nlibrary VaultLib {\r\n    using SafeERC20 for IERC20;\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"csigma.vault.storage\");\r\n\r\n    struct VaultState {\r\n        mapping(string => uint256) vaultBalance;\r\n        mapping(string => uint256) borrowedAmount;\r\n        mapping(string => RequestStatus) pendingRequest;\r\n        Request[] requests;\r\n        uint256 minDepositLimit;\r\n        address paymentToken;\r\n        bool isVaultCall;\r\n        bool paused;\r\n    }\r\n\r\n    struct Request {\r\n        string roleId;\r\n        string poolId;\r\n        address wallet;\r\n        RequestType requestType;\r\n        uint256 amount;\r\n    }\r\n\r\n    struct RequestStatus {\r\n        bool isPending;\r\n        uint256 requestIndex;\r\n    }\r\n\r\n    struct PaymentInfo {\r\n        uint256 amount;\r\n        PaymentLib.PaymentType paymentType;\r\n    }\r\n\r\n    enum RequestType {INVESTMENT, WITHDRAW, RECEIVE}\r\n\r\n    enum AccountType {LENDER, POOL}\r\n\r\n    event Exit(string indexed roleId, string poolId, uint256 amount);\r\n    event Fee(string indexed poolId, uint256 amount);\r\n\r\n    modifier whenNotPaused() {\r\n        requireNotPaused();\r\n        _;\r\n    }\r\n\r\n    modifier whenPaused() {\r\n        requirePaused();\r\n        _;\r\n    }\r\n    \r\n    /// @dev Returns storage position of vault library inside diamond\r\n    function diamondStorage() internal pure returns (VaultState storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    /// @dev Returns vault balance of given vault account\r\n    /// @param _roleId RoleId associated with given vault account  \r\n    function getVaultBalance(string calldata _roleId) internal view returns (uint256) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.vaultBalance[_roleId];\r\n    }\r\n\r\n    /// @dev Returns stable coin balance of given vault account\r\n    /// @param _roleId RoleId associated with given vault account\r\n    /// @param _token Address of stable coin  \r\n    function getTokenBalance(string calldata _roleId, address _token) internal view returns (uint256) {\r\n        if(_token == getPaymentToken()) {\r\n            return getVaultBalance(_roleId);\r\n        } else {\r\n            return StableCoinLib.getStableCoinBalance(_roleId, _token);\r\n        }\r\n    }\r\n\r\n    /// @dev Returns amount already borrowed by given pool\r\n    /// @param _poolId PoolId associated with given pool\r\n    function getBorrowedAmount(string memory _poolId) internal view returns (uint256) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.borrowedAmount[_poolId];\r\n    }\r\n\r\n    /// @dev Returns minimum amount that needs to be deposited \r\n    function getMinDepositLimit() internal view returns (uint256) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.minDepositLimit;\r\n    }\r\n\r\n    /// @dev Returns contract address of payment token\r\n    function getPaymentToken() internal view returns (address) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.paymentToken;\r\n    }\r\n\r\n    /// @dev Returns request status of given user\r\n    /// @param _roleId LenderId / PoolManagerId of given user\r\n    function getRequestStatus(string calldata _roleId) internal view returns (RequestStatus memory) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.pendingRequest[_roleId];\r\n    }\r\n\r\n    /// @dev Returns request list\r\n    function getRequests() internal view returns (Request[] memory) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.requests;\r\n    }\r\n\r\n    /// @dev Returns request data associated with request index\r\n    /// @param _reqIndex Request index to query for data\r\n    function getRequestByIndex(uint256 _reqIndex) internal view returns (Request memory) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.requests[_reqIndex];\r\n    }\r\n\r\n    /// @dev Returns number of requests registered so far \r\n    function getRequestsLength() internal view returns (uint256) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.requests.length;\r\n    }\r\n\r\n    /// @dev Returns true if contract is paused for certain operations\r\n    function paused() internal view returns (bool) {\r\n        VaultState storage vaultState = diamondStorage();\r\n        return vaultState.paused;\r\n    }\r\n\r\n    /// @dev Initializes payment token address\r\n    /// @notice This function can be called only once, throws error if the address is already set\r\n    /// @notice Restricted access function, should be called by owner only\r\n    /// @param _token Address of payment token\r\n    function initializePaymentToken(address _token) internal {\r\n        LibDiamond.enforceIsContractOwner();\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(vaultState.paymentToken != address(0)) {\r\n            revert PaymentTokenIsInitialized(vaultState.paymentToken);\r\n        }\r\n        vaultState.paymentToken = _token;\r\n    }\r\n\r\n    /// @dev Sets minimum deposit limit\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _limit New limit to set\r\n    function setMinDepositLimit(uint256 _limit) internal {\r\n        AccessControlLib.enforceIsConfigManager();\r\n        VaultState storage vaultState = diamondStorage();\r\n        vaultState.minDepositLimit = _limit;\r\n    }\r\n\r\n    /// @dev Pauses the contract to restrict certain functions\r\n    /// @notice Restricted access function, should be called by owner only\r\n    function pause() internal whenNotPaused {\r\n        LibDiamond.enforceIsContractOwner();\r\n        VaultState storage vaultState = diamondStorage();\r\n        vaultState.paused = true;\r\n    }\r\n\r\n    /// @dev Unpauses the contract to allow certain functions\r\n    /// @notice Restricted access function, should be called by owner only\r\n    function unpause() internal whenPaused {\r\n        LibDiamond.enforceIsContractOwner();\r\n        VaultState storage vaultState = diamondStorage();\r\n        vaultState.paused = false;\r\n    }\r\n\r\n    /// @dev Allows lender to deposit whitelisted tokens into vault\r\n    /// @notice Throws error if lender is not KYB verified\r\n    /// @param _roleId LenderId of given user\r\n    /// @param _token Address of stable coin\r\n    /// @param _amount Amount of payment token to deposit\r\n    function deposit(string calldata _roleId, address _token, uint256 _amount) internal whenNotPaused returns (string memory) {\r\n        LenderLib.enforceIsLender(_roleId);\r\n        LenderLib.enforceIsLenderKYBVerified(_roleId);\r\n        VaultState storage vaultState = diamondStorage();\r\n        uint256 _minAmount = (VaultLib.getMinDepositLimit() * (10 ** IERC20Metadata(_token).decimals())) / 1000000;\r\n        if(_amount == 0 || _amount < _minAmount) {\r\n            revert InvalidAmount(_amount);\r\n        }\r\n        if(!StableCoinLib.isWhitelistedToken(_token)) {\r\n            revert InvalidPoolToken(_token);\r\n        }\r\n        IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\r\n        vaultState.isVaultCall = true;\r\n        string memory _paymentId = PaymentLib.addPayment(_roleId, new string(0), PaymentLib.PaymentType.DEPOSIT, msg.sender, address(this), _amount);\r\n        LenderLib.addPaymentId(_roleId, _paymentId);\r\n        if(_token == vaultState.paymentToken) {\r\n            vaultState.vaultBalance[_roleId] += _amount;\r\n        } else {\r\n            StableCoinLib.increaseBalance(_roleId, _token, _amount);\r\n            StableCoinLib.addPaymentStableCoin(_paymentId, _token);\r\n        }\r\n        vaultState.isVaultCall = false;\r\n        return _paymentId;\r\n    }\r\n\r\n    /// @dev Allows lender to invest into given pool\r\n    /// @param _roleId LenderId of given user\r\n    /// @param _poolId PoolId of the credit pool to which user wants to invest in\r\n    /// @param _amount Amount of payment token to invest \r\n    function invest(string calldata _roleId, string calldata _poolId, uint256 _amount) internal whenNotPaused {\r\n        LenderLib.enforceIsLender(_roleId);\r\n        LenderLib.enforceIsLenderKYBVerified(_roleId);\r\n        CreditPoolLib.enforceIsActivePool(_poolId);\r\n        CreditPoolLib.enforcePoolIsNotExpired(_poolId);\r\n        VaultState storage vaultState = diamondStorage();\r\n        uint256 _balance = getTokenBalance(_roleId, StableCoinLib.getPoolToken(_poolId));\r\n        if(\r\n            _amount == 0 ||\r\n            _amount > _balance ||\r\n            _amount + vaultState.borrowedAmount[_poolId] > CreditPoolLib.getCreditPoolBorrowingAmount(_poolId)\r\n        ) {\r\n            revert InvalidAmount(_amount);\r\n        }\r\n        if(vaultState.pendingRequest[_roleId].isPending) {\r\n            revert PendingRequestExist(_roleId);\r\n        }\r\n        vaultState.isVaultCall = true;\r\n        string memory _paymentId = PaymentLib.addPayment(\r\n            _roleId,\r\n            _poolId,\r\n            PaymentLib.PaymentType.INVESTMENT,\r\n            msg.sender,\r\n            address(this),\r\n            _amount\r\n        );\r\n        LenderLib.addPaymentId(_roleId, _paymentId);\r\n        CreditPoolLib.addPaymentId(_poolId, _paymentId);\r\n        CreditPoolLib.addLenderId(_poolId, _roleId);\r\n        if(StableCoinLib.getPoolToken(_poolId) == vaultState.paymentToken) {\r\n            vaultState.vaultBalance[_roleId] -= _amount;\r\n        } else {\r\n            StableCoinLib.decreaseBalance(_roleId, StableCoinLib.getPoolToken(_poolId), _amount);\r\n        }\r\n        vaultState.isVaultCall = false;\r\n        vaultState.vaultBalance[_poolId] += _amount;\r\n        vaultState.borrowedAmount[_poolId] += _amount;\r\n    }\r\n\r\n    /// @dev Distributes pool payment to lender who invested into the pool\r\n    /// @notice Ristricted access function, should be called by distribute facet only \r\n    /// @param _roleId LenderId of user to distribute\r\n    /// @param _poolId PoolId of credit pool from which payment is being distributed\r\n    /// @param _paymentInfo Payment details with breakdown that is being distributed\r\n    function distribute(\r\n        string calldata _roleId,\r\n        string calldata _poolId,\r\n        PaymentInfo[] calldata _paymentInfo\r\n    ) internal whenNotPaused {\r\n        DistributeLib.enforceIsDistribute();\r\n        VaultState storage vaultState = diamondStorage();\r\n        LenderLib.enforceIsLender(_roleId);\r\n        LenderLib.enforceIsLenderKYBVerified(_roleId);\r\n        CreditPoolLib.enforceIsLenderBoundWithPool(_roleId, _poolId);\r\n        uint256 _amount;\r\n        vaultState.isVaultCall = true;\r\n        for(uint i = 0; i < _paymentInfo.length; i++) {\r\n            if(_paymentInfo[i].amount == 0) revert InvalidAmount(_paymentInfo[i].amount);\r\n            if(\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.INVESTMENT ||\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.DEPOSIT ||\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.WITHDRAW ||\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.FEE\r\n            ) {\r\n                revert InvalidPaymentType(_paymentInfo[i].paymentType);\r\n            }\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                _poolId,\r\n                _paymentInfo[i].paymentType,\r\n                address(this),\r\n                msg.sender,\r\n                _paymentInfo[i].amount\r\n            );\r\n            LenderLib.addPaymentId(_roleId, _paymentId);\r\n            CreditPoolLib.addPaymentId(_poolId, _paymentId);\r\n            if(_paymentInfo[i].paymentType == PaymentLib.PaymentType.EXIT) {\r\n                CreditPoolLib.removeLenderId(_poolId, _roleId);\r\n                emit Exit(_roleId, _poolId, _paymentInfo[i].amount);\r\n            }\r\n            _amount += _paymentInfo[i].amount;\r\n        }\r\n        if(_amount > StableCoinLib.getPaidBalance(_poolId)) revert InvalidAmount(_amount);\r\n        StableCoinLib.decreasePaidBalance(_poolId, _amount);\r\n        if(StableCoinLib.getPoolToken(_poolId) == vaultState.paymentToken) {\r\n            vaultState.vaultBalance[_roleId] += _amount;\r\n        } else {\r\n            StableCoinLib.increaseBalance(_roleId, StableCoinLib.getPoolToken(_poolId), _amount);\r\n        }\r\n        vaultState.isVaultCall = false;\r\n    }\r\n\r\n    /// @dev Withdraws given amount from vault if eligible, registers a request otherwise\r\n    /// @param _roleId LenderId of given user\r\n    /// @param _token Address of whitelisted stable coin\r\n    /// @param _amount Amount of stable coin to withdraw from vault\r\n    function withdrawRequest(string calldata _roleId, address _token, uint256 _amount) internal whenNotPaused returns(bool _isWithdrawn) {\r\n        LenderLib.enforceIsLender(_roleId);\r\n        LenderLib.enforceIsLenderKYBVerified(_roleId);\r\n        VaultState storage vaultState = diamondStorage();\r\n        uint256 _balance = getTokenBalance(_roleId, _token);\r\n        if(_amount == 0 || _amount > _balance) {\r\n            revert InvalidAmount(_amount);\r\n        }\r\n        vaultState.isVaultCall = true;\r\n        uint256 _threshold = (StableCoinLib.getLenderThreshold() * (10 ** IERC20Metadata(_token).decimals())) / 1000000;\r\n        if(\r\n            (_amount <= _threshold) && \r\n            (block.timestamp > StableCoinLib.getLenderCoolingTime() + StableCoinLib.getLastWithdrawalTimeStamp(_roleId))\r\n        ) {\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                new string(0),\r\n                PaymentLib.PaymentType.WITHDRAW,\r\n                address(this),\r\n                msg.sender,\r\n                _amount\r\n            );\r\n            LenderLib.addPaymentId(_roleId, _paymentId);\r\n            if(_token == vaultState.paymentToken) {\r\n                vaultState.vaultBalance[_roleId] -= _amount;\r\n            } else {\r\n                StableCoinLib.decreaseBalance(_roleId, _token, _amount);\r\n                StableCoinLib.addPaymentStableCoin(_paymentId, _token);\r\n            }\r\n            StableCoinLib.updateLastWithdrawalTimeStamp(_roleId, uint64(block.timestamp));\r\n            IERC20(_token).safeTransfer(msg.sender, _amount);\r\n            _isWithdrawn = true;    \r\n        } else {\r\n            if(vaultState.pendingRequest[_roleId].isPending) {\r\n                revert PendingRequestExist(_roleId);\r\n            }\r\n            uint256 _reqIndex = vaultState.requests.length;\r\n            vaultState.requests.push(Request(_roleId, new string(0), msg.sender, RequestType.WITHDRAW, _amount));\r\n            StableCoinLib.addRequestedToken(_roleId, _token);\r\n            vaultState.pendingRequest[_roleId] = RequestStatus(true, _reqIndex);\r\n        }\r\n        vaultState.isVaultCall = false;\r\n    }\r\n\r\n    /// @dev Processes withdraw request of lender\r\n    /// @notice Restricted access function, should be called by an address with withdraw manager role\r\n    /// @param _reqIndex Request index to process\r\n    /// @param _isApproved True / False to accept / reject request\r\n    function processWithdrawRequest(uint256 _reqIndex, bool _isApproved) internal {\r\n        AccessControlLib.enforceIsWithdrawManager();\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(vaultState.requests[_reqIndex].requestType != RequestType.WITHDRAW) {\r\n            revert InvalidRequestIndex(_reqIndex);\r\n        }\r\n        Request memory _request = vaultState.requests[_reqIndex];\r\n        if(_isApproved) {\r\n            LenderLib.enforceIsLenderKYBVerified(_request.roleId);\r\n            vaultState.isVaultCall = true;\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _request.roleId,\r\n                _request.poolId,\r\n                PaymentLib.PaymentType.WITHDRAW,\r\n                address(this),\r\n                _request.wallet,\r\n                _request.amount\r\n            );\r\n            LenderLib.addPaymentId(_request.roleId, _paymentId);\r\n            address _token = StableCoinLib.getRequestedToken(_request.roleId);\r\n            if(_token == vaultState.paymentToken) {\r\n                vaultState.vaultBalance[_request.roleId] -= _request.amount;\r\n            } else {\r\n                StableCoinLib.decreaseBalance(_request.roleId, _token, _request.amount);\r\n                StableCoinLib.addPaymentStableCoin(_paymentId, _token);\r\n            }\r\n            vaultState.isVaultCall = false;\r\n            IERC20(_token).safeTransfer(_request.wallet, _request.amount);\r\n        }\r\n        uint256 _lastReqIndex = vaultState.requests.length - 1;\r\n        if(_reqIndex != _lastReqIndex) {\r\n            vaultState.requests[_reqIndex] = vaultState.requests[_lastReqIndex];\r\n            vaultState.pendingRequest[vaultState.requests[_lastReqIndex].roleId].requestIndex = _reqIndex;\r\n        }\r\n        vaultState.requests.pop();\r\n        delete vaultState.pendingRequest[_request.roleId];\r\n    }\r\n\r\n    /// @dev Withdraws given amount from pool if eligible, registers a request otherwise\r\n    /// @param _roleId PoolManagerId of given user\r\n    /// @param _poolId PoolId of credit pool from which pool manager wants to withdraw funds\r\n    /// @param _amount Amount of payment token to withdraw from given pool\r\n    function receiveInvestmentRequest(string calldata _roleId, string calldata _poolId, uint256 _amount) internal whenNotPaused returns(bool _isWithdrawn) {\r\n        CreditPoolLib.enforceIsPoolManagerBoundWithPool(_roleId, _poolId);\r\n        PoolManagerLib.enforceIsPoolManager(_roleId);\r\n        PoolManagerLib.enforceIsPoolManagerKYBVerified(_roleId);\r\n        CreditPoolLib.enforceIsActivePool(_poolId);\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(_amount == 0 || _amount > vaultState.vaultBalance[_poolId]) {\r\n            revert InvalidAmount(_amount);\r\n        }\r\n        vaultState.isVaultCall = true;\r\n        uint256 _threshold = (StableCoinLib.getPoolThreshold() * (10 ** IERC20Metadata(StableCoinLib.getPoolToken(_poolId)).decimals())) / 1000000;\r\n        if(\r\n            (_amount <= _threshold) && \r\n            (block.timestamp > StableCoinLib.getPoolCoolingTime() + StableCoinLib.getLastWithdrawalTimeStamp(_poolId))\r\n        ) {\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                _poolId,\r\n                PaymentLib.PaymentType.WITHDRAW,\r\n                address(this),\r\n                msg.sender,\r\n                _amount\r\n            );\r\n            PoolManagerLib.addPaymentId(_roleId, _paymentId);\r\n            CreditPoolLib.addPaymentId(_poolId, _paymentId);\r\n            vaultState.vaultBalance[_poolId] -= _amount;\r\n            address _token = StableCoinLib.getPoolToken(_poolId);\r\n            StableCoinLib.updateLastWithdrawalTimeStamp(_poolId, uint64(block.timestamp));\r\n            IERC20(_token).safeTransfer(msg.sender, _amount);\r\n            _isWithdrawn = true;\r\n        } else {\r\n            if(vaultState.pendingRequest[_roleId].isPending) {\r\n                revert PendingRequestExist(_roleId);\r\n            }\r\n            uint256 _reqIndex = vaultState.requests.length;\r\n            vaultState.requests.push(Request(_roleId, _poolId, msg.sender, RequestType.RECEIVE, _amount));\r\n            vaultState.pendingRequest[_roleId] = RequestStatus(true, _reqIndex);\r\n        }\r\n        vaultState.isVaultCall = false;\r\n    }\r\n\r\n    /// @dev Processes withdraw request of pool manager\r\n    /// @notice Restricted access function, should be called by an address with withdraw manager role\r\n    /// @param _reqIndex Request index to process\r\n    /// @param _isApproved True / False to accept / reject request\r\n    function processReceiveInvestmentRequest(uint256 _reqIndex, bool _isApproved) internal {\r\n        AccessControlLib.enforceIsWithdrawManager();\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(vaultState.requests[_reqIndex].requestType != RequestType.RECEIVE) {\r\n            revert InvalidRequestIndex(_reqIndex);\r\n        }\r\n        Request memory _request = vaultState.requests[_reqIndex];\r\n        if(_isApproved) {\r\n            PoolManagerLib.enforceIsPoolManagerKYBVerified(_request.roleId);\r\n            CreditPoolLib.enforceIsActivePool(_request.poolId);\r\n            vaultState.isVaultCall = true;\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _request.roleId,\r\n                _request.poolId,\r\n                PaymentLib.PaymentType.WITHDRAW,\r\n                address(this),\r\n                _request.wallet,\r\n                _request.amount\r\n            );\r\n            PoolManagerLib.addPaymentId(_request.roleId, _paymentId);\r\n            CreditPoolLib.addPaymentId(_request.poolId, _paymentId);\r\n            vaultState.isVaultCall = false;\r\n            vaultState.vaultBalance[_request.poolId] -= _request.amount;\r\n            address _token = StableCoinLib.getPoolToken(_request.poolId);\r\n            IERC20(_token).safeTransfer(_request.wallet, _request.amount);\r\n        }\r\n        uint256 _lastReqIndex = vaultState.requests.length - 1;\r\n        if(_reqIndex != _lastReqIndex) {\r\n            vaultState.requests[_reqIndex] = vaultState.requests[_lastReqIndex];\r\n            vaultState.pendingRequest[vaultState.requests[_lastReqIndex].roleId].requestIndex = _reqIndex;\r\n        }\r\n        vaultState.requests.pop();\r\n        delete vaultState.pendingRequest[_request.roleId];\r\n    }\r\n\r\n    /// @dev Allows pool manager to pay payment tokens to credit pool\r\n    /// @param _roleId PoolManagerId of given user\r\n    /// @param _poolId PoolId of credit pool to pay for\r\n    /// @param _paymentInfo Payment details with breakdown that is being paid to given pool\r\n    function pay(\r\n        string calldata _roleId,\r\n        string calldata _poolId,\r\n        PaymentInfo[] calldata _paymentInfo\r\n    ) internal whenNotPaused {\r\n        CreditPoolLib.enforceIsPoolManagerBoundWithPool(_roleId, _poolId);\r\n        PoolManagerLib.enforceIsPoolManager(_roleId);\r\n        PoolManagerLib.enforceIsPoolManagerKYBVerified(_roleId);\r\n        CreditPoolLib.enforceIsActivePool(_poolId);\r\n        VaultState storage vaultState = diamondStorage();\r\n        uint256 _amount;\r\n        vaultState.isVaultCall = true;\r\n        address _token = StableCoinLib.getPoolToken(_poolId);\r\n        for(uint i = 0; i < _paymentInfo.length; i++) {\r\n            if(_paymentInfo[i].amount == 0) revert InvalidAmount(_paymentInfo[i].amount);\r\n            if(\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.INVESTMENT ||\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.DEPOSIT ||\r\n                _paymentInfo[i].paymentType == PaymentLib.PaymentType.WITHDRAW\r\n            ) {\r\n                revert InvalidPaymentType(_paymentInfo[i].paymentType);\r\n            }\r\n            string memory _paymentId;\r\n            if(_paymentInfo[i].paymentType == PaymentLib.PaymentType.FEE) {\r\n                _paymentId = PaymentLib.addPayment(_roleId, _poolId, PaymentLib.PaymentType.FEE, msg.sender, LibDiamond.contractOwner(), _paymentInfo[i].amount);\r\n                IERC20(_token).safeTransfer(LibDiamond.contractOwner(), _paymentInfo[i].amount);\r\n                emit Fee(_poolId, _paymentInfo[i].amount);\r\n            } else {\r\n                _paymentId = PaymentLib.addPayment(_roleId, _poolId, _paymentInfo[i].paymentType, msg.sender, address(this), _paymentInfo[i].amount);\r\n                _amount += _paymentInfo[i].amount;\r\n            }\r\n            PoolManagerLib.addPaymentId(_roleId, _paymentId);\r\n            CreditPoolLib.addPaymentId(_poolId, _paymentId);\r\n        }\r\n        IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);\r\n        StableCoinLib.increasePaidBalance(_poolId, _amount);\r\n        vaultState.isVaultCall = false;\r\n    }\r\n\r\n    /// @dev Adjusts vault balance of lender / paid balance of pool case of correction\r\n    /// @notice Restricted access function, should be called by an owner only\r\n    /// @param _id LenderId / PoolId of a vault account\r\n    /// @param _amount Amount of payment token to adjust\r\n    /// @param _account Account type of given id\r\n    /// @param _type Type of adjustment (deposit / withdraw) \r\n    function adjustVaultBalance(\r\n        string calldata _id,\r\n        uint256 _amount,\r\n        AccountType _account,\r\n        PaymentLib.PaymentType _type\r\n    ) internal {\r\n        LibDiamond.enforceIsContractOwner();\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(_amount == 0) revert InvalidAmount(_amount);\r\n        string memory _roleId = _account == AccountType.LENDER ? _id : new string(0);\r\n        string memory _poolId = _account == AccountType.POOL ? _id : new string(0);\r\n        if(_type == PaymentLib.PaymentType.DEPOSIT) {\r\n            vaultState.isVaultCall = true;\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                _poolId,\r\n                _type,\r\n                msg.sender,\r\n                address(this),\r\n                _amount\r\n            );\r\n            if (_account == AccountType.LENDER) {\r\n                LenderLib.addPaymentId(_id, _paymentId);\r\n                vaultState.vaultBalance[_id] += _amount;\r\n            } else {\r\n                CreditPoolLib.addPaymentId(_id, _paymentId);\r\n                StableCoinLib.increasePaidBalance(_id, _amount);\r\n            } \r\n            vaultState.isVaultCall = false;\r\n        }\r\n        if(_type == PaymentLib.PaymentType.WITHDRAW) {\r\n            vaultState.isVaultCall = true;\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                _poolId,\r\n                _type,\r\n                address(this),\r\n                msg.sender,\r\n                _amount\r\n            );\r\n            if (_account == AccountType.LENDER) {\r\n                LenderLib.addPaymentId(_id, _paymentId);\r\n                vaultState.vaultBalance[_id] -= _amount;\r\n            } else {\r\n                CreditPoolLib.addPaymentId(_id, _paymentId);\r\n                StableCoinLib.decreasePaidBalance(_id, _amount);\r\n            }\r\n            vaultState.isVaultCall = false;\r\n        }\r\n    }\r\n\r\n    /// @dev Adjusts balance of lender account in case of correction\r\n    /// @notice Restricted access function, should be called by an owner only\r\n    /// @param _roleId LenderId of a vault account\r\n    /// @param _amount Amount of payment token to adjust\r\n    /// @param _token Address of stable coin\r\n    /// @param _type Type of adjustment (deposit / withdraw) \r\n    function adjustStableCoinBalance(\r\n        string calldata _roleId,\r\n        uint256 _amount,\r\n        address _token,\r\n        PaymentLib.PaymentType _type\r\n    ) internal {\r\n        LibDiamond.enforceIsContractOwner();\r\n        LenderLib.enforceIsLenderKYBVerified(_roleId);\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(_amount == 0) revert InvalidAmount(_amount);\r\n        if(!StableCoinLib.isWhitelistedToken(_token)) {\r\n            revert InvalidPoolToken(_token);\r\n        }\r\n        if(_token == vaultState.paymentToken) {\r\n            revert InvalidFunction();\r\n        }\r\n        if(_type == PaymentLib.PaymentType.DEPOSIT) {\r\n            vaultState.isVaultCall = true;\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                new string(0),\r\n                _type,\r\n                msg.sender,\r\n                address(this),\r\n                _amount\r\n            );\r\n            LenderLib.addPaymentId(_roleId, _paymentId);\r\n            StableCoinLib.increaseBalance(_roleId, _token, _amount);\r\n            StableCoinLib.addPaymentStableCoin(_paymentId, _token);\r\n            vaultState.isVaultCall = false;\r\n        }\r\n        if(_type == PaymentLib.PaymentType.WITHDRAW) {\r\n            vaultState.isVaultCall = true;\r\n            string memory _paymentId = PaymentLib.addPayment(\r\n                _roleId,\r\n                new string(0),\r\n                _type,\r\n                address(this),\r\n                msg.sender,\r\n                _amount\r\n            );\r\n            LenderLib.addPaymentId(_roleId, _paymentId);\r\n            StableCoinLib.decreaseBalance(_roleId, _token, _amount);\r\n            StableCoinLib.addPaymentStableCoin(_paymentId, _token);\r\n            vaultState.isVaultCall = false;\r\n        }\r\n    }\r\n\r\n    /// @dev Withdraws ERC20 token from contract in case of emergency\r\n    /// @notice Restricted access function, should be called by an owner only\r\n    /// @param _token Address of ERC20 token to withdraw\r\n    /// @param _to Address of receiver\r\n    /// @param _amount Amount of ERC20 token to withdraw from contract \r\n    function emergencyWithdraw(address _token, address _to, uint256 _amount) internal {\r\n        LibDiamond.enforceIsContractOwner();\r\n        if(_amount == 0) revert InvalidAmount(_amount);\r\n        IERC20(_token).safeTransfer(_to, _amount);\r\n    }\r\n\r\n    /// @dev Throws error if called by other than vault library\r\n    function enforceIsVault() internal view {\r\n        VaultState storage vaultState = diamondStorage();\r\n        if(!vaultState.isVaultCall) {\r\n            revert NotVaultCall();\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if contract is not paused\r\n    function requireNotPaused() internal view {\r\n        if (paused()) {\r\n            revert EnforcedPause();\r\n        }\r\n    }\r\n\r\n    /// @dev Throws error if contract is paused\r\n    function requirePaused() internal view {\r\n        if (!paused()) {\r\n            revert ExpectedPause();\r\n        }\r\n    }    \r\n}\r\n\r\n/// @title Vault facet\r\ncontract VaultFacet {\r\n    event Adjust(string indexed id, uint256 amount, VaultLib.AccountType account, PaymentLib.PaymentType paymentType);\r\n    event Deposit(string indexed roleId, uint256 amount);\r\n    event DepositStableCoin(string indexed roleId, address token, uint256 amount);\r\n    event Invest(string indexed roleId, string poolId, uint256 amount);\r\n    event Withdraw(string indexed roleId, uint256 amount);\r\n    event WithdrawStableCoin(string indexed roleId, address token, uint256 amount);\r\n    event WithdrawRequest(string roleId, address token, uint256 amount);\r\n    event Receive(string indexed roleId, string poolId, uint256 amount);\r\n    event ReceiveRequest(string roleId, string poolId, uint256 amount);\r\n    event Pay(string indexed roleId, string poolId, VaultLib.PaymentInfo[] paymentInfo);\r\n    event Paused(address account);\r\n    event Unpaused(address account);\r\n    \r\n    /// @dev Returns balance of given vault account\r\n    /// @param _roleId RoleId associated with given vault account  \r\n    function getVaultBalance(string calldata _roleId) external view returns (uint256) {\r\n        return VaultLib.getVaultBalance(_roleId);\r\n    }\r\n\r\n    /// @dev Returns stable coin balance of given vault account\r\n    /// @param _roleId RoleId associated with given vault account\r\n    /// @param _token Address of stable coin  \r\n    function getTokenBalance(string calldata _roleId, address _token) external view returns (uint256) {\r\n        return VaultLib.getTokenBalance(_roleId, _token);\r\n    }\r\n\r\n    /// @dev Returns amount already borrowed by given pool\r\n    /// @param _poolId PoolId associated with given pool\r\n    function getBorrowedAmount(string calldata _poolId) external view returns (uint256) {\r\n        return VaultLib.getBorrowedAmount(_poolId);\r\n    }\r\n\r\n    /// @dev Returns minimum amount that needs to be deposited \r\n    function getMinDepositLimit() external view returns (uint256) {\r\n        return VaultLib.getMinDepositLimit();\r\n    }\r\n\r\n    /// @dev Returns contract address of payment token\r\n    function getPaymentToken() external view returns (address) {\r\n        return VaultLib.getPaymentToken();\r\n    }\r\n\r\n    /// @dev Returns request status of given user\r\n    /// @param _roleId LenderId / PoolManagerId of given user\r\n    function getRequestStatus(string calldata _roleId) external view returns (VaultLib.RequestStatus memory) {\r\n        return VaultLib.getRequestStatus(_roleId);\r\n    }\r\n\r\n    /// @dev Returns request list\r\n    function getRequests() external view returns (VaultLib.Request[] memory) {\r\n        return VaultLib.getRequests();\r\n    }\r\n\r\n    /// @dev Returns request data associated with request index\r\n    /// @param _reqIndex Request index to query for data\r\n    function getRequestByIndex(uint256 _reqIndex) external view returns (VaultLib.Request memory) {\r\n        return VaultLib.getRequestByIndex(_reqIndex);\r\n    }\r\n\r\n    /// @dev Returns number of requests registered so far \r\n    function getRequestsLength() external view returns (uint256) {\r\n        return VaultLib.getRequestsLength();\r\n    }\r\n\r\n    /// @dev Returns true if contract is paused for certain operations\r\n    function paused() external view returns (bool) {\r\n        return VaultLib.paused();\r\n    }\r\n\r\n    /// @dev Initializes payment token address\r\n    /// @notice This function can be called only once, throws error if the address is already set\r\n    /// @notice Restricted access function, should be called by owner only\r\n    /// @param _token Address of payment token\r\n    function initializePaymentToken(address _token) external {\r\n        return VaultLib.initializePaymentToken(_token);\r\n    }\r\n\r\n    /// @dev Sets minimum deposit limit\r\n    /// @notice Restricted access function, should be called by an address with config manager role\r\n    /// @param _limit New limit to set\r\n    function setMinDepositLimit(uint256 _limit) external {\r\n        return VaultLib.setMinDepositLimit(_limit);\r\n    }\r\n\r\n    /// @dev Adjusts vault balance of lender / paid balance of pool case of correction\r\n    /// @notice Restricted access function, should be called by an owner only\r\n    /// @param _id LenderId / PoolId of a vault account\r\n    /// @param _amount Amount of payment token to adjust\r\n    /// @param _account Account type of given id\r\n    /// @param _type Type of adjustment (deposit / withdraw) \r\n    function adjustVaultBalance(\r\n        string calldata _id,\r\n        uint256 _amount,\r\n        VaultLib.AccountType _account,\r\n        PaymentLib.PaymentType _type\r\n    ) external {\r\n        VaultLib.adjustVaultBalance(_id, _amount, _account, _type);\r\n        emit Adjust(_id, _amount, _account, _type);\r\n    }\r\n\r\n    /// @dev Pauses the contract to restrict certain functions\r\n    /// @notice Restricted access function, should be called by owner only\r\n    function pause() external {\r\n        VaultLib.pause();\r\n        emit Paused(msg.sender);\r\n    }\r\n\r\n    /// @dev Unpauses the contract to allow certain functions\r\n    /// @notice Restricted access function, should be called by owner only\r\n    function unpause() external {\r\n        VaultLib.unpause();\r\n        emit Unpaused(msg.sender);\r\n    }\r\n\r\n    /// @dev Allows lender to deposit whitelisted tokens into vault\r\n    /// @notice Throws error if lender is not KYB verified\r\n    /// @param _roleId LenderId of given user\r\n    /// @param _token Address of stable coin\r\n    /// @param _amount Amount of payment token to deposit\r\n    function deposit(string calldata _roleId, address _token, uint256 _amount) external returns (string memory) {\r\n        if(_token == VaultLib.getPaymentToken()) {\r\n            emit Deposit(_roleId, _amount);\r\n        } else {\r\n            emit DepositStableCoin(_roleId, _token, _amount);\r\n        }\r\n        return VaultLib.deposit(_roleId, _token, _amount);\r\n    }\r\n\r\n    /// @dev Allows lender to invest into given pool\r\n    /// @param _roleId LenderId of given user\r\n    /// @param _poolId PoolId of the credit pool to which user wants to invest in\r\n    /// @param _amount Amount of payment token to invest \r\n    function invest(string calldata _roleId, string calldata _poolId, uint256 _amount) external {\r\n        VaultLib.invest(_roleId, _poolId, _amount);\r\n        emit Invest(_roleId, _poolId, _amount);\r\n    }\r\n\r\n    /// @dev Withdraws given amount from vault if eligible, registers a request otherwise\r\n    /// @param _roleId LenderId of given user\r\n    /// @param _token Address of whitelisted stable coin\r\n    /// @param _amount Amount of stable coin to withdraw from vault\r\n    function withdrawRequest(string calldata _roleId, address _token, uint256 _amount) external returns(bool _isWithdrawn) {\r\n        _isWithdrawn = VaultLib.withdrawRequest(_roleId, _token, _amount);\r\n        if(_isWithdrawn) {\r\n            if(_token == VaultLib.getPaymentToken()) {\r\n                emit Withdraw(_roleId, _amount);\r\n            } else {\r\n                emit WithdrawStableCoin(_roleId, _token, _amount);\r\n            }\r\n        } else {\r\n            emit WithdrawRequest(_roleId, _token, _amount);\r\n        }\r\n    }\r\n\r\n    /// @dev Processes withdraw request of lender\r\n    /// @notice Restricted access function, should be called by an address with withdraw manager role\r\n    /// @param _reqIndex Request index to process\r\n    /// @param _isApproved True / False to accept / reject request\r\n    function processWithdrawRequest(uint256 _reqIndex, bool _isApproved) external {\r\n        if(_isApproved) {\r\n            VaultLib.Request memory _request = VaultLib.getRequestByIndex(_reqIndex);\r\n            address _token = StableCoinLib.getRequestedToken(_request.roleId);\r\n            if(_token == VaultLib.getPaymentToken()) {\r\n                emit Withdraw(_request.roleId, _request.amount);\r\n            } else {\r\n                emit WithdrawStableCoin(_request.roleId, _token, _request.amount);\r\n            }\r\n        }\r\n        VaultLib.processWithdrawRequest(_reqIndex, _isApproved);\r\n    }\r\n\r\n    /// @dev Withdraws given amount from pool if eligible, registers a request otherwise\r\n    /// @param _roleId PoolManagerId of given user\r\n    /// @param _poolId PoolId of credit pool from which pool manager wants to withdraw funds\r\n    /// @param _amount Amount of payment token to withdraw from given pool\r\n    function receiveInvestmentRequest(string calldata _roleId, string calldata _poolId, uint256 _amount) external returns(bool _isWithdrawn) {\r\n        _isWithdrawn = VaultLib.receiveInvestmentRequest(_roleId, _poolId, _amount);\r\n        if(_isWithdrawn) {\r\n            emit Receive(_roleId, _poolId, _amount);\r\n        } else {\r\n            emit ReceiveRequest(_roleId, _poolId, _amount);\r\n        }\r\n    }\r\n\r\n    /// @dev Processes withdraw request of pool manager\r\n    /// @notice Restricted access function, should be called by an address with withdraw manager role\r\n    /// @param _reqIndex Request index to process\r\n    /// @param _isApproved True / False to accept / reject request\r\n    function processReceiveInvestmentRequest(uint256 _reqIndex, bool _isApproved) external {\r\n        if(_isApproved) {\r\n            VaultLib.Request memory _request = VaultLib.getRequestByIndex(_reqIndex);\r\n            emit Receive(_request.roleId, _request.poolId, _request.amount);\r\n        }\r\n        VaultLib.processReceiveInvestmentRequest(_reqIndex, _isApproved);\r\n    }\r\n\r\n    /// @dev Allows pool manager to pay payment tokens to credit pool\r\n    /// @param _roleId PoolManagerId of given user\r\n    /// @param _poolId PoolId of credit pool to pay for\r\n    /// @param _paymentInfo Payment details with breakdown that is being paid to given pool\r\n    function pay(\r\n        string calldata _roleId,\r\n        string calldata _poolId,\r\n        VaultLib.PaymentInfo[] calldata _paymentInfo\r\n    ) external {\r\n        VaultLib.pay(_roleId, _poolId, _paymentInfo);\r\n        emit Pay(_roleId, _poolId, _paymentInfo);\r\n    }\r\n}"
      },
      "contracts/interfaces/IDiamond.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\n/******************************************************************************\\\r\n* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\r\n* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535\r\n/******************************************************************************/\r\n\r\ninterface IDiamond {\r\n    enum FacetCutAction {Add, Replace, Remove}\r\n    // Add=0, Replace=1, Remove=2\r\n\r\n    struct FacetCut {\r\n        address facetAddress;\r\n        FacetCutAction action;\r\n        bytes4[] functionSelectors;\r\n    }\r\n\r\n    event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);\r\n}"
      },
      "contracts/interfaces/IDiamondCut.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\n/******************************************************************************\\\r\n* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\r\n* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535\r\n/******************************************************************************/\r\n\r\nimport { IDiamond } from \"./IDiamond.sol\";\r\n\r\ninterface IDiamondCut is IDiamond {    \r\n\r\n    /// @notice Add/replace/remove any number of functions and optionally execute\r\n    ///         a function with delegatecall\r\n    /// @param _diamondCut Contains the facet addresses and function selectors\r\n    /// @param _init The address of the contract or facet to execute _calldata\r\n    /// @param _calldata A function call, including function selector and arguments\r\n    ///                  _calldata is executed with delegatecall on _init\r\n    function diamondCut(\r\n        FacetCut[] calldata _diamondCut,\r\n        address _init,\r\n        bytes calldata _calldata\r\n    ) external;    \r\n}\r\n"
      },
      "contracts/libraries/LibDiamond.sol": {
        "content": "// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\n/******************************************************************************\\\r\n* Author: Nick Mudge <nick@perfectabstractions.com> (https://twitter.com/mudgen)\r\n* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535\r\n/******************************************************************************/\r\nimport { IDiamond } from \"../interfaces/IDiamond.sol\";\r\nimport { IDiamondCut } from \"../interfaces/IDiamondCut.sol\";\r\n\r\n// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.\r\n// The loupe functions are required by the EIP2535 Diamonds standard\r\n\r\nerror NoSelectorsGivenToAdd();\r\nerror NotContractOwner(address _user, address _contractOwner);\r\nerror NoSelectorsProvidedForFacetForCut(address _facetAddress);\r\nerror CannotAddSelectorsToZeroAddress(bytes4[] _selectors);\r\nerror NoBytecodeAtAddress(address _contractAddress, string _message);\r\nerror IncorrectFacetCutAction(uint8 _action);\r\nerror CannotAddFunctionToDiamondThatAlreadyExists(bytes4 _selector);\r\nerror CannotReplaceFunctionsFromFacetWithZeroAddress(bytes4[] _selectors);\r\nerror CannotReplaceImmutableFunction(bytes4 _selector);\r\nerror CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(bytes4 _selector);\r\nerror CannotReplaceFunctionThatDoesNotExists(bytes4 _selector);\r\nerror RemoveFacetAddressMustBeZeroAddress(address _facetAddress);\r\nerror CannotRemoveFunctionThatDoesNotExist(bytes4 _selector);\r\nerror CannotRemoveImmutableFunction(bytes4 _selector);\r\nerror InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);\r\n\r\nlibrary LibDiamond {\r\n    bytes32 constant DIAMOND_STORAGE_POSITION = keccak256(\"diamond.standard.diamond.storage\");\r\n\r\n    struct FacetAddressAndSelectorPosition {\r\n        address facetAddress;\r\n        uint16 selectorPosition;\r\n    }\r\n\r\n    struct DiamondStorage {\r\n        // function selector => facet address and selector position in selectors array\r\n        mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition;\r\n        bytes4[] selectors;\r\n        mapping(bytes4 => bool) supportedInterfaces;\r\n        // owner of the contract\r\n        address contractOwner;\r\n    }\r\n\r\n    function diamondStorage() internal pure returns (DiamondStorage storage ds) {\r\n        bytes32 position = DIAMOND_STORAGE_POSITION;\r\n        assembly {\r\n            ds.slot := position\r\n        }\r\n    }\r\n\r\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\r\n\r\n    function setContractOwner(address _newOwner) internal {\r\n        DiamondStorage storage ds = diamondStorage();\r\n        address previousOwner = ds.contractOwner;\r\n        ds.contractOwner = _newOwner;\r\n        emit OwnershipTransferred(previousOwner, _newOwner);\r\n    }\r\n\r\n    function contractOwner() internal view returns (address contractOwner_) {\r\n        contractOwner_ = diamondStorage().contractOwner;\r\n    }\r\n\r\n    function enforceIsContractOwner() internal view {\r\n        if(msg.sender != diamondStorage().contractOwner) {\r\n            revert NotContractOwner(msg.sender, diamondStorage().contractOwner);\r\n        }        \r\n    }\r\n\r\n    event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);\r\n\r\n    // Internal function version of diamondCut\r\n    function diamondCut(\r\n        IDiamondCut.FacetCut[] memory _diamondCut,\r\n        address _init,\r\n        bytes memory _calldata\r\n    ) internal {\r\n        for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {\r\n            bytes4[] memory functionSelectors = _diamondCut[facetIndex].functionSelectors;\r\n            address facetAddress = _diamondCut[facetIndex].facetAddress;\r\n            if(functionSelectors.length == 0) {\r\n                revert NoSelectorsProvidedForFacetForCut(facetAddress);\r\n            }\r\n            IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;\r\n            if (action == IDiamond.FacetCutAction.Add) {\r\n                addFunctions(facetAddress, functionSelectors);\r\n            } else if (action == IDiamond.FacetCutAction.Replace) {\r\n                replaceFunctions(facetAddress, functionSelectors);\r\n            } else if (action == IDiamond.FacetCutAction.Remove) {\r\n                removeFunctions(facetAddress, functionSelectors);\r\n            } else {\r\n                revert IncorrectFacetCutAction(uint8(action));\r\n            }\r\n        }\r\n        emit DiamondCut(_diamondCut, _init, _calldata);\r\n        initializeDiamondCut(_init, _calldata);\r\n    }\r\n\r\n    function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {        \r\n        if(_facetAddress == address(0)) {\r\n            revert CannotAddSelectorsToZeroAddress(_functionSelectors);\r\n        }\r\n        DiamondStorage storage ds = diamondStorage();\r\n        uint16 selectorCount = uint16(ds.selectors.length);                \r\n        enforceHasContractCode(_facetAddress, \"LibDiamondCut: Add facet has no code\");\r\n        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\r\n            bytes4 selector = _functionSelectors[selectorIndex];\r\n            address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;\r\n            if(oldFacetAddress != address(0)) {\r\n                revert CannotAddFunctionToDiamondThatAlreadyExists(selector);\r\n            }            \r\n            ds.facetAddressAndSelectorPosition[selector] = FacetAddressAndSelectorPosition(_facetAddress, selectorCount);\r\n            ds.selectors.push(selector);\r\n            selectorCount++;\r\n        }\r\n    }\r\n\r\n    function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {        \r\n        DiamondStorage storage ds = diamondStorage();\r\n        if(_facetAddress == address(0)) {\r\n            revert CannotReplaceFunctionsFromFacetWithZeroAddress(_functionSelectors);\r\n        }\r\n        enforceHasContractCode(_facetAddress, \"LibDiamondCut: Replace facet has no code\");\r\n        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\r\n            bytes4 selector = _functionSelectors[selectorIndex];\r\n            address oldFacetAddress = ds.facetAddressAndSelectorPosition[selector].facetAddress;\r\n            // can't replace immutable functions -- functions defined directly in the diamond in this case\r\n            if(oldFacetAddress == address(this)) {\r\n                revert CannotReplaceImmutableFunction(selector);\r\n            }\r\n            if(oldFacetAddress == _facetAddress) {\r\n                revert CannotReplaceFunctionWithTheSameFunctionFromTheSameFacet(selector);\r\n            }\r\n            if(oldFacetAddress == address(0)) {\r\n                revert CannotReplaceFunctionThatDoesNotExists(selector);\r\n            }\r\n            // replace old facet address\r\n            ds.facetAddressAndSelectorPosition[selector].facetAddress = _facetAddress;\r\n        }\r\n    }\r\n\r\n    function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {        \r\n        DiamondStorage storage ds = diamondStorage();\r\n        uint256 selectorCount = ds.selectors.length;\r\n        if(_facetAddress != address(0)) {\r\n            revert RemoveFacetAddressMustBeZeroAddress(_facetAddress);\r\n        }        \r\n        for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {\r\n            bytes4 selector = _functionSelectors[selectorIndex];\r\n            FacetAddressAndSelectorPosition memory oldFacetAddressAndSelectorPosition = ds.facetAddressAndSelectorPosition[selector];\r\n            if(oldFacetAddressAndSelectorPosition.facetAddress == address(0)) {\r\n                revert CannotRemoveFunctionThatDoesNotExist(selector);\r\n            }\r\n            \r\n            \r\n            // can't remove immutable functions -- functions defined directly in the diamond\r\n            if(oldFacetAddressAndSelectorPosition.facetAddress == address(this)) {\r\n                revert CannotRemoveImmutableFunction(selector);\r\n            }\r\n            // replace selector with last selector\r\n            selectorCount--;\r\n            if (oldFacetAddressAndSelectorPosition.selectorPosition != selectorCount) {\r\n                bytes4 lastSelector = ds.selectors[selectorCount];\r\n                ds.selectors[oldFacetAddressAndSelectorPosition.selectorPosition] = lastSelector;\r\n                ds.facetAddressAndSelectorPosition[lastSelector].selectorPosition = oldFacetAddressAndSelectorPosition.selectorPosition;\r\n            }\r\n            // delete last selector\r\n            ds.selectors.pop();\r\n            delete ds.facetAddressAndSelectorPosition[selector];\r\n        }\r\n    }\r\n\r\n    function initializeDiamondCut(address _init, bytes memory _calldata) internal {\r\n        if (_init == address(0)) {\r\n            return;\r\n        }\r\n        enforceHasContractCode(_init, \"LibDiamondCut: _init address has no code\");        \r\n        (bool success, bytes memory error) = _init.delegatecall(_calldata);\r\n        if (!success) {\r\n            if (error.length > 0) {\r\n                // bubble up error\r\n                /// @solidity memory-safe-assembly\r\n                assembly {\r\n                    let returndata_size := mload(error)\r\n                    revert(add(32, error), returndata_size)\r\n                }\r\n            } else {\r\n                revert InitializationFunctionReverted(_init, _calldata);\r\n            }\r\n        }        \r\n    }\r\n\r\n    function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {\r\n        uint256 contractSize;\r\n        assembly {\r\n            contractSize := extcodesize(_contract)\r\n        }\r\n        if(contractSize == 0) {\r\n            revert NoBytecodeAtAddress(_contract, _errorMessage);\r\n        }        \r\n    }\r\n}\r\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}