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/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "contracts/DeveloperWallet.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.14;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./interface/IDatabase.sol\";\n\n/// @title   Developer Wallet\n/// @notice  Contract that a developer is deployed upon minting of Proof of Developer NFT\n/// @author  Hyacinth\ncontract DeveloperWallet {\n    /// EVENTS ///\n\n    /// @notice             Emitted after bounty has been added to\n    /// @param token        Address of token added to bounty\n    /// @param auditId      Audit id of audit bounty is being added to\n    /// @param amountAdded  Amount added to bounty\n    event AddedToBounty(address indexed token, uint256 indexed auditId, uint256 indexed amountAdded);\n\n    /// ERRORS ///\n\n    /// @notice Error for if audit id is not being audited\n    error NotBeingAudited();\n    /// @notice Error for if msg.sender is not database\n    error NotDatabase();\n    /// @notice Error for if contrac was not developed by developer\n    error NotDeveloper();\n    /// @notice Error for if bounty has been paid out already\n    error BountyPaid();\n    /// @notice Error for if USDC balance too low\n    error BalanceTooLow();\n\n    /// STATE VARIABLES ///\n\n    /// @notice Address of developer\n    address public immutable owner;\n    /// @notice Address of USDC\n    address public immutable USDC;\n    /// @notice Address of database contract\n    address public immutable database;\n\n    /// @notice Amount of tokens on bounties\n    mapping(address => uint256) public tokenOnBounties;\n\n    /// @notice Bounty amount of token on audit\n    mapping(uint256 => mapping(address => uint256)) public bountyOnContract;\n\n    /// @notice Token addresses on bounty\n    mapping(uint256 => address[]) public tokenAddressOnBounty;\n\n    /// @notice Bool if bounty has been paid out\n    mapping(uint256 => bool) public bountyPaidOut;\n\n    /// CONSTRUCTOR ///\n\n    constructor(address owner_, address database_) {\n        owner = owner_;\n        database = database_;\n        USDC = IDatabase(database_).USDC();\n    }\n\n    /// EXTERNAL FUNCTION ///\n\n    /// @notice           Add to bounty of `auditId_`\n    /// @param auditId_   Audit id to add bounty to\n    /// @param amount_    Amount of stable to add to bounty\n    /// @param transfer_  Bool if transferring token in or using what has been transferred directly\n    /// @param token_     Address of token on bounty\n    function addToBounty(uint256 auditId_, uint256 amount_, bool transfer_, address token_) external {\n        (, address developer_, , , , ) = IDatabase(database).audits(auditId_);\n        if ((developer_ != owner || developer_ != msg.sender) && database != msg.sender) revert NotDeveloper();\n        (, , IDatabase.STATUS status_, , , ) = IDatabase(database).audits(auditId_);\n        if (status_ != IDatabase.STATUS.PENDING) revert NotBeingAudited();\n        if (transfer_) IERC20(token_).transferFrom(msg.sender, address(this), amount_);\n        else {\n            uint256 avail_ = IERC20(token_).balanceOf(address(this)) - tokenOnBounties[token_];\n            if (avail_ < amount_) revert BalanceTooLow();\n        }\n\n        if (bountyOnContract[auditId_][token_] == 0) tokenAddressOnBounty[auditId_].push(token_);\n        bountyOnContract[auditId_][token_] += amount_;\n        tokenOnBounties[token_] += amount_;\n\n        emit AddedToBounty(token_, auditId_, amount_);\n    }\n\n    /// DATABASE FUNCTION ///\n\n    /// @notice                   Pays out bounty of `auditId_`\n    /// @param auditId_           Id of audit to pay bounty out for\n    /// @param collaborators_     Array of collaborators for `auditId_`\n    /// @param percentsOfBounty_  Array of corresponding percents of bounty for `collaborators_`\n    /// @return level_            Level of bounty\n    function payOutBounty(\n        uint256 auditId_,\n        address[] calldata collaborators_,\n        uint256[] calldata percentsOfBounty_\n    ) external returns (uint256 level_) {\n        if (msg.sender != database) revert NotDatabase();\n        if (bountyPaidOut[auditId_]) revert BountyPaid();\n\n        bountyPaidOut[auditId_] = true;\n\n        (address auditor_, , , , , ) = IDatabase(database).audits(auditId_);\n\n        (level_, ) = currentBountyLevel(auditId_);\n\n        for (uint i; i < tokenAddressOnBounty[auditId_].length; ++i) {\n            address token_ = tokenAddressOnBounty[auditId_][i];\n            uint256 bounty_ = bountyOnContract[auditId_][token_];\n            tokenOnBounties[token_] -= bounty_;\n            bountyOnContract[auditId_][token_] = 0;\n            uint256 bountyToDistribute_ = ((bounty_ * (100 - IDatabase(database).HYACINTH_FEE())) / 100);\n            uint256 hyacinthReceives_ = bounty_ - bountyToDistribute_;\n            IERC20(token_).transfer(IDatabase(database).hyacinthWallet(), hyacinthReceives_);\n\n            uint256 collaboratorsReceived_;\n            for (uint256 n; n < collaborators_.length; ++n) {\n                uint256 collaboratorsReceives_ = (bountyToDistribute_ * percentsOfBounty_[n]) / 100;\n                IERC20(token_).transfer(collaborators_[n], collaboratorsReceives_);\n                collaboratorsReceived_ += collaboratorsReceives_;\n            }\n\n            uint256 auditorReceives_ = bountyToDistribute_ - collaboratorsReceived_;\n            IERC20(token_).transfer(auditor_, auditorReceives_);\n        }\n    }\n\n    /// @notice           Rolls over bounty of `previous_` to `new_`\n    /// @param previous_  Audit id of roll overed audit\n    /// @param new_       Audsit id of new audit after roll over\n    function rollOverBounty(uint256 previous_, uint256 new_) external {\n        if (msg.sender != database) revert NotDatabase();\n\n        for (uint i; i < tokenAddressOnBounty[previous_].length; ++i) {\n            address token_ = tokenAddressOnBounty[previous_][i];\n            uint256 bounty_ = bountyOnContract[previous_][token_];\n\n            bountyOnContract[previous_][token_] = 0;\n            bountyOnContract[new_][token_] = bounty_;\n        }\n\n        tokenAddressOnBounty[new_] = tokenAddressOnBounty[previous_];\n    }\n\n    /// @notice           Function that allows developer to get a refund for bounty if no auditor or past deadline\n    /// @param auditId_   Audit id to get refund for\n    function refundBounty(uint256 auditId_) external {\n        if (msg.sender != database) revert NotDatabase();\n        for (uint i; i < tokenAddressOnBounty[auditId_].length; ++i) {\n            address token_ = tokenAddressOnBounty[auditId_][i];\n            uint256 bounty_ = bountyOnContract[auditId_][token_];\n            bountyOnContract[auditId_][token_] = 0;\n            tokenOnBounties[token_] -= bounty_;\n            IERC20(token_).transfer(owner, bounty_);\n        }\n    }\n\n    /// VIEW FUNCTIONS ///\n\n    /// @notice          Returns current `level_` and `bounty_` of `auditId_`\n    /// @param auditId_  Audit to check bounty for\n    /// @return level_   Current level of `contract_` bounty\n    /// @return bounty_  Current bouty of `contract_`\n    function currentBountyLevel(uint256 auditId_) public view returns (uint256 level_, uint256 bounty_) {\n        bounty_ = bountyOnContract[auditId_][USDC];\n\n        uint256 decimals_ = 10 ** IERC20Metadata(USDC).decimals();\n        if (bounty_ >= 1000 * decimals_) {\n            if (bounty_ < 10000 * decimals_) level_ = 1;\n            else if (bounty_ < 100000 * decimals_) level_ = 2;\n            else level_ = 3;\n        }\n    }\n}\n"
      },
      "contracts/interface/IDatabase.sol": {
        "content": "pragma solidity ^0.8.0;\n\ninterface IDatabase {\n    enum STATUS {\n        NOTAUDITED,\n        PENDING,\n        PASSED,\n        FAILED,\n        REFUNDED\n    }\n\n    function HYACINTH_FEE() external view returns (uint256);\n\n    function USDC() external view returns (address);\n\n    function audits(uint256 auditId_) external view returns (address, address, STATUS, string memory, uint256, bool);\n\n    function auditors(address auditor_) external view returns (uint256, uint256, uint256, uint256);\n\n    function approvedAuditor(address auditor_) external view returns (bool isAuditor_);\n\n    function hyacinthWallet() external view returns (address);\n\n    function beingAudited() external;\n\n    function mintPOD() external returns (uint256 id_, address developerWallet_);\n\n    function addApprovedAuditor(address[] calldata auditors_) external;\n\n    function removeApprovedAuditor(address[] calldata auditors_) external;\n\n    function giveAuditorFeedback(uint256 auditId_, bool positive_) external;\n\n    function refundBounty(uint256 auditId_) external;\n\n    function submitResult(uint256 auditId_, STATUS result_, string memory description_) external;\n\n    function rollOverExpired(uint256 auditId_) external;\n\n    function levelsCompleted(address auditor_) external view returns (uint256[4] memory);\n\n    function auditStatus(address contractAddress_) external view returns (STATUS status_);\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": false,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}