{
  "language": "Solidity",
  "sources": {
    "contracts/abstract/JuiceboxProject.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\n\nimport \"./../interfaces/ITerminalV1.sol\";\n\n/** \n  @notice A contract that inherits from JuiceboxProject can use Juicebox as a business-model-as-a-service.\n  @dev The owner of the contract makes admin decisions such as:\n    - Which address is the funding cycle owner, which can tap funds from the funding cycle.\n    - Should this project's Tickets be migrated to a new TerminalV1. \n*/\nabstract contract JuiceboxProject is IERC721Receiver, Ownable {\n    /// @notice The direct deposit terminals.\n    ITerminalDirectory public immutable terminalDirectory;\n\n    /// @notice The ID of the project that should be used to forward this contract's received payments.\n    uint256 public projectId;\n\n    /** \n      @param _projectId The ID of the project that should be used to forward this contract's received payments.\n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n    constructor(uint256 _projectId, ITerminalDirectory _terminalDirectory) {\n        projectId = _projectId;\n        terminalDirectory = _terminalDirectory;\n    }\n\n    receive() external payable {}\n\n    /** \n      @notice Withdraws funds stored in this contract.\n      @param _beneficiary The address to send the funds to.\n      @param _amount The amount to send.\n    */\n    function withdraw(address payable _beneficiary, uint256 _amount)\n        external\n        onlyOwner\n    {\n        Address.sendValue(_beneficiary, _amount);\n    }\n\n    /** \n      @notice Allows the project that is being managed to be set.\n      @param _projectId The ID of the project that is being managed.\n    */\n    function setProjectId(uint256 _projectId) external onlyOwner {\n        projectId = _projectId;\n    }\n\n    /** \n      @notice Make a payment to this project.\n      @param _beneficiary The address who will receive tickets from this fee.\n      @param _memo A memo that will be included in the published event.\n      @param _preferUnstakedTickets Whether ERC20's should be claimed automatically if they have been issued.\n    */\n    function pay(\n        address _beneficiary,\n        string calldata _memo,\n        bool _preferUnstakedTickets\n    ) external payable {\n        require(projectId != 0, \"JuiceboxProject::pay: PROJECT_NOT_FOUND\");\n\n        // Get the terminal for this contract's project.\n        ITerminal _terminal = terminalDirectory.terminalOf(projectId);\n\n        // There must be a terminal.\n        require(\n            _terminal != ITerminal(address(0)),\n            \"JuiceboxProject::pay: TERMINAL_NOT_FOUND\"\n        );\n\n        _terminal.pay{value: msg.value}(\n            projectId,\n            _beneficiary,\n            _memo,\n            _preferUnstakedTickets\n        );\n    }\n\n    /** \n        @notice Transfer the ownership of the project to a new owner.  \n        @dev This contract will no longer be able to reconfigure or tap funds from this project.\n        @param _projects The projects contract.\n        @param _newOwner The new project owner.\n        @param _projectId The ID of the project to transfer ownership of.\n        @param _data Arbitrary data to include in the transaction.\n    */\n    function transferProjectOwnership(\n        IProjects _projects,\n        address _newOwner,\n        uint256 _projectId,\n        bytes calldata _data\n    ) external onlyOwner {\n        _projects.safeTransferFrom(address(this), _newOwner, _projectId, _data);\n    }\n\n    /** \n      @notice Allows this contract to receive a project.\n    */\n    function onERC721Received(\n        address,\n        address,\n        uint256,\n        bytes calldata\n    ) public pure override returns (bytes4) {\n        return this.onERC721Received.selector;\n    }\n\n    function setOperator(\n        IOperatorStore _operatorStore,\n        address _operator,\n        uint256 _projectId,\n        uint256[] calldata _permissionIndexes\n    ) external onlyOwner {\n        _operatorStore.setOperator(_operator, _projectId, _permissionIndexes);\n    }\n\n    function setOperators(\n        IOperatorStore _operatorStore,\n        address[] calldata _operators,\n        uint256[] calldata _projectIds,\n        uint256[][] calldata _permissionIndexes\n    ) external onlyOwner {\n        _operatorStore.setOperators(\n            _operators,\n            _projectIds,\n            _permissionIndexes\n        );\n    }\n\n    /** \n      @notice Take a fee for this project from this contract.\n      @param _amount The payment amount.\n      @param _beneficiary The address who will receive tickets from this fee.\n      @param _memo A memo that will be included in the published event.\n      @param _preferUnstakedTickets Whether ERC20's should be claimed automatically if they have been issued.\n    */\n    function _takeFee(\n        uint256 _amount,\n        address _beneficiary,\n        string memory _memo,\n        bool _preferUnstakedTickets\n    ) internal {\n        require(projectId != 0, \"JuiceboxProject::takeFee: PROJECT_NOT_FOUND\");\n        // Find the terminal for this contract's project.\n        ITerminal _terminal = terminalDirectory.terminalOf(projectId);\n\n        // There must be a terminal.\n        require(\n            _terminal != ITerminal(address(0)),\n            \"JuiceboxProject::takeFee: TERMINAL_NOT_FOUND\"\n        );\n\n        // There must be enough funds in the contract to take the fee.\n        require(\n            address(this).balance >= _amount,\n            \"JuiceboxProject::takeFee: INSUFFICIENT_FUNDS\"\n        );\n\n        // Send funds to the terminal.\n        _terminal.pay{value: _amount}(\n            projectId,\n            _beneficiary,\n            _memo,\n            _preferUnstakedTickets\n        );\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
    },
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _setOwner(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _setOwner(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _setOwner(newOwner);\n    }\n\n    function _setOwner(address newOwner) private {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return _verifyCallResult(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        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return _verifyCallResult(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        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    function _verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) private pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\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\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}\n"
    },
    "contracts/interfaces/ITerminalV1.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport '@openzeppelin/contracts/token/ERC721/IERC721.sol';\n\nimport './ITicketBooth.sol';\nimport './IFundingCycles.sol';\nimport './IYielder.sol';\nimport './IProjects.sol';\nimport './IModStore.sol';\nimport './ITerminal.sol';\nimport './IOperatorStore.sol';\n\nstruct FundingCycleMetadata {\n  uint256 reservedRate;\n  uint256 bondingCurveRate;\n  uint256 reconfigurationBondingCurveRate;\n}\n\ninterface ITerminalV1 {\n  event Pay(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 amount,\n    string note,\n    address caller\n  );\n\n  event AddToBalance(uint256 indexed projectId, uint256 value, address caller);\n\n  event AllowMigration(ITerminal allowed);\n\n  event Migrate(uint256 indexed projectId, ITerminal indexed to, uint256 _amount, address caller);\n\n  event Configure(uint256 indexed fundingCycleId, uint256 indexed projectId, address caller);\n\n  event Tap(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 amount,\n    uint256 currency,\n    uint256 netTransferAmount,\n    uint256 beneficiaryTransferAmount,\n    uint256 govFeeAmount,\n    address caller\n  );\n  event Redeem(\n    address indexed holder,\n    address indexed beneficiary,\n    uint256 indexed _projectId,\n    uint256 amount,\n    uint256 returnAmount,\n    address caller\n  );\n\n  event PrintReserveTickets(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 count,\n    uint256 beneficiaryTicketAmount,\n    address caller\n  );\n\n  event DistributeToPayoutMod(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    PayoutMod mod,\n    uint256 modCut,\n    address caller\n  );\n  event DistributeToTicketMod(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    TicketMod mod,\n    uint256 modCut,\n    address caller\n  );\n  event AppointGovernance(address governance);\n\n  event AcceptGovernance(address governance);\n\n  event PrintPreminedTickets(\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 amount,\n    uint256 currency,\n    string memo,\n    address caller\n  );\n\n  event Deposit(uint256 amount);\n\n  event EnsureTargetLocalWei(uint256 target);\n\n  event SetYielder(IYielder newYielder);\n\n  event SetFee(uint256 _amount);\n\n  event SetTargetLocalWei(uint256 amount);\n\n  function governance() external view returns (address payable);\n\n  function pendingGovernance() external view returns (address payable);\n\n  function projects() external view returns (IProjects);\n\n  function fundingCycles() external view returns (IFundingCycles);\n\n  function ticketBooth() external view returns (ITicketBooth);\n\n  function prices() external view returns (IPrices);\n\n  function modStore() external view returns (IModStore);\n\n  function reservedTicketBalanceOf(uint256 _projectId, uint256 _reservedRate)\n    external\n    view\n    returns (uint256);\n\n  function canPrintPreminedTickets(uint256 _projectId) external view returns (bool);\n\n  function balanceOf(uint256 _projectId) external view returns (uint256);\n\n  function currentOverflowOf(uint256 _projectId) external view returns (uint256);\n\n  function claimableOverflowOf(\n    address _account,\n    uint256 _amount,\n    uint256 _projectId\n  ) external view returns (uint256);\n\n  function fee() external view returns (uint256);\n\n  function deploy(\n    address _owner,\n    bytes32 _handle,\n    string calldata _uri,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  ) external;\n\n  function configure(\n    uint256 _projectId,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  ) external returns (uint256);\n\n  function printPreminedTickets(\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _currency,\n    address _beneficiary,\n    string memory _memo,\n    bool _preferUnstakedTickets\n  ) external;\n\n  function tap(\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _currency,\n    uint256 _minReturnedWei\n  ) external returns (uint256);\n\n  function redeem(\n    address _account,\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _minReturnedWei,\n    address payable _beneficiary,\n    bool _preferUnstaked\n  ) external returns (uint256 returnAmount);\n\n  function printReservedTickets(uint256 _projectId)\n    external\n    returns (uint256 reservedTicketsToPrint);\n\n  function setFee(uint256 _fee) external;\n\n  function appointGovernance(address payable _pendingGovernance) external;\n\n  function acceptGovernance() external;\n}\n"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external;\n}\n"
    },
    "contracts/interfaces/ITicketBooth.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./IProjects.sol\";\nimport \"./IOperatorStore.sol\";\nimport \"./ITickets.sol\";\n\ninterface ITicketBooth {\n    event Issue(\n        uint256 indexed projectId,\n        string name,\n        string symbol,\n        address caller\n    );\n    event Print(\n        address indexed holder,\n        uint256 indexed projectId,\n        uint256 amount,\n        bool convertedTickets,\n        bool preferUnstakedTickets,\n        address controller\n    );\n\n    event Redeem(\n        address indexed holder,\n        uint256 indexed projectId,\n        uint256 amount,\n        uint256 stakedTickets,\n        bool preferUnstaked,\n        address controller\n    );\n\n    event Stake(\n        address indexed holder,\n        uint256 indexed projectId,\n        uint256 amount,\n        address caller\n    );\n\n    event Unstake(\n        address indexed holder,\n        uint256 indexed projectId,\n        uint256 amount,\n        address caller\n    );\n\n    event Lock(\n        address indexed holder,\n        uint256 indexed projectId,\n        uint256 amount,\n        address caller\n    );\n\n    event Unlock(\n        address indexed holder,\n        uint256 indexed projectId,\n        uint256 amount,\n        address caller\n    );\n\n    event Transfer(\n        address indexed holder,\n        uint256 indexed projectId,\n        address indexed recipient,\n        uint256 amount,\n        address caller\n    );\n\n    function ticketsOf(uint256 _projectId) external view returns (ITickets);\n\n    function projects() external view returns (IProjects);\n\n    function lockedBalanceOf(address _holder, uint256 _projectId)\n        external\n        view\n        returns (uint256);\n\n    function lockedBalanceBy(\n        address _operator,\n        address _holder,\n        uint256 _projectId\n    ) external view returns (uint256);\n\n    function stakedBalanceOf(address _holder, uint256 _projectId)\n        external\n        view\n        returns (uint256);\n\n    function stakedTotalSupplyOf(uint256 _projectId)\n        external\n        view\n        returns (uint256);\n\n    function totalSupplyOf(uint256 _projectId) external view returns (uint256);\n\n    function balanceOf(address _holder, uint256 _projectId)\n        external\n        view\n        returns (uint256 _result);\n\n    function issue(\n        uint256 _projectId,\n        string calldata _name,\n        string calldata _symbol\n    ) external;\n\n    function print(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount,\n        bool _preferUnstakedTickets\n    ) external;\n\n    function redeem(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount,\n        bool _preferUnstaked\n    ) external;\n\n    function stake(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    ) external;\n\n    function unstake(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    ) external;\n\n    function lock(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    ) external;\n\n    function unlock(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    ) external;\n\n    function transfer(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount,\n        address _recipient\n    ) external;\n}\n"
    },
    "contracts/interfaces/IFundingCycles.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./IPrices.sol\";\nimport \"./IProjects.sol\";\nimport \"./IFundingCycleBallot.sol\";\n\n/// @notice The funding cycle structure represents a project stewarded by an address, and accounts for which addresses have helped sustain the project.\nstruct FundingCycle {\n    // A unique number that's incremented for each new funding cycle, starting with 1.\n    uint256 id;\n    // The ID of the project contract that this funding cycle belongs to.\n    uint256 projectId;\n    // The number of this funding cycle for the project.\n    uint256 number;\n    // The ID of a previous funding cycle that this one is based on.\n    uint256 basedOn;\n    // The time when this funding cycle was last configured.\n    uint256 configured;\n    // The number of cycles that this configuration should last for before going back to the last permanent.\n    uint256 cycleLimit;\n    // A number determining the amount of redistribution shares this funding cycle will issue to each sustainer.\n    uint256 weight;\n    // The ballot contract to use to determine a subsequent funding cycle's reconfiguration status.\n    IFundingCycleBallot ballot;\n    // The time when this funding cycle will become active.\n    uint256 start;\n    // The number of seconds until this funding cycle's surplus is redistributed.\n    uint256 duration;\n    // The amount that this funding cycle is targeting in terms of the currency.\n    uint256 target;\n    // The currency that the target is measured in.\n    uint256 currency;\n    // The percentage of each payment to send as a fee to the Juicebox admin.\n    uint256 fee;\n    // A percentage indicating how much more weight to give a funding cycle compared to its predecessor.\n    uint256 discountRate;\n    // The amount of available funds that have been tapped by the project in terms of the currency.\n    uint256 tapped;\n    // A packed list of extra data. The first 8 bytes are reserved for versioning.\n    uint256 metadata;\n}\n\nstruct FundingCycleProperties {\n    uint256 target;\n    uint256 currency;\n    uint256 duration;\n    uint256 cycleLimit;\n    uint256 discountRate;\n    IFundingCycleBallot ballot;\n}\n\ninterface IFundingCycles {\n    event Configure(\n        uint256 indexed fundingCycleId,\n        uint256 indexed projectId,\n        uint256 reconfigured,\n        FundingCycleProperties _properties,\n        uint256 metadata,\n        address caller\n    );\n\n    event Tap(\n        uint256 indexed fundingCycleId,\n        uint256 indexed projectId,\n        uint256 amount,\n        uint256 newTappedAmount,\n        address caller\n    );\n\n    event Init(\n        uint256 indexed fundingCycleId,\n        uint256 indexed projectId,\n        uint256 number,\n        uint256 previous,\n        uint256 weight,\n        uint256 start\n    );\n\n    function latestIdOf(uint256 _projectId) external view returns (uint256);\n\n    function count() external view returns (uint256);\n\n    function BASE_WEIGHT() external view returns (uint256);\n\n    function MAX_CYCLE_LIMIT() external view returns (uint256);\n\n    function get(uint256 _fundingCycleId)\n        external\n        view\n        returns (FundingCycle memory);\n\n    function queuedOf(uint256 _projectId)\n        external\n        view\n        returns (FundingCycle memory);\n\n    function currentOf(uint256 _projectId)\n        external\n        view\n        returns (FundingCycle memory);\n\n    function currentBallotStateOf(uint256 _projectId)\n        external\n        view\n        returns (BallotState);\n\n    function configure(\n        uint256 _projectId,\n        FundingCycleProperties calldata _properties,\n        uint256 _metadata,\n        uint256 _fee,\n        bool _configureActiveFundingCycle\n    ) external returns (FundingCycle memory fundingCycle);\n\n    function tap(uint256 _projectId, uint256 _amount)\n        external\n        returns (FundingCycle memory fundingCycle);\n}\n"
    },
    "contracts/interfaces/IYielder.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nimport \"./ITerminalV1.sol\";\n\n// In constructure, give unlimited access for TerminalV1 to take money from this.\ninterface IYielder {\n    function deposited() external view returns (uint256);\n\n    function getCurrentBalance() external view returns (uint256);\n\n    function deposit() external payable;\n\n    function withdraw(uint256 _amount, address payable _beneficiary) external;\n\n    function withdrawAll(address payable _beneficiary)\n        external\n        returns (uint256);\n}\n"
    },
    "contracts/interfaces/IProjects.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport \"./ITerminal.sol\";\nimport \"./IOperatorStore.sol\";\n\ninterface IProjects is IERC721 {\n    event Create(\n        uint256 indexed projectId,\n        address indexed owner,\n        bytes32 indexed handle,\n        string uri,\n        ITerminal terminal,\n        address caller\n    );\n\n    event SetHandle(\n        uint256 indexed projectId,\n        bytes32 indexed handle,\n        address caller\n    );\n\n    event SetUri(uint256 indexed projectId, string uri, address caller);\n\n    event TransferHandle(\n        uint256 indexed projectId,\n        address indexed to,\n        bytes32 indexed handle,\n        bytes32 newHandle,\n        address caller\n    );\n\n    event ClaimHandle(\n        address indexed account,\n        uint256 indexed projectId,\n        bytes32 indexed handle,\n        address caller\n    );\n\n    event ChallengeHandle(\n        bytes32 indexed handle,\n        uint256 challengeExpiry,\n        address caller\n    );\n\n    event RenewHandle(\n        bytes32 indexed handle,\n        uint256 indexed projectId,\n        address caller\n    );\n\n    function count() external view returns (uint256);\n\n    function uriOf(uint256 _projectId) external view returns (string memory);\n\n    function handleOf(uint256 _projectId) external returns (bytes32 handle);\n\n    function projectFor(bytes32 _handle) external returns (uint256 projectId);\n\n    function transferAddressFor(bytes32 _handle)\n        external\n        returns (address receiver);\n\n    function challengeExpiryOf(bytes32 _handle) external returns (uint256);\n\n    function exists(uint256 _projectId) external view returns (bool);\n\n    function create(\n        address _owner,\n        bytes32 _handle,\n        string calldata _uri,\n        ITerminal _terminal\n    ) external returns (uint256 id);\n\n    function setHandle(uint256 _projectId, bytes32 _handle) external;\n\n    function setUri(uint256 _projectId, string calldata _uri) external;\n\n    function transferHandle(\n        uint256 _projectId,\n        address _to,\n        bytes32 _newHandle\n    ) external returns (bytes32 _handle);\n\n    function claimHandle(\n        bytes32 _handle,\n        address _for,\n        uint256 _projectId\n    ) external;\n}\n"
    },
    "contracts/interfaces/IModStore.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./IOperatorStore.sol\";\nimport \"./IProjects.sol\";\nimport \"./IModAllocator.sol\";\n\nstruct PayoutMod {\n    bool preferUnstaked;\n    uint16 percent;\n    uint48 lockedUntil;\n    address payable beneficiary;\n    IModAllocator allocator;\n    uint56 projectId;\n}\n\nstruct TicketMod {\n    bool preferUnstaked;\n    uint16 percent;\n    uint48 lockedUntil;\n    address payable beneficiary;\n}\n\ninterface IModStore {\n    event SetPayoutMod(\n        uint256 indexed projectId,\n        uint256 indexed configuration,\n        PayoutMod mods,\n        address caller\n    );\n\n    event SetTicketMod(\n        uint256 indexed projectId,\n        uint256 indexed configuration,\n        TicketMod mods,\n        address caller\n    );\n\n    function projects() external view returns (IProjects);\n\n    function payoutModsOf(uint256 _projectId, uint256 _configuration)\n        external\n        view\n        returns (PayoutMod[] memory);\n\n    function ticketModsOf(uint256 _projectId, uint256 _configuration)\n        external\n        view\n        returns (TicketMod[] memory);\n\n    function setPayoutMods(\n        uint256 _projectId,\n        uint256 _configuration,\n        PayoutMod[] memory _mods\n    ) external;\n\n    function setTicketMods(\n        uint256 _projectId,\n        uint256 _configuration,\n        TicketMod[] memory _mods\n    ) external;\n}\n"
    },
    "contracts/interfaces/ITerminal.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport './ITerminalDirectory.sol';\n\ninterface ITerminal {\n  function terminalDirectory() external view returns (ITerminalDirectory);\n\n  function migrationIsAllowed(ITerminal _terminal) external view returns (bool);\n\n  function pay(\n    uint256 _projectId,\n    address _beneficiary,\n    string calldata _memo,\n    bool _preferUnstakedTickets\n  ) external payable returns (uint256 fundingCycleId);\n\n  function addToBalance(uint256 _projectId) external payable;\n\n  function allowMigration(ITerminal _contract) external;\n\n  function migrate(uint256 _projectId, ITerminal _to) external;\n}\n"
    },
    "contracts/interfaces/IOperatorStore.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\ninterface IOperatorStore {\n    event SetOperator(\n        address indexed operator,\n        address indexed account,\n        uint256 indexed domain,\n        uint256[] permissionIndexes,\n        uint256 packed\n    );\n\n    function permissionsOf(\n        address _operator,\n        address _account,\n        uint256 _domain\n    ) external view returns (uint256);\n\n    function hasPermission(\n        address _operator,\n        address _account,\n        uint256 _domain,\n        uint256 _permissionIndex\n    ) external view returns (bool);\n\n    function hasPermissions(\n        address _operator,\n        address _account,\n        uint256 _domain,\n        uint256[] calldata _permissionIndexes\n    ) external view returns (bool);\n\n    function setOperator(\n        address _operator,\n        uint256 _domain,\n        uint256[] calldata _permissionIndexes\n    ) external;\n\n    function setOperators(\n        address[] calldata _operators,\n        uint256[] calldata _domains,\n        uint256[][] calldata _permissionIndexes\n    ) external;\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
    },
    "contracts/interfaces/ITickets.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface ITickets is IERC20 {\n    function print(address _account, uint256 _amount) external;\n\n    function redeem(address _account, uint256 _amount) external;\n}\n"
    },
    "contracts/interfaces/ITerminalDirectory.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./IDirectPaymentAddress.sol\";\nimport \"./ITerminal.sol\";\nimport \"./IProjects.sol\";\nimport \"./IProjects.sol\";\n\ninterface ITerminalDirectory {\n    event DeployAddress(\n        uint256 indexed projectId,\n        string memo,\n        address indexed caller\n    );\n\n    event SetTerminal(\n        uint256 indexed projectId,\n        ITerminal indexed terminal,\n        address caller\n    );\n\n    event SetPayerPreferences(\n        address indexed account,\n        address beneficiary,\n        bool preferUnstakedTickets\n    );\n\n    function projects() external view returns (IProjects);\n\n    function terminalOf(uint256 _projectId) external view returns (ITerminal);\n\n    function beneficiaryOf(address _account) external returns (address);\n\n    function unstakedTicketsPreferenceOf(address _account)\n        external\n        returns (bool);\n\n    function addressesOf(uint256 _projectId)\n        external\n        view\n        returns (IDirectPaymentAddress[] memory);\n\n    function deployAddress(uint256 _projectId, string calldata _memo) external;\n\n    function setTerminal(uint256 _projectId, ITerminal _terminal) external;\n\n    function setPayerPreferences(\n        address _beneficiary,\n        bool _preferUnstakedTickets\n    ) external;\n}\n"
    },
    "contracts/interfaces/IDirectPaymentAddress.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./ITerminalDirectory.sol\";\nimport \"./ITerminal.sol\";\n\ninterface IDirectPaymentAddress {\n    event Forward(\n        address indexed payer,\n        uint256 indexed projectId,\n        address beneficiary,\n        uint256 value,\n        string memo,\n        bool preferUnstakedTickets\n    );\n\n    function terminalDirectory() external returns (ITerminalDirectory);\n\n    function projectId() external returns (uint256);\n\n    function memo() external returns (string memory);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\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 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 `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n\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"
    },
    "contracts/interfaces/IPrices.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol\";\n\ninterface IPrices {\n    event AddFeed(uint256 indexed currency, AggregatorV3Interface indexed feed);\n\n    function feedDecimalAdjuster(uint256 _currency) external returns (uint256);\n\n    function targetDecimals() external returns (uint256);\n\n    function feedFor(uint256 _currency)\n        external\n        returns (AggregatorV3Interface);\n\n    function getETHPriceFor(uint256 _currency) external view returns (uint256);\n\n    function addFeed(AggregatorV3Interface _priceFeed, uint256 _currency)\n        external;\n}\n"
    },
    "contracts/interfaces/IFundingCycleBallot.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./ITerminalV1.sol\";\n\nenum BallotState {\n    Approved,\n    Active,\n    Failed,\n    Standby\n}\n\ninterface IFundingCycleBallot {\n    function duration() external view returns (uint256);\n\n    function state(uint256 _fundingCycleId, uint256 _configured)\n        external\n        view\n        returns (BallotState);\n}\n"
    },
    "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.6.0;\n\ninterface AggregatorV3Interface {\n\n  function decimals() external view returns (uint8);\n  function description() external view returns (string memory);\n  function version() external view returns (uint256);\n\n  // getRoundData and latestRoundData should both raise \"No data present\"\n  // if they do not have data to report, instead of returning unset values\n  // which could be misinterpreted as actual reported values.\n  function getRoundData(uint80 _roundId)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n  function latestRoundData()\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n}\n"
    },
    "contracts/interfaces/IModAllocator.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\ninterface IModAllocator {\n    event Allocate(\n        uint256 indexed projectId,\n        uint256 indexed forProjectId,\n        address indexed beneficiary,\n        uint256 amount,\n        address caller\n    );\n\n    function allocate(\n        uint256 _projectId,\n        uint256 _forProjectId,\n        address _beneficiary\n    ) external payable;\n}\n"
    },
    "contracts/TerminalV1.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport '@openzeppelin/contracts/utils/Address.sol';\n\nimport '@paulrberg/contracts/math/PRBMath.sol';\nimport '@paulrberg/contracts/math/PRBMathUD60x18.sol';\n\nimport './interfaces/ITerminalV1.sol';\nimport './abstract/JuiceboxProject.sol';\nimport './abstract/Operatable.sol';\n\nimport './libraries/Operations.sol';\n\n/**\n  ─────────────────────────────────────────────────────────────────────────────────────────────────\n  ─────────██████──███████──██████──██████████──██████████████──██████████████──████████████████───\n  ─────────██░░██──███░░██──██░░██──██░░░░░░██──██░░░░░░░░░░██──██░░░░░░░░░░██──██░░░░░░░░░░░░██───\n  ─────────██░░██──███░░██──██░░██──████░░████──██░░██████████──██░░██████████──██░░████████░░██───\n  ─────────██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██──────────██░░██────██░░██───\n  ─────────██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██████████──██░░████████░░██───\n  ─────────██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░░░░░░░░░██──██░░░░░░░░░░░░██───\n  ─██████──██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██████████──██░░██████░░████───\n  ─██░░██──██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██──────────██░░██──██░░██─────\n  ─██░░██████░░██──███░░██████░░██──████░░████──██░░██████████──██░░██████████──██░░██──██░░██████─\n  ─██░░░░░░░░░░██──███░░░░░░░░░░██──██░░░░░░██──██░░░░░░░░░░██──██░░░░░░░░░░██──██░░██──██░░░░░░██─\n  ─██████████████──███████████████──██████████──██████████████──██████████████──██████──██████████─\n  ───────────────────────────────────────────────────────────────────────────────────────────\n\n  @notice \n  This contract manages the Juicebox ecosystem, serves as a payment terminal, and custodies all funds.\n\n  @dev \n  A project can transfer its funds, along with the power to reconfigure and mint/burn their Tickets, from this contract to another allowed terminal contract at any time.\n*/\ncontract TerminalV1 is Operatable, ITerminalV1, ITerminal, ReentrancyGuard {\n  // Modifier to only allow governance to call the function.\n  modifier onlyGov() {\n    require(msg.sender == governance, 'TerminalV1: UNAUTHORIZED');\n    _;\n  }\n\n  // --- private stored properties --- //\n\n  // The difference between the processed ticket tracker of a project and the project's ticket's total supply is the amount of tickets that\n  // still need to have reserves printed against them.\n  mapping(uint256 => int256) private _processedTicketTrackerOf;\n\n  // The amount of ticket printed prior to a project configuring their first funding cycle.\n  mapping(uint256 => uint256) private _preconfigureTicketCountOf;\n\n  // --- public immutable stored properties --- //\n\n  /// @notice The Projects contract which mints ERC-721's that represent project ownership and transfers.\n  IProjects public immutable override projects;\n\n  /// @notice The contract storing all funding cycle configurations.\n  IFundingCycles public immutable override fundingCycles;\n\n  /// @notice The contract that manages Ticket printing and redeeming.\n  ITicketBooth public immutable override ticketBooth;\n\n  /// @notice The contract that stores mods for each project.\n  IModStore public immutable override modStore;\n\n  /// @notice The prices feeds.\n  IPrices public immutable override prices;\n\n  /// @notice The directory of terminals.\n  ITerminalDirectory public immutable override terminalDirectory;\n\n  // --- public stored properties --- //\n\n  /// @notice The amount of ETH that each project is responsible for.\n  mapping(uint256 => uint256) public override balanceOf;\n\n  /// @notice The percent fee the Juicebox project takes from tapped amounts. Out of 200.\n  uint256 public override fee = 10;\n\n  /// @notice The governance of the contract who makes fees and can allow new TerminalV1 contracts to be migrated to by project owners.\n  address payable public override governance;\n\n  /// @notice The governance of the contract who makes fees and can allow new TerminalV1 contracts to be migrated to by project owners.\n  address payable public override pendingGovernance;\n\n  // Whether or not a particular contract is available for projects to migrate their funds and Tickets to.\n  mapping(ITerminal => bool) public override migrationIsAllowed;\n\n  // --- external views --- //\n\n  /** \n      @notice \n      Gets the current overflowed amount for a specified project.\n\n      @param _projectId The ID of the project to get overflow for.\n\n      @return overflow The current overflow of funds for the project.\n    */\n  function currentOverflowOf(uint256 _projectId) external view override returns (uint256 overflow) {\n    // Get a reference to the project's current funding cycle.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // There's no overflow if there's no funding cycle.\n    if (_fundingCycle.id == 0) return 0;\n\n    return _overflowFrom(_fundingCycle);\n  }\n\n  /** \n      @notice \n      Gets the amount of reserved tickets that a project has.\n\n      @param _projectId The ID of the project to get overflow for.\n      @param _reservedRate The reserved rate to use to make the calculation.\n\n      @return amount overflow The current overflow of funds for the project.\n    */\n  function reservedTicketBalanceOf(uint256 _projectId, uint256 _reservedRate)\n    external\n    view\n    override\n    returns (uint256)\n  {\n    return\n      _reservedTicketAmountFrom(\n        _processedTicketTrackerOf[_projectId],\n        _reservedRate,\n        ticketBooth.totalSupplyOf(_projectId)\n      );\n  }\n\n  // --- public views --- //\n\n  /**\n      @notice \n      The amount of tokens that can be claimed by the given address.\n\n      @dev The _account must have at least _count tickets for the specified project.\n      @dev If there is a funding cycle reconfiguration ballot open for the project, the project's current bonding curve is bypassed.\n\n      @param _account The address to get an amount for.\n      @param _projectId The ID of the project to get a claimable amount for.\n      @param _count The number of Tickets that would be redeemed to get the resulting amount.\n\n      @return amount The amount of tokens that can be claimed.\n    */\n  function claimableOverflowOf(\n    address _account,\n    uint256 _projectId,\n    uint256 _count\n  ) public view override returns (uint256) {\n    // The holder must have the specified number of the project's tickets.\n    require(\n      ticketBooth.balanceOf(_account, _projectId) >= _count,\n      'TerminalV1::claimableOverflow: INSUFFICIENT_TICKETS'\n    );\n\n    // Get a reference to the current funding cycle for the project.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // There's no overflow if there's no funding cycle.\n    if (_fundingCycle.id == 0) return 0;\n\n    // Get the amount of current overflow.\n    uint256 _currentOverflow = _overflowFrom(_fundingCycle);\n\n    // If there is no overflow, nothing is claimable.\n    if (_currentOverflow == 0) return 0;\n\n    // Get the total number of tickets in circulation.\n    uint256 _totalSupply = ticketBooth.totalSupplyOf(_projectId);\n\n    // Get the number of reserved tickets the project has.\n    // The reserved rate is in bits 8-15 of the metadata.\n    uint256 _reservedTicketAmount = _reservedTicketAmountFrom(\n      _processedTicketTrackerOf[_projectId],\n      uint256(uint8(_fundingCycle.metadata >> 8)),\n      _totalSupply\n    );\n\n    // If there are reserved tickets, add them to the total supply.\n    if (_reservedTicketAmount > 0) _totalSupply = _totalSupply + _reservedTicketAmount;\n\n    // If the amount being redeemed is the the total supply, return the rest of the overflow.\n    if (_count == _totalSupply) return _currentOverflow;\n\n    // Get a reference to the linear proportion.\n    uint256 _base = PRBMath.mulDiv(_currentOverflow, _count, _totalSupply);\n\n    // Use the reconfiguration bonding curve if the queued cycle is pending approval according to the previous funding cycle's ballot.\n    uint256 _bondingCurveRate = fundingCycles.currentBallotStateOf(_projectId) == BallotState.Active // The reconfiguration bonding curve rate is stored in bytes 24-31 of the metadata property.\n      ? uint256(uint8(_fundingCycle.metadata >> 24)) // The bonding curve rate is stored in bytes 16-23 of the data property after.\n      : uint256(uint8(_fundingCycle.metadata >> 16));\n\n    // The bonding curve formula.\n    // https://www.desmos.com/calculator/sp9ru6zbpk\n    // where x is _count, o is _currentOverflow, s is _totalSupply, and r is _bondingCurveRate.\n\n    // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n    if (_bondingCurveRate == 200) return _base;\n    if (_bondingCurveRate == 0) return PRBMath.mulDiv(_base, _count, _totalSupply);\n    return\n      PRBMath.mulDiv(\n        _base,\n        _bondingCurveRate + PRBMath.mulDiv(_count, 200 - _bondingCurveRate, _totalSupply),\n        200\n      );\n  }\n\n  /**\n      @notice\n      Whether or not a project can still print premined tickets.\n\n      @param _projectId The ID of the project to get the status of.\n\n      @return Boolean flag.\n    */\n  function canPrintPreminedTickets(uint256 _projectId) public view override returns (bool) {\n    return\n      // The total supply of tickets must equal the preconfigured ticket count.\n      ticketBooth.totalSupplyOf(_projectId) == _preconfigureTicketCountOf[_projectId] &&\n      // The above condition is still possible after post-configured tickets have been printed due to ticket redeeming.\n      // The only case when processedTicketTracker is 0 is before redeeming and printing reserved tickets.\n      _processedTicketTrackerOf[_projectId] >= 0 &&\n      uint256(_processedTicketTrackerOf[_projectId]) == _preconfigureTicketCountOf[_projectId];\n  }\n\n  // --- external transactions --- //\n\n  /** \n      @param _projects A Projects contract which mints ERC-721's that represent project ownership and transfers.\n      @param _fundingCycles A funding cycle configuration store.\n      @param _ticketBooth A contract that manages Ticket printing and redeeming.\n      @param _operatorStore A contract storing operator assignments.\n      @param _modStore A storage for a project's mods.\n      @param _prices A price feed contract to use.\n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n  constructor(\n    IProjects _projects,\n    IFundingCycles _fundingCycles,\n    ITicketBooth _ticketBooth,\n    IOperatorStore _operatorStore,\n    IModStore _modStore,\n    IPrices _prices,\n    ITerminalDirectory _terminalDirectory,\n    address payable _governance\n  ) Operatable(_operatorStore) {\n    require(\n      _projects != IProjects(address(0)) &&\n        _fundingCycles != IFundingCycles(address(0)) &&\n        _ticketBooth != ITicketBooth(address(0)) &&\n        _modStore != IModStore(address(0)) &&\n        _prices != IPrices(address(0)) &&\n        _terminalDirectory != ITerminalDirectory(address(0)) &&\n        _governance != address(address(0)),\n      'TerminalV1: ZERO_ADDRESS'\n    );\n    projects = _projects;\n    fundingCycles = _fundingCycles;\n    ticketBooth = _ticketBooth;\n    modStore = _modStore;\n    prices = _prices;\n    terminalDirectory = _terminalDirectory;\n    governance = _governance;\n  }\n\n  /**\n      @notice \n      Deploys a project. This will mint an ERC-721 into the `_owner`'s account, configure a first funding cycle, and set up any mods.\n\n      @dev\n      Each operation withing this transaction can be done in sequence separately.\n\n      @dev\n      Anyone can deploy a project on an owner's behalf.\n\n      @param _owner The address that will own the project.\n      @param _handle The project's unique handle.\n      @param _uri A link to information about the project and this funding cycle.\n      @param _properties The funding cycle configuration.\n        @dev _properties.target The amount that the project wants to receive in this funding cycle. Sent as a wad.\n        @dev _properties.currency The currency of the `target`. Send 0 for ETH or 1 for USD.\n        @dev _properties.duration The duration of the funding stage for which the `target` amount is needed. Measured in days. Send 0 for a boundless cycle reconfigurable at any time.\n        @dev _properties.cycleLimit The number of cycles that this configuration should last for before going back to the last permanent. This has no effect for a project's first funding cycle.\n        @dev _properties.discountRate A number from 0-200 indicating how valuable a contribution to this funding stage is compared to the project's previous funding stage.\n          If it's 200, each funding stage will have equal weight.\n          If the number is 180, a contribution to the next funding stage will only give you 90% of tickets given to a contribution of the same amount during the current funding stage.\n          If the number is 0, an non-recurring funding stage will get made.\n        @dev _properties.ballot The new ballot that will be used to approve subsequent reconfigurations.\n      @param _metadata A struct specifying the TerminalV1 specific params _bondingCurveRate, and _reservedRate.\n        @dev _metadata.reservedRate A number from 0-200 indicating the percentage of each contribution's tickets that will be reserved for the project owner.\n        @dev _metadata.bondingCurveRate The rate from 0-200 at which a project's Tickets can be redeemed for surplus.\n          The bonding curve formula is https://www.desmos.com/calculator/sp9ru6zbpk\n          where x is _count, o is _currentOverflow, s is _totalSupply, and r is _bondingCurveRate.\n        @dev _metadata.reconfigurationBondingCurveRate The bonding curve rate to apply when there is an active ballot.\n      @param _payoutMods Any payout mods to set.\n      @param _ticketMods Any ticket mods to set.\n    */\n  function deploy(\n    address _owner,\n    bytes32 _handle,\n    string calldata _uri,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  ) external override {\n    // Make sure the metadata checks out. If it does, return a packed version of it.\n    uint256 _packedMetadata = _validateAndPackFundingCycleMetadata(_metadata);\n\n    // Create the project for the owner.\n    uint256 _projectId = projects.create(_owner, _handle, _uri, this);\n\n    // Configure the funding stage's state.\n    FundingCycle memory _fundingCycle = fundingCycles.configure(\n      _projectId,\n      _properties,\n      _packedMetadata,\n      fee,\n      true\n    );\n\n    // Set payout mods if there are any.\n    if (_payoutMods.length > 0)\n      modStore.setPayoutMods(_projectId, _fundingCycle.configured, _payoutMods);\n\n    // Set ticket mods if there are any.\n    if (_ticketMods.length > 0)\n      modStore.setTicketMods(_projectId, _fundingCycle.configured, _ticketMods);\n  }\n\n  /**\n      @notice \n      Configures the properties of the current funding cycle if the project hasn't distributed tickets yet, or\n      sets the properties of the proposed funding cycle that will take effect once the current one expires\n      if it is approved by the current funding cycle's ballot.\n\n      @dev\n      Only a project's owner or a designated operator can configure its funding cycles.\n\n      @param _projectId The ID of the project being reconfigured. \n      @param _properties The funding cycle configuration.\n        @dev _properties.target The amount that the project wants to receive in this funding stage. Sent as a wad.\n        @dev _properties.currency The currency of the `target`. Send 0 for ETH or 1 for USD.\n        @dev _properties.duration The duration of the funding stage for which the `target` amount is needed. Measured in days. Send 0 for a boundless cycle reconfigurable at any time.\n        @dev _properties.cycleLimit The number of cycles that this configuration should last for before going back to the last permanent. This has no effect for a project's first funding cycle.\n        @dev _properties.discountRate A number from 0-200 indicating how valuable a contribution to this funding stage is compared to the project's previous funding stage.\n          If it's 200, each funding stage will have equal weight.\n          If the number is 180, a contribution to the next funding stage will only give you 90% of tickets given to a contribution of the same amount during the current funding stage.\n          If the number is 0, an non-recurring funding stage will get made.\n        @dev _properties.ballot The new ballot that will be used to approve subsequent reconfigurations.\n      @param _metadata A struct specifying the TerminalV1 specific params _bondingCurveRate, and _reservedRate.\n        @dev _metadata.reservedRate A number from 0-200 indicating the percentage of each contribution's tickets that will be reserved for the project owner.\n        @dev _metadata.bondingCurveRate The rate from 0-200 at which a project's Tickets can be redeemed for surplus.\n          The bonding curve formula is https://www.desmos.com/calculator/sp9ru6zbpk\n          where x is _count, o is _currentOverflow, s is _totalSupply, and r is _bondingCurveRate.\n        @dev _metadata.reconfigurationBondingCurveRate The bonding curve rate to apply when there is an active ballot.\n\n      @return The ID of the funding cycle that was successfully configured.\n    */\n  function configure(\n    uint256 _projectId,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  )\n    external\n    override\n    requirePermission(projects.ownerOf(_projectId), _projectId, Operations.Configure)\n    returns (uint256)\n  {\n    // Make sure the metadata is validated, and pack it into a uint256.\n    uint256 _packedMetadata = _validateAndPackFundingCycleMetadata(_metadata);\n\n    // If the project can still print premined tickets configure the active funding cycle instead of creating a standby one.\n    bool _shouldConfigureActive = canPrintPreminedTickets(_projectId);\n\n    // Configure the funding stage's state.\n    FundingCycle memory _fundingCycle = fundingCycles.configure(\n      _projectId,\n      _properties,\n      _packedMetadata,\n      fee,\n      _shouldConfigureActive\n    );\n\n    // Set payout mods for the new configuration if there are any.\n    if (_payoutMods.length > 0)\n      modStore.setPayoutMods(_projectId, _fundingCycle.configured, _payoutMods);\n\n    // Set payout mods for the new configuration if there are any.\n    if (_ticketMods.length > 0)\n      modStore.setTicketMods(_projectId, _fundingCycle.configured, _ticketMods);\n\n    return _fundingCycle.id;\n  }\n\n  /** \n      @notice \n      Allows a project to print tickets for a specified beneficiary before payments have been received.\n\n      @dev \n      This can only be done if the project hasn't yet received a payment after configuring a funding cycle.\n\n      @dev\n      Only a project's owner or a designated operator can print premined tickets.\n\n      @param _projectId The ID of the project to premine tickets for.\n      @param _amount The amount to base the ticket premine off of.\n      @param _currency The currency of the amount to base the ticket premine off of. \n      @param _beneficiary The address to send the printed tickets to.\n      @param _memo A memo to leave with the printing.\n      @param _preferUnstakedTickets If there is a preference to unstake the printed tickets.\n    */\n  function printPreminedTickets(\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _currency,\n    address _beneficiary,\n    string memory _memo,\n    bool _preferUnstakedTickets\n  )\n    external\n    override\n    requirePermission(projects.ownerOf(_projectId), _projectId, Operations.PrintPreminedTickets)\n  {\n    // Can't send to the zero address.\n    require(_beneficiary != address(0), 'TerminalV1::printTickets: ZERO_ADDRESS');\n\n    // Get the current funding cycle to read the weight and currency from.\n    uint256 _weight = fundingCycles.BASE_WEIGHT();\n\n    // Get the current funding cycle to read the weight and currency from.\n    // Get the currency price of ETH.\n    uint256 _ethPrice = prices.getETHPriceFor(_currency);\n\n    // Multiply the amount by the funding cycle's weight to determine the amount of tickets to print.\n    uint256 _weightedAmount = PRBMathUD60x18.mul(PRBMathUD60x18.div(_amount, _ethPrice), _weight);\n\n    // Make sure the project hasnt printed tickets that werent preconfigure.\n    // Do this check after the external calls above.\n    require(canPrintPreminedTickets(_projectId), 'TerminalV1::printTickets: ALREADY_ACTIVE');\n\n    // Set the preconfigure tickets as processed so that reserved tickets cant be minted against them.\n    // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n    require(\n      _processedTicketTrackerOf[_projectId] < 0 ||\n        uint256(_processedTicketTrackerOf[_projectId]) + uint256(_weightedAmount) <=\n        uint256(type(int256).max),\n      'TerminalV1::printTickets: INT_LIMIT_REACHED'\n    );\n\n    _processedTicketTrackerOf[_projectId] =\n      _processedTicketTrackerOf[_projectId] +\n      int256(_weightedAmount);\n\n    // Set the count of preconfigure tickets this project has printed.\n    _preconfigureTicketCountOf[_projectId] =\n      _preconfigureTicketCountOf[_projectId] +\n      _weightedAmount;\n\n    // Print the project's tickets for the beneficiary.\n    ticketBooth.print(_beneficiary, _projectId, _weightedAmount, _preferUnstakedTickets);\n\n    emit PrintPreminedTickets(_projectId, _beneficiary, _amount, _currency, _memo, msg.sender);\n  }\n\n  /**\n      @notice \n      Contribute ETH to a project.\n\n      @dev \n      Print's the project's tickets proportional to the amount of the contribution.\n\n      @dev \n      The msg.value is the amount of the contribution in wei.\n\n      @param _projectId The ID of the project being contribute to.\n      @param _beneficiary The address to print Tickets for. \n      @param _memo A memo that will be included in the published event.\n      @param _preferUnstakedTickets Whether ERC20's should be unstaked automatically if they have been issued.\n\n      @return The ID of the funding cycle that the payment was made during.\n    */\n  function pay(\n    uint256 _projectId,\n    address _beneficiary,\n    string calldata _memo,\n    bool _preferUnstakedTickets\n  ) external payable override returns (uint256) {\n    // Positive payments only.\n    require(msg.value > 0, 'TerminalV1::pay: BAD_AMOUNT');\n\n    // Cant send tickets to the zero address.\n    require(_beneficiary != address(0), 'TerminalV1::pay: ZERO_ADDRESS');\n\n    return _pay(_projectId, msg.value, _beneficiary, _memo, _preferUnstakedTickets);\n  }\n\n  /**\n      @notice \n      Tap into funds that have been contributed to a project's current funding cycle.\n\n      @dev\n      Anyone can tap funds on a project's behalf.\n\n      @param _projectId The ID of the project to which the funding cycle being tapped belongs.\n      @param _amount The amount being tapped, in the funding cycle's currency.\n      @param _currency The expected currency being tapped.\n      @param _minReturnedWei The minimum number of wei that the amount should be valued at.\n\n      @return The ID of the funding cycle that was tapped.\n    */\n  function tap(\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _currency,\n    uint256 _minReturnedWei\n  ) external override nonReentrant returns (uint256) {\n    // Register the funds as tapped. Get the ID of the funding cycle that was tapped.\n    FundingCycle memory _fundingCycle = fundingCycles.tap(_projectId, _amount);\n\n    // If there's no funding cycle, there are no funds to tap.\n    if (_fundingCycle.id == 0) return 0;\n\n    // Make sure the currency's match.\n    require(_currency == _fundingCycle.currency, 'TerminalV1::tap: UNEXPECTED_CURRENCY');\n\n    // Get a reference to this project's current balance, including any earned yield.\n    // Get the currency price of ETH.\n    uint256 _ethPrice = prices.getETHPriceFor(_fundingCycle.currency);\n\n    // Get the price of ETH.\n    // The amount of ETH that is being tapped.\n    uint256 _tappedWeiAmount = PRBMathUD60x18.div(_amount, _ethPrice);\n\n    // The amount being tapped must be at least as much as was expected.\n    require(_minReturnedWei <= _tappedWeiAmount, 'TerminalV1::tap: INADEQUATE');\n\n    // Get a reference to this project's current balance, including any earned yield.\n    uint256 _balance = balanceOf[_fundingCycle.projectId];\n\n    // The amount being tapped must be available.\n    require(_tappedWeiAmount <= _balance, 'TerminalV1::tap: INSUFFICIENT_FUNDS');\n\n    // Removed the tapped funds from the project's balance.\n    balanceOf[_projectId] = _balance - _tappedWeiAmount;\n\n    // Get a reference to the project owner, which will receive the admin's tickets from paying the fee,\n    // and receive any extra tapped funds not allocated to mods.\n    address payable _projectOwner = payable(projects.ownerOf(_fundingCycle.projectId));\n\n    // Get a reference to the handle of the project paying the fee and sending payouts.\n    bytes32 _handle = projects.handleOf(_projectId);\n\n    // Take a fee from the _tappedWeiAmount, if needed.\n    // The project's owner will be the beneficiary of the resulting printed tickets from the governance project.\n    uint256 _feeAmount = _fundingCycle.fee > 0\n      ? _takeFee(\n        _tappedWeiAmount,\n        _fundingCycle.fee,\n        _projectOwner,\n        string(bytes.concat('Fee from @', _handle))\n      )\n      : 0;\n\n    // Payout to mods and get a reference to the leftover transfer amount after all mods have been paid.\n    // The net transfer amount is the tapped amount minus the fee.\n    uint256 _leftoverTransferAmount = _distributeToPayoutMods(\n      _fundingCycle,\n      _tappedWeiAmount - _feeAmount,\n      string(bytes.concat('Payout from @', _handle))\n    );\n\n    // Transfer any remaining balance to the beneficiary.\n    if (_leftoverTransferAmount > 0) Address.sendValue(_projectOwner, _leftoverTransferAmount);\n\n    emit Tap(\n      _fundingCycle.id,\n      _fundingCycle.projectId,\n      _projectOwner,\n      _amount,\n      _fundingCycle.currency,\n      _tappedWeiAmount - _feeAmount,\n      _leftoverTransferAmount,\n      _feeAmount,\n      msg.sender\n    );\n\n    return _fundingCycle.id;\n  }\n\n  /**\n      @notice \n      Addresses can redeem their Tickets to claim the project's overflowed ETH.\n\n      @dev\n      Only a ticket's holder or a designated operator can redeem it.\n\n      @param _account The account to redeem tickets for.\n      @param _projectId The ID of the project to which the Tickets being redeemed belong.\n      @param _count The number of Tickets to redeem.\n      @param _minReturnedWei The minimum amount of Wei expected in return.\n      @param _beneficiary The address to send the ETH to.\n      @param _preferUnstaked If the preference is to redeem tickets that have been converted to ERC-20s.\n\n      @return amount The amount of ETH that the tickets were redeemed for.\n    */\n  function redeem(\n    address _account,\n    uint256 _projectId,\n    uint256 _count,\n    uint256 _minReturnedWei,\n    address payable _beneficiary,\n    bool _preferUnstaked\n  )\n    external\n    override\n    nonReentrant\n    requirePermissionAllowingWildcardDomain(_account, _projectId, Operations.Redeem)\n    returns (uint256 amount)\n  {\n    // There must be an amount specified to redeem.\n    require(_count > 0, 'TerminalV1::redeem: NO_OP');\n\n    // Can't send claimed funds to the zero address.\n    require(_beneficiary != address(0), 'TerminalV1::redeem: ZERO_ADDRESS');\n\n    // The amount of ETH claimable by the message sender from the specified project by redeeming the specified number of tickets.\n    amount = claimableOverflowOf(_account, _projectId, _count);\n\n    // Nothing to do if the amount is 0.\n    require(amount > 0, 'TerminalV1::redeem: NO_OP');\n\n    // The amount being claimed must be at least as much as was expected.\n    require(amount >= _minReturnedWei, 'TerminalV1::redeem: INADEQUATE');\n\n    // Remove the redeemed funds from the project's balance.\n    balanceOf[_projectId] = balanceOf[_projectId] - amount;\n\n    // Get a reference to the processed ticket tracker for the project.\n    int256 _processedTicketTracker = _processedTicketTrackerOf[_projectId];\n\n    // Subtract the count from the processed ticket tracker.\n    // Subtract from processed tickets so that the difference between whats been processed and the\n    // total supply remains the same.\n    // If there are at least as many processed tickets as there are tickets being redeemed,\n    // the processed ticket tracker of the project will be positive. Otherwise it will be negative.\n    _processedTicketTrackerOf[_projectId] = _processedTicketTracker < 0 // If the tracker is negative, add the count and reverse it.\n      ? -int256(uint256(-_processedTicketTracker) + _count) // the tracker is less than the count, subtract it from the count and reverse it.\n      : _processedTicketTracker < int256(_count)\n      ? -(int256(_count) - _processedTicketTracker) // simply subtract otherwise.\n      : _processedTicketTracker - int256(_count);\n\n    // Redeem the tickets, which burns them.\n    ticketBooth.redeem(_account, _projectId, _count, _preferUnstaked);\n\n    // Transfer funds to the specified address.\n    Address.sendValue(_beneficiary, amount);\n\n    emit Redeem(_account, _beneficiary, _projectId, _count, amount, msg.sender);\n  }\n\n  /**\n      @notice \n      Allows a project owner to migrate its funds and operations to a new contract.\n\n      @dev\n      Only a project's owner or a designated operator can migrate it.\n\n      @param _projectId The ID of the project being migrated.\n      @param _to The contract that will gain the project's funds.\n    */\n  function migrate(uint256 _projectId, ITerminal _to)\n    external\n    override\n    requirePermission(projects.ownerOf(_projectId), _projectId, Operations.Migrate)\n    nonReentrant\n  {\n    // This TerminalV1 must be the project's current terminal.\n    require(terminalDirectory.terminalOf(_projectId) == this, 'TerminalV1::migrate: UNAUTHORIZED');\n\n    // The migration destination must be allowed.\n    require(migrationIsAllowed[_to], 'TerminalV1::migrate: NOT_ALLOWED');\n\n    // All reserved tickets must be printed before migrating.\n    if (uint256(_processedTicketTrackerOf[_projectId]) != ticketBooth.totalSupplyOf(_projectId))\n      printReservedTickets(_projectId);\n\n    // Get a reference to this project's current balance, included any earned yield.\n    uint256 _balanceOf = balanceOf[_projectId];\n\n    // Set the balance to 0.\n    balanceOf[_projectId] = 0;\n\n    // Move the funds to the new contract if needed.\n    if (_balanceOf > 0) _to.addToBalance{value: _balanceOf}(_projectId);\n\n    // Switch the direct payment terminal.\n    terminalDirectory.setTerminal(_projectId, _to);\n\n    emit Migrate(_projectId, _to, _balanceOf, msg.sender);\n  }\n\n  /** \n      @notice \n      Receives and allocates funds belonging to the specified project.\n\n      @param _projectId The ID of the project to which the funds received belong.\n    */\n  function addToBalance(uint256 _projectId) external payable override {\n    // The amount must be positive.\n    require(msg.value > 0, 'TerminalV1::addToBalance: BAD_AMOUNT');\n    balanceOf[_projectId] = balanceOf[_projectId] + msg.value;\n    emit AddToBalance(_projectId, msg.value, msg.sender);\n  }\n\n  /**\n      @notice \n      Adds to the contract addresses that projects can migrate their Tickets to.\n\n      @dev\n      Only governance can add a contract to the migration allow list.\n\n      @param _contract The contract to allow.\n    */\n  function allowMigration(ITerminal _contract) external override onlyGov {\n    // Can't allow the zero address.\n    require(_contract != ITerminal(address(0)), 'TerminalV1::allowMigration: ZERO_ADDRESS');\n\n    // Can't migrate to this same contract\n    require(_contract != this, 'TerminalV1::allowMigration: NO_OP');\n\n    // Set the contract as allowed\n    migrationIsAllowed[_contract] = true;\n\n    emit AllowMigration(_contract);\n  }\n\n  /** \n      @notice \n      Allow the admin to change the fee. \n\n      @dev\n      Only funding cycle reconfigurations after the new fee is set will use the new fee.\n      All future funding cycles based on configurations made in the past will use the fee that was set at the time of the configuration.\n    \n      @dev\n      Only governance can set a new fee.\n\n      @param _fee The new fee percent. Out of 200.\n    */\n  function setFee(uint256 _fee) external override onlyGov {\n    // Fee must be under 100%.\n    require(_fee <= 200, 'TerminalV1::setFee: BAD_FEE');\n\n    // Set the fee.\n    fee = _fee;\n\n    emit SetFee(_fee);\n  }\n\n  /** \n      @notice \n      Allows governance to transfer its privileges to another contract.\n\n      @dev\n      Only the currency governance can appoint a new governance.\n\n      @param _pendingGovernance The governance to transition power to. \n        @dev This address will have to accept the responsibility in a subsequent transaction.\n    */\n  function appointGovernance(address payable _pendingGovernance) external override onlyGov {\n    // The new governance can't be the zero address.\n    require(_pendingGovernance != address(0), 'TerminalV1::appointGovernance: ZERO_ADDRESS');\n    // The new governance can't be the same as the current governance.\n    require(_pendingGovernance != governance, 'TerminalV1::appointGovernance: NO_OP');\n\n    // Set the appointed governance as pending.\n    pendingGovernance = _pendingGovernance;\n\n    emit AppointGovernance(_pendingGovernance);\n  }\n\n  /** \n      @notice \n      Allows contract to accept its appointment as the new governance.\n    */\n  function acceptGovernance() external override {\n    // Only the pending governance address can accept.\n    require(msg.sender == pendingGovernance, 'TerminalV1::acceptGovernance: UNAUTHORIZED');\n\n    // Get a reference to the pending governance.\n    address payable _pendingGovernance = pendingGovernance;\n\n    // Set the govenance to the pending value.\n    governance = _pendingGovernance;\n\n    emit AcceptGovernance(_pendingGovernance);\n  }\n\n  // --- public transactions --- //\n\n  /**\n      @notice \n      Prints all reserved tickets for a project.\n\n      @param _projectId The ID of the project to which the reserved tickets belong.\n\n      @return amount The amount of tickets that are being printed.\n    */\n  function printReservedTickets(uint256 _projectId) public override returns (uint256 amount) {\n    // Get the current funding cycle to read the reserved rate from.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // If there's no funding cycle, there's no reserved tickets to print.\n    if (_fundingCycle.id == 0) return 0;\n\n    // Get a reference to new total supply of tickets before printing reserved tickets.\n    uint256 _totalTickets = ticketBooth.totalSupplyOf(_projectId);\n\n    // Get a reference to the number of tickets that need to be printed.\n    // If there's no funding cycle, there's no tickets to print.\n    // The reserved rate is in bits 8-15 of the metadata.\n    amount = _reservedTicketAmountFrom(\n      _processedTicketTrackerOf[_projectId],\n      uint256(uint8(_fundingCycle.metadata >> 8)),\n      _totalTickets\n    );\n\n    // If there's nothing to print, return.\n    if (amount == 0) return amount;\n\n    // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n    require(\n      _totalTickets + amount <= uint256(type(int256).max),\n      'TerminalV1::printReservedTickets: INT_LIMIT_REACHED'\n    );\n\n    // Set the tracker to be the new total supply.\n    _processedTicketTrackerOf[_projectId] = int256(_totalTickets + amount);\n\n    // Distribute tickets to mods and get a reference to the leftover amount to print after all mods have had their share printed.\n    uint256 _leftoverTicketAmount = _distributeToTicketMods(_fundingCycle, amount);\n\n    // Get a reference to the project owner.\n    address _owner = projects.ownerOf(_projectId);\n\n    // Print any remaining reserved tickets to the owner.\n    if (_leftoverTicketAmount > 0)\n      ticketBooth.print(_owner, _projectId, _leftoverTicketAmount, false);\n\n    emit PrintReserveTickets(\n      _fundingCycle.id,\n      _projectId,\n      _owner,\n      amount,\n      _leftoverTicketAmount,\n      msg.sender\n    );\n  }\n\n  // --- private helper functions --- //\n\n  /** \n      @notice\n      Pays out the mods for the specified funding cycle.\n\n      @param _fundingCycle The funding cycle to base the distribution on.\n      @param _amount The total amount being paid out.\n      @param _memo A memo to send along with project payouts.\n\n      @return leftoverAmount If the mod percents dont add up to 100%, the leftover amount is returned.\n\n    */\n  function _distributeToPayoutMods(\n    FundingCycle memory _fundingCycle,\n    uint256 _amount,\n    string memory _memo\n  ) private returns (uint256 leftoverAmount) {\n    // Set the leftover amount to the initial amount.\n    leftoverAmount = _amount;\n\n    // Get a reference to the project's payout mods.\n    PayoutMod[] memory _mods = modStore.payoutModsOf(\n      _fundingCycle.projectId,\n      _fundingCycle.configured\n    );\n\n    if (_mods.length == 0) return leftoverAmount;\n\n    //Transfer between all mods.\n    for (uint256 _i = 0; _i < _mods.length; _i++) {\n      // Get a reference to the mod being iterated on.\n      PayoutMod memory _mod = _mods[_i];\n\n      // The amount to send towards mods. Mods percents are out of 10000.\n      uint256 _modCut = PRBMath.mulDiv(_amount, _mod.percent, 10000);\n\n      if (_modCut > 0) {\n        // Transfer ETH to the mod.\n        // If there's an allocator set, transfer to its `allocate` function.\n        if (_mod.allocator != IModAllocator(address(0))) {\n          _mod.allocator.allocate{value: _modCut}(\n            _fundingCycle.projectId,\n            _mod.projectId,\n            _mod.beneficiary\n          );\n        } else if (_mod.projectId != 0) {\n          // Otherwise, if a project is specified, make a payment to it.\n\n          // Get a reference to the Juicebox terminal being used.\n          ITerminal _terminal = terminalDirectory.terminalOf(_mod.projectId);\n\n          // The project must have a terminal to send funds to.\n          require(_terminal != ITerminal(address(0)), 'TerminalV1::tap: BAD_MOD');\n\n          // Save gas if this contract is being used as the terminal.\n          if (_terminal == this) {\n            _pay(_mod.projectId, _modCut, _mod.beneficiary, _memo, _mod.preferUnstaked);\n          } else {\n            _terminal.pay{value: _modCut}(\n              _mod.projectId,\n              _mod.beneficiary,\n              _memo,\n              _mod.preferUnstaked\n            );\n          }\n        } else {\n          // Otherwise, send the funds directly to the beneficiary.\n          Address.sendValue(_mod.beneficiary, _modCut);\n        }\n      }\n\n      // Subtract from the amount to be sent to the beneficiary.\n      leftoverAmount = leftoverAmount - _modCut;\n\n      emit DistributeToPayoutMod(\n        _fundingCycle.id,\n        _fundingCycle.projectId,\n        _mod,\n        _modCut,\n        msg.sender\n      );\n    }\n  }\n\n  /** \n      @notice\n      distributed tickets to the mods for the specified funding cycle.\n\n      @param _fundingCycle The funding cycle to base the ticket distribution on.\n      @param _amount The total amount of tickets to print.\n\n      @return leftoverAmount If the mod percents dont add up to 100%, the leftover amount is returned.\n\n    */\n  function _distributeToTicketMods(FundingCycle memory _fundingCycle, uint256 _amount)\n    private\n    returns (uint256 leftoverAmount)\n  {\n    // Set the leftover amount to the initial amount.\n    leftoverAmount = _amount;\n\n    // Get a reference to the project's ticket mods.\n    TicketMod[] memory _mods = modStore.ticketModsOf(\n      _fundingCycle.projectId,\n      _fundingCycle.configured\n    );\n\n    //Transfer between all mods.\n    for (uint256 _i = 0; _i < _mods.length; _i++) {\n      // Get a reference to the mod being iterated on.\n      TicketMod memory _mod = _mods[_i];\n\n      // The amount to send towards mods. Mods percents are out of 10000.\n      uint256 _modCut = PRBMath.mulDiv(_amount, _mod.percent, 10000);\n\n      // Print tickets for the mod if needed.\n      if (_modCut > 0)\n        ticketBooth.print(_mod.beneficiary, _fundingCycle.projectId, _modCut, _mod.preferUnstaked);\n\n      // Subtract from the amount to be sent to the beneficiary.\n      leftoverAmount = leftoverAmount - _modCut;\n\n      emit DistributeToTicketMod(\n        _fundingCycle.id,\n        _fundingCycle.projectId,\n        _mod,\n        _modCut,\n        msg.sender\n      );\n    }\n  }\n\n  /** \n      @notice \n      See the documentation for 'pay'.\n    */\n  function _pay(\n    uint256 _projectId,\n    uint256 _amount,\n    address _beneficiary,\n    string memory _memo,\n    bool _preferUnstakedTickets\n  ) private returns (uint256) {\n    // Get a reference to the current funding cycle for the project.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // Use the funding cycle's weight if it exists. Otherwise use the base weight.\n    uint256 _weight = _fundingCycle.number == 0\n      ? fundingCycles.BASE_WEIGHT()\n      : _fundingCycle.weight;\n\n    // Multiply the amount by the funding cycle's weight to determine the amount of tickets to print.\n    uint256 _weightedAmount = PRBMathUD60x18.mul(_amount, _weight);\n\n    // Use the funding cycle's reserved rate if it exists. Otherwise don't set a reserved rate.\n    // The reserved rate is stored in bytes 8-15 of the metadata property.\n    uint256 _reservedRate = _fundingCycle.number == 0\n      ? 0\n      : uint256(uint8(_fundingCycle.metadata >> 8));\n\n    // Only print the tickets that are unreserved.\n    uint256 _unreservedWeightedAmount = PRBMath.mulDiv(_weightedAmount, 200 - _reservedRate, 200);\n\n    // Add to the balance of the project.\n    balanceOf[_projectId] = balanceOf[_projectId] + _amount;\n\n    // If theres an unreserved weighted amount, print tickets representing this amount for the beneficiary.\n    if (_unreservedWeightedAmount > 0) {\n      // If there's no funding cycle, track this payment as having been made before a configuration.\n      if (_fundingCycle.number == 0) {\n        // Mark the premined tickets as processed so that reserved tickets can't later be printed against them.\n        // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n        require(\n          _processedTicketTrackerOf[_projectId] < 0 ||\n            uint256(_processedTicketTrackerOf[_projectId]) + uint256(_weightedAmount) <=\n            uint256(type(int256).max),\n          'TerminalV1::printTickets: INT_LIMIT_REACHED'\n        );\n        _processedTicketTrackerOf[_projectId] =\n          _processedTicketTrackerOf[_projectId] +\n          int256(_unreservedWeightedAmount);\n\n        // If theres no funding cycle, add these tickets to the amount that were printed before a funding cycle was configured.\n        _preconfigureTicketCountOf[_projectId] =\n          _preconfigureTicketCountOf[_projectId] +\n          _unreservedWeightedAmount;\n      }\n\n      // Print the project's tickets for the beneficiary.\n      ticketBooth.print(\n        _beneficiary,\n        _projectId,\n        _unreservedWeightedAmount,\n        _preferUnstakedTickets\n      );\n    } else if (_weightedAmount > 0) {\n      // If there is no unreserved weight amount but there is a weighted amount,\n      // the full weighted amount should be explicitly tracked as reserved since no unreserved tickets were printed.\n\n      // Subtract the total weighted amount from the tracker so the full reserved ticket amount can be printed later.\n      // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n      require(\n        _processedTicketTrackerOf[_projectId] > 0 ||\n          uint256(-_processedTicketTrackerOf[_projectId]) + uint256(_weightedAmount) <=\n          uint256(type(int256).max),\n        'TerminalV1::printTickets: INT_LIMIT_REACHED'\n      );\n      _processedTicketTrackerOf[_projectId] =\n        _processedTicketTrackerOf[_projectId] -\n        int256(_weightedAmount);\n    }\n\n    emit Pay(_fundingCycle.id, _projectId, _beneficiary, _amount, _memo, msg.sender);\n\n    return _fundingCycle.id;\n  }\n\n  /** \n      @notice \n      Gets the amount overflowed in relation to the provided funding cycle.\n\n      @dev\n      This amount changes as the price of ETH changes against the funding cycle's currency.\n\n      @param _currentFundingCycle The ID of the funding cycle to base the overflow on.\n\n      @return overflow The current overflow of funds.\n    */\n  function _overflowFrom(FundingCycle memory _currentFundingCycle) private view returns (uint256) {\n    // Get the current price of ETH.\n    uint256 _ethPrice = prices.getETHPriceFor(_currentFundingCycle.currency);\n\n    // Get a reference to the amount still tappable in the current funding cycle.\n    uint256 _limit = _currentFundingCycle.target - _currentFundingCycle.tapped;\n\n    // The amount of ETH that the owner could currently still tap if its available. This amount isn't considered overflow.\n    uint256 _ethLimit = _limit == 0 ? 0 : PRBMathUD60x18.div(_limit, _ethPrice);\n\n    // Get the current balance of the project.\n    uint256 _balanceOf = balanceOf[_currentFundingCycle.projectId];\n\n    // Overflow is the balance of this project minus the reserved amount.\n    return _balanceOf < _ethLimit ? 0 : _balanceOf - _ethLimit;\n  }\n\n  /** \n      @notice \n      Gets the amount of reserved tickets currently tracked for a project given a reserved rate.\n\n      @param _processedTicketTracker The tracker to make the calculation with.\n      @param _reservedRate The reserved rate to use to make the calculation.\n      @param _totalEligibleTickets The total amount to make the calculation with.\n\n      @return amount reserved ticket amount.\n    */\n  function _reservedTicketAmountFrom(\n    int256 _processedTicketTracker,\n    uint256 _reservedRate,\n    uint256 _totalEligibleTickets\n  ) private pure returns (uint256) {\n    // Get a reference to the amount of tickets that are unprocessed.\n    uint256 _unprocessedTicketBalanceOf = _processedTicketTracker >= 0 // preconfigure tickets shouldn't contribute to the reserved ticket amount.\n      ? _totalEligibleTickets - uint256(_processedTicketTracker)\n      : _totalEligibleTickets + uint256(-_processedTicketTracker);\n\n    // If there are no unprocessed tickets, return.\n    if (_unprocessedTicketBalanceOf == 0) return 0;\n\n    // If all tickets are reserved, return the full unprocessed amount.\n    if (_reservedRate == 200) return _unprocessedTicketBalanceOf;\n\n    return\n      PRBMath.mulDiv(_unprocessedTicketBalanceOf, 200, 200 - _reservedRate) -\n      _unprocessedTicketBalanceOf;\n  }\n\n  /**\n      @notice \n      Validate and pack the funding cycle metadata.\n\n      @param _metadata The metadata to validate and pack.\n\n      @return packed The packed uint256 of all metadata params. The first 8 bytes specify the version.\n     */\n  function _validateAndPackFundingCycleMetadata(FundingCycleMetadata memory _metadata)\n    private\n    pure\n    returns (uint256 packed)\n  {\n    // The reserved project ticket rate must be less than or equal to 200.\n    require(\n      _metadata.reservedRate <= 200,\n      'TerminalV1::_validateAndPackFundingCycleMetadata: BAD_RESERVED_RATE'\n    );\n\n    // The bonding curve rate must be between 0 and 200.\n    require(\n      _metadata.bondingCurveRate <= 200,\n      'TerminalV1::_validateAndPackFundingCycleMetadata: BAD_BONDING_CURVE_RATE'\n    );\n\n    // The reconfiguration bonding curve rate must be less than or equal to 200.\n    require(\n      _metadata.reconfigurationBondingCurveRate <= 200,\n      'TerminalV1::_validateAndPackFundingCycleMetadata: BAD_RECONFIGURATION_BONDING_CURVE_RATE'\n    );\n\n    // version 0 in the first 8 bytes.\n    packed = 0;\n    // reserved rate in bytes 8-15.\n    packed |= _metadata.reservedRate << 8;\n    // bonding curve in bytes 16-23.\n    packed |= _metadata.bondingCurveRate << 16;\n    // reconfiguration bonding curve rate in bytes 24-31.\n    packed |= _metadata.reconfigurationBondingCurveRate << 24;\n  }\n\n  /** \n      @notice \n      Takes a fee into the Governance contract's project.\n\n      @param _from The amount to take a fee from.\n      @param _percent The percent fee to take. Out of 200.\n      @param _beneficiary The address to print governance's tickets for.\n      @param _memo A memo to send with the fee.\n\n      @return feeAmount The amount of the fee taken.\n    */\n  function _takeFee(\n    uint256 _from,\n    uint256 _percent,\n    address _beneficiary,\n    string memory _memo\n  ) private returns (uint256 feeAmount) {\n    // The amount of ETH from the _tappedAmount to pay as a fee.\n    feeAmount = _from - PRBMath.mulDiv(_from, 200, _percent + 200);\n\n    // Nothing to do if there's no fee to take.\n    if (feeAmount == 0) return 0;\n\n    // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n    if (terminalDirectory.terminalOf(JuiceboxProject(governance).projectId()) == this) {\n      // Use the local pay call.\n      _pay(JuiceboxProject(governance).projectId(), feeAmount, _beneficiary, _memo, false);\n    } else {\n      // Use the external pay call of the governance contract.\n      JuiceboxProject(governance).pay{value: feeAmount}(_beneficiary, _memo, false);\n    }\n  }\n}\n"
    },
    "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and make it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        // On the first call to nonReentrant, _notEntered will be true\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n}\n"
    },
    "@paulrberg/contracts/math/PRBMath.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMath.sol\";\n"
    },
    "@paulrberg/contracts/math/PRBMathUD60x18.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.4;\n\nimport \"prb-math/contracts/PRBMathUD60x18.sol\";\n"
    },
    "contracts/abstract/Operatable.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./../interfaces/IOperatable.sol\";\n\nabstract contract Operatable is IOperatable {\n    modifier requirePermission(\n        address _account,\n        uint256 _domain,\n        uint256 _index\n    ) {\n        require(\n            msg.sender == _account ||\n                operatorStore.hasPermission(\n                    msg.sender,\n                    _account,\n                    _domain,\n                    _index\n                ),\n            \"Operatable: UNAUTHORIZED\"\n        );\n        _;\n    }\n\n    modifier requirePermissionAllowingWildcardDomain(\n        address _account,\n        uint256 _domain,\n        uint256 _index\n    ) {\n        require(\n            msg.sender == _account ||\n                operatorStore.hasPermission(\n                    msg.sender,\n                    _account,\n                    _domain,\n                    _index\n                ) ||\n                operatorStore.hasPermission(msg.sender, _account, 0, _index),\n            \"Operatable: UNAUTHORIZED\"\n        );\n        _;\n    }\n\n    modifier requirePermissionAcceptingAlternateAddress(\n        address _account,\n        uint256 _domain,\n        uint256 _index,\n        address _alternate\n    ) {\n        require(\n            msg.sender == _account ||\n                operatorStore.hasPermission(\n                    msg.sender,\n                    _account,\n                    _domain,\n                    _index\n                ) ||\n                msg.sender == _alternate,\n            \"Operatable: UNAUTHORIZED\"\n        );\n        _;\n    }\n\n    /// @notice A contract storing operator assignments.\n    IOperatorStore public immutable override operatorStore;\n\n    /** \n      @param _operatorStore A contract storing operator assignments.\n    */\n    constructor(IOperatorStore _operatorStore) {\n        operatorStore = _operatorStore;\n    }\n}\n"
    },
    "contracts/libraries/Operations.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nlibrary Operations {\n  uint256 public constant Configure = 1;\n  uint256 public constant PrintPreminedTickets = 2;\n  uint256 public constant Redeem = 3;\n  uint256 public constant Migrate = 4;\n  uint256 public constant SetHandle = 5;\n  uint256 public constant SetUri = 6;\n  uint256 public constant ClaimHandle = 7;\n  uint256 public constant RenewHandle = 8;\n  uint256 public constant Issue = 9;\n  uint256 public constant Stake = 10;\n  uint256 public constant Unstake = 11;\n  uint256 public constant Transfer = 12;\n  uint256 public constant Lock = 13;\n  uint256 public constant SetPayoutMods = 14;\n  uint256 public constant SetTicketMods = 15;\n  uint256 public constant SetTerminal = 16;\n  uint256 public constant PrintTickets = 17;\n}\n"
    },
    "prb-math/contracts/PRBMath.sol": {
      "content": "// SPDX-License-Identifier: WTFPL\npragma solidity >=0.8.4;\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivFixedPointOverflow(uint256 prod1);\n\n/// @notice Emitted when the result overflows uint256.\nerror PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator);\n\n/// @notice Emitted when one of the inputs is type(int256).min.\nerror PRBMath__MulDivSignedInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows int256.\nerror PRBMath__MulDivSignedOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is MIN_SD59x18.\nerror PRBMathSD59x18__AbsInputTooSmall();\n\n/// @notice Emitted when ceiling a number overflows SD59x18.\nerror PRBMathSD59x18__CeilOverflow(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__DivInputTooSmall();\n\n/// @notice Emitted when one of the intermediary unsigned results overflows SD59x18.\nerror PRBMathSD59x18__DivOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathSD59x18__ExpInputTooBig(int256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathSD59x18__Exp2InputTooBig(int256 x);\n\n/// @notice Emitted when flooring a number underflows SD59x18.\nerror PRBMathSD59x18__FloorUnderflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18.\nerror PRBMathSD59x18__FromIntOverflow(int256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18.\nerror PRBMathSD59x18__FromIntUnderflow(int256 x);\n\n/// @notice Emitted when the product of the inputs is negative.\nerror PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y);\n\n/// @notice Emitted when multiplying the inputs overflows SD59x18.\nerror PRBMathSD59x18__GmOverflow(int256 x, int256 y);\n\n/// @notice Emitted when the input is less than or equal to zero.\nerror PRBMathSD59x18__LogInputTooSmall(int256 x);\n\n/// @notice Emitted when one of the inputs is MIN_SD59x18.\nerror PRBMathSD59x18__MulInputTooSmall();\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__MulOverflow(uint256 rAbs);\n\n/// @notice Emitted when the intermediary absolute result overflows SD59x18.\nerror PRBMathSD59x18__PowuOverflow(uint256 rAbs);\n\n/// @notice Emitted when the input is negative.\nerror PRBMathSD59x18__SqrtNegativeInput(int256 x);\n\n/// @notice Emitted when the calculting the square root overflows SD59x18.\nerror PRBMathSD59x18__SqrtOverflow(int256 x);\n\n/// @notice Emitted when addition overflows UD60x18.\nerror PRBMathUD60x18__AddOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when ceiling a number overflows UD60x18.\nerror PRBMathUD60x18__CeilOverflow(uint256 x);\n\n/// @notice Emitted when the input is greater than 133.084258667509499441.\nerror PRBMathUD60x18__ExpInputTooBig(uint256 x);\n\n/// @notice Emitted when the input is greater than 192.\nerror PRBMathUD60x18__Exp2InputTooBig(uint256 x);\n\n/// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18.\nerror PRBMathUD60x18__FromUintOverflow(uint256 x);\n\n/// @notice Emitted when multiplying the inputs overflows UD60x18.\nerror PRBMathUD60x18__GmOverflow(uint256 x, uint256 y);\n\n/// @notice Emitted when the input is less than 1.\nerror PRBMathUD60x18__LogInputTooSmall(uint256 x);\n\n/// @notice Emitted when the calculting the square root overflows UD60x18.\nerror PRBMathUD60x18__SqrtOverflow(uint256 x);\n\n/// @notice Emitted when subtraction underflows UD60x18.\nerror PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y);\n\n/// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library\n/// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point\n/// representation. When it does not, it is explictly mentioned in the NatSpec documentation.\nlibrary PRBMath {\n    /// STRUCTS ///\n\n    struct SD59x18 {\n        int256 value;\n    }\n\n    struct UD60x18 {\n        uint256 value;\n    }\n\n    /// STORAGE ///\n\n    /// @dev How many trailing decimals can be represented.\n    uint256 internal constant SCALE = 1e18;\n\n    /// @dev Largest power of two divisor of SCALE.\n    uint256 internal constant SCALE_LPOTD = 262144;\n\n    /// @dev SCALE inverted mod 2^256.\n    uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661508869554232690281;\n\n    /// FUNCTIONS ///\n\n    /// @notice Calculates the binary exponent of x using the binary fraction method.\n    /// @dev Has to use 192.64-bit fixed-point numbers.\n    /// See https://ethereum.stackexchange.com/a/96594/24693.\n    /// @param x The exponent as an unsigned 192.64-bit fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function exp2(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            // Start from 0.5 in the 192.64-bit fixed-point format.\n            result = 0x800000000000000000000000000000000000000000000000;\n\n            // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows\n            // because the initial result is 2^191 and all magic factors are less than 2^65.\n            if (x & 0x8000000000000000 > 0) {\n                result = (result * 0x16A09E667F3BCC909) >> 64;\n            }\n            if (x & 0x4000000000000000 > 0) {\n                result = (result * 0x1306FE0A31B7152DF) >> 64;\n            }\n            if (x & 0x2000000000000000 > 0) {\n                result = (result * 0x1172B83C7D517ADCE) >> 64;\n            }\n            if (x & 0x1000000000000000 > 0) {\n                result = (result * 0x10B5586CF9890F62A) >> 64;\n            }\n            if (x & 0x800000000000000 > 0) {\n                result = (result * 0x1059B0D31585743AE) >> 64;\n            }\n            if (x & 0x400000000000000 > 0) {\n                result = (result * 0x102C9A3E778060EE7) >> 64;\n            }\n            if (x & 0x200000000000000 > 0) {\n                result = (result * 0x10163DA9FB33356D8) >> 64;\n            }\n            if (x & 0x100000000000000 > 0) {\n                result = (result * 0x100B1AFA5ABCBED61) >> 64;\n            }\n            if (x & 0x80000000000000 > 0) {\n                result = (result * 0x10058C86DA1C09EA2) >> 64;\n            }\n            if (x & 0x40000000000000 > 0) {\n                result = (result * 0x1002C605E2E8CEC50) >> 64;\n            }\n            if (x & 0x20000000000000 > 0) {\n                result = (result * 0x100162F3904051FA1) >> 64;\n            }\n            if (x & 0x10000000000000 > 0) {\n                result = (result * 0x1000B175EFFDC76BA) >> 64;\n            }\n            if (x & 0x8000000000000 > 0) {\n                result = (result * 0x100058BA01FB9F96D) >> 64;\n            }\n            if (x & 0x4000000000000 > 0) {\n                result = (result * 0x10002C5CC37DA9492) >> 64;\n            }\n            if (x & 0x2000000000000 > 0) {\n                result = (result * 0x1000162E525EE0547) >> 64;\n            }\n            if (x & 0x1000000000000 > 0) {\n                result = (result * 0x10000B17255775C04) >> 64;\n            }\n            if (x & 0x800000000000 > 0) {\n                result = (result * 0x1000058B91B5BC9AE) >> 64;\n            }\n            if (x & 0x400000000000 > 0) {\n                result = (result * 0x100002C5C89D5EC6D) >> 64;\n            }\n            if (x & 0x200000000000 > 0) {\n                result = (result * 0x10000162E43F4F831) >> 64;\n            }\n            if (x & 0x100000000000 > 0) {\n                result = (result * 0x100000B1721BCFC9A) >> 64;\n            }\n            if (x & 0x80000000000 > 0) {\n                result = (result * 0x10000058B90CF1E6E) >> 64;\n            }\n            if (x & 0x40000000000 > 0) {\n                result = (result * 0x1000002C5C863B73F) >> 64;\n            }\n            if (x & 0x20000000000 > 0) {\n                result = (result * 0x100000162E430E5A2) >> 64;\n            }\n            if (x & 0x10000000000 > 0) {\n                result = (result * 0x1000000B172183551) >> 64;\n            }\n            if (x & 0x8000000000 > 0) {\n                result = (result * 0x100000058B90C0B49) >> 64;\n            }\n            if (x & 0x4000000000 > 0) {\n                result = (result * 0x10000002C5C8601CC) >> 64;\n            }\n            if (x & 0x2000000000 > 0) {\n                result = (result * 0x1000000162E42FFF0) >> 64;\n            }\n            if (x & 0x1000000000 > 0) {\n                result = (result * 0x10000000B17217FBB) >> 64;\n            }\n            if (x & 0x800000000 > 0) {\n                result = (result * 0x1000000058B90BFCE) >> 64;\n            }\n            if (x & 0x400000000 > 0) {\n                result = (result * 0x100000002C5C85FE3) >> 64;\n            }\n            if (x & 0x200000000 > 0) {\n                result = (result * 0x10000000162E42FF1) >> 64;\n            }\n            if (x & 0x100000000 > 0) {\n                result = (result * 0x100000000B17217F8) >> 64;\n            }\n            if (x & 0x80000000 > 0) {\n                result = (result * 0x10000000058B90BFC) >> 64;\n            }\n            if (x & 0x40000000 > 0) {\n                result = (result * 0x1000000002C5C85FE) >> 64;\n            }\n            if (x & 0x20000000 > 0) {\n                result = (result * 0x100000000162E42FF) >> 64;\n            }\n            if (x & 0x10000000 > 0) {\n                result = (result * 0x1000000000B17217F) >> 64;\n            }\n            if (x & 0x8000000 > 0) {\n                result = (result * 0x100000000058B90C0) >> 64;\n            }\n            if (x & 0x4000000 > 0) {\n                result = (result * 0x10000000002C5C860) >> 64;\n            }\n            if (x & 0x2000000 > 0) {\n                result = (result * 0x1000000000162E430) >> 64;\n            }\n            if (x & 0x1000000 > 0) {\n                result = (result * 0x10000000000B17218) >> 64;\n            }\n            if (x & 0x800000 > 0) {\n                result = (result * 0x1000000000058B90C) >> 64;\n            }\n            if (x & 0x400000 > 0) {\n                result = (result * 0x100000000002C5C86) >> 64;\n            }\n            if (x & 0x200000 > 0) {\n                result = (result * 0x10000000000162E43) >> 64;\n            }\n            if (x & 0x100000 > 0) {\n                result = (result * 0x100000000000B1721) >> 64;\n            }\n            if (x & 0x80000 > 0) {\n                result = (result * 0x10000000000058B91) >> 64;\n            }\n            if (x & 0x40000 > 0) {\n                result = (result * 0x1000000000002C5C8) >> 64;\n            }\n            if (x & 0x20000 > 0) {\n                result = (result * 0x100000000000162E4) >> 64;\n            }\n            if (x & 0x10000 > 0) {\n                result = (result * 0x1000000000000B172) >> 64;\n            }\n            if (x & 0x8000 > 0) {\n                result = (result * 0x100000000000058B9) >> 64;\n            }\n            if (x & 0x4000 > 0) {\n                result = (result * 0x10000000000002C5D) >> 64;\n            }\n            if (x & 0x2000 > 0) {\n                result = (result * 0x1000000000000162E) >> 64;\n            }\n            if (x & 0x1000 > 0) {\n                result = (result * 0x10000000000000B17) >> 64;\n            }\n            if (x & 0x800 > 0) {\n                result = (result * 0x1000000000000058C) >> 64;\n            }\n            if (x & 0x400 > 0) {\n                result = (result * 0x100000000000002C6) >> 64;\n            }\n            if (x & 0x200 > 0) {\n                result = (result * 0x10000000000000163) >> 64;\n            }\n            if (x & 0x100 > 0) {\n                result = (result * 0x100000000000000B1) >> 64;\n            }\n            if (x & 0x80 > 0) {\n                result = (result * 0x10000000000000059) >> 64;\n            }\n            if (x & 0x40 > 0) {\n                result = (result * 0x1000000000000002C) >> 64;\n            }\n            if (x & 0x20 > 0) {\n                result = (result * 0x10000000000000016) >> 64;\n            }\n            if (x & 0x10 > 0) {\n                result = (result * 0x1000000000000000B) >> 64;\n            }\n            if (x & 0x8 > 0) {\n                result = (result * 0x10000000000000006) >> 64;\n            }\n            if (x & 0x4 > 0) {\n                result = (result * 0x10000000000000003) >> 64;\n            }\n            if (x & 0x2 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n            if (x & 0x1 > 0) {\n                result = (result * 0x10000000000000001) >> 64;\n            }\n\n            // We're doing two things at the same time:\n            //\n            //   1. Multiply the result by 2^n + 1, where \"2^n\" is the integer part and the one is added to account for\n            //      the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191\n            //      rather than 192.\n            //   2. Convert the result to the unsigned 60.18-decimal fixed-point format.\n            //\n            // This works because 2^(191-ip) = 2^ip / 2^191, where \"ip\" is the integer part \"2^n\".\n            result *= SCALE;\n            result >>= (191 - (x >> 64));\n        }\n    }\n\n    /// @notice Finds the zero-based index of the first one in the binary representation of x.\n    /// @dev See the note on msb in the \"Find First Set\" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set\n    /// @param x The uint256 number for which to find the index of the most significant bit.\n    /// @return msb The index of the most significant bit as an uint256.\n    function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) {\n        if (x >= 2**128) {\n            x >>= 128;\n            msb += 128;\n        }\n        if (x >= 2**64) {\n            x >>= 64;\n            msb += 64;\n        }\n        if (x >= 2**32) {\n            x >>= 32;\n            msb += 32;\n        }\n        if (x >= 2**16) {\n            x >>= 16;\n            msb += 16;\n        }\n        if (x >= 2**8) {\n            x >>= 8;\n            msb += 8;\n        }\n        if (x >= 2**4) {\n            x >>= 4;\n            msb += 4;\n        }\n        if (x >= 2**2) {\n            x >>= 2;\n            msb += 2;\n        }\n        if (x >= 2**1) {\n            // No need to shift x any more.\n            msb += 1;\n        }\n    }\n\n    /// @notice Calculates floor(x*y÷denominator) with full precision.\n    ///\n    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.\n    ///\n    /// Requirements:\n    /// - The denominator cannot be zero.\n    /// - The result must fit within uint256.\n    ///\n    /// Caveats:\n    /// - This function does not work with fixed-point numbers.\n    ///\n    /// @param x The multiplicand as an uint256.\n    /// @param y The multiplier as an uint256.\n    /// @param denominator The divisor as an uint256.\n    /// @return result The result as an uint256.\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\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            unchecked {\n                result = prod0 / denominator;\n            }\n            return result;\n        }\n\n        // Make sure the result is less than 2^256. Also prevents denominator == 0.\n        if (prod1 >= denominator) {\n            revert PRBMath__MulDivOverflow(prod1, denominator);\n        }\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        unchecked {\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 lpotdod = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by lpotdod.\n                denominator := div(denominator, lpotdod)\n\n                // Divide [prod1 prod0] by lpotdod.\n                prod0 := div(prod0, lpotdod)\n\n                // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one.\n                lpotdod := add(div(sub(0, lpotdod), lpotdod), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * lpotdod;\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            // Now use 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    /// @notice Calculates floor(x*y÷1e18) with full precision.\n    ///\n    /// @dev Variant of \"mulDiv\" with constant folding, i.e. in which the denominator is always 1e18. Before returning the\n    /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of\n    /// being rounded to 1e-18.  See \"Listing 6\" and text above it at https://accu.org/index.php/journals/1717.\n    ///\n    /// Requirements:\n    /// - The result must fit within uint256.\n    ///\n    /// Caveats:\n    /// - The body is purposely left uncommented; see the NatSpec comments in \"PRBMath.mulDiv\" to understand how this works.\n    /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations:\n    ///     1. x * y = type(uint256).max * SCALE\n    ///     2. (x * y) % SCALE >= SCALE / 2\n    ///\n    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        uint256 prod0;\n        uint256 prod1;\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        if (prod1 >= SCALE) {\n            revert PRBMath__MulDivFixedPointOverflow(prod1);\n        }\n\n        uint256 remainder;\n        uint256 roundUpUnit;\n        assembly {\n            remainder := mulmod(x, y, SCALE)\n            roundUpUnit := gt(remainder, 499999999999999999)\n        }\n\n        if (prod1 == 0) {\n            unchecked {\n                result = (prod0 / SCALE) + roundUpUnit;\n                return result;\n            }\n        }\n\n        assembly {\n            result := add(\n                mul(\n                    or(\n                        div(sub(prod0, remainder), SCALE_LPOTD),\n                        mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1))\n                    ),\n                    SCALE_INVERSE\n                ),\n                roundUpUnit\n            )\n        }\n    }\n\n    /// @notice Calculates floor(x*y÷denominator) with full precision.\n    ///\n    /// @dev An extension of \"mulDiv\" for signed numbers. Works by computing the signs and the absolute values separately.\n    ///\n    /// Requirements:\n    /// - None of the inputs can be type(int256).min.\n    /// - The result must fit within int256.\n    ///\n    /// @param x The multiplicand as an int256.\n    /// @param y The multiplier as an int256.\n    /// @param denominator The divisor as an int256.\n    /// @return result The result as an int256.\n    function mulDivSigned(\n        int256 x,\n        int256 y,\n        int256 denominator\n    ) internal pure returns (int256 result) {\n        if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {\n            revert PRBMath__MulDivSignedInputTooSmall();\n        }\n\n        // Get hold of the absolute values of x, y and the denominator.\n        uint256 ax;\n        uint256 ay;\n        uint256 ad;\n        unchecked {\n            ax = x < 0 ? uint256(-x) : uint256(x);\n            ay = y < 0 ? uint256(-y) : uint256(y);\n            ad = denominator < 0 ? uint256(-denominator) : uint256(denominator);\n        }\n\n        // Compute the absolute value of (x*y)÷denominator. The result must fit within int256.\n        uint256 rAbs = mulDiv(ax, ay, ad);\n        if (rAbs > uint256(type(int256).max)) {\n            revert PRBMath__MulDivSignedOverflow(rAbs);\n        }\n\n        // Get the signs of x, y and the denominator.\n        uint256 sx;\n        uint256 sy;\n        uint256 sd;\n        assembly {\n            sx := sgt(x, sub(0, 1))\n            sy := sgt(y, sub(0, 1))\n            sd := sgt(denominator, sub(0, 1))\n        }\n\n        // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs.\n        // If yes, the result should be negative.\n        result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs);\n    }\n\n    /// @notice Calculates the square root of x, rounding down.\n    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n    ///\n    /// Caveats:\n    /// - This function does not work with fixed-point numbers.\n    ///\n    /// @param x The uint256 number for which to calculate the square root.\n    /// @return result The result as an uint256.\n    function sqrt(uint256 x) internal pure returns (uint256 result) {\n        if (x == 0) {\n            return 0;\n        }\n\n        // Set the initial guess to the closest power of two that is higher than x.\n        uint256 xAux = uint256(x);\n        result = 1;\n        if (xAux >= 0x100000000000000000000000000000000) {\n            xAux >>= 128;\n            result <<= 64;\n        }\n        if (xAux >= 0x10000000000000000) {\n            xAux >>= 64;\n            result <<= 32;\n        }\n        if (xAux >= 0x100000000) {\n            xAux >>= 32;\n            result <<= 16;\n        }\n        if (xAux >= 0x10000) {\n            xAux >>= 16;\n            result <<= 8;\n        }\n        if (xAux >= 0x100) {\n            xAux >>= 8;\n            result <<= 4;\n        }\n        if (xAux >= 0x10) {\n            xAux >>= 4;\n            result <<= 2;\n        }\n        if (xAux >= 0x8) {\n            result <<= 1;\n        }\n\n        // The operations can never overflow because the result is max 2^127 when it enters this block.\n        unchecked {\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1;\n            result = (result + x / result) >> 1; // Seven iterations should be enough\n            uint256 roundedDownResult = x / result;\n            return result >= roundedDownResult ? roundedDownResult : result;\n        }\n    }\n}\n"
    },
    "prb-math/contracts/PRBMathUD60x18.sol": {
      "content": "// SPDX-License-Identifier: WTFPL\npragma solidity >=0.8.4;\n\nimport \"./PRBMath.sol\";\n\n/// @title PRBMathUD60x18\n/// @author Paul Razvan Berg\n/// @notice Smart contract library for advanced fixed-point math that works with uint256 numbers considered to have 18\n/// trailing decimals. We call this number representation unsigned 60.18-decimal fixed-point, since there can be up to 60\n/// digits in the integer part and up to 18 decimals in the fractional part. The numbers are bound by the minimum and the\n/// maximum values permitted by the Solidity type uint256.\nlibrary PRBMathUD60x18 {\n    /// @dev Half the SCALE number.\n    uint256 internal constant HALF_SCALE = 5e17;\n\n    /// @dev log2(e) as an unsigned 60.18-decimal fixed-point number.\n    uint256 internal constant LOG2_E = 1442695040888963407;\n\n    /// @dev The maximum value an unsigned 60.18-decimal fixed-point number can have.\n    uint256 internal constant MAX_UD60x18 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;\n\n    /// @dev The maximum whole value an unsigned 60.18-decimal fixed-point number can have.\n    uint256 internal constant MAX_WHOLE_UD60x18 = 115792089237316195423570985008687907853269984665640564039457000000000000000000;\n\n    /// @dev How many trailing decimals can be represented.\n    uint256 internal constant SCALE = 1e18;\n\n    /// @notice Calculates arithmetic average of x and y, rounding down.\n    /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The arithmetic average as an unsigned 60.18-decimal fixed-point number.\n    function avg(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        // The operations can never overflow.\n        unchecked {\n            // The last operand checks if both x and y are odd and if that is the case, we add 1 to the result. We need\n            // to do this because if both numbers are odd, the 0.5 remainder gets truncated twice.\n            result = (x >> 1) + (y >> 1) + (x & y & 1);\n        }\n    }\n\n    /// @notice Yields the least unsigned 60.18 decimal fixed-point number greater than or equal to x.\n    ///\n    /// @dev Optimised for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\n    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n    ///\n    /// Requirements:\n    /// - x must be less than or equal to MAX_WHOLE_UD60x18.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number to ceil.\n    /// @param result The least integer greater than or equal to x, as an unsigned 60.18-decimal fixed-point number.\n    function ceil(uint256 x) internal pure returns (uint256 result) {\n        if (x > MAX_WHOLE_UD60x18) {\n            revert PRBMathUD60x18__CeilOverflow(x);\n        }\n        assembly {\n            // Equivalent to \"x % SCALE\" but faster.\n            let remainder := mod(x, SCALE)\n\n            // Equivalent to \"SCALE - remainder\" but faster.\n            let delta := sub(SCALE, remainder)\n\n            // Equivalent to \"x + delta * (remainder > 0 ? 1 : 0)\" but faster.\n            result := add(x, mul(delta, gt(remainder, 0)))\n        }\n    }\n\n    /// @notice Divides two unsigned 60.18-decimal fixed-point numbers, returning a new unsigned 60.18-decimal fixed-point number.\n    ///\n    /// @dev Uses mulDiv to enable overflow-safe multiplication and division.\n    ///\n    /// Requirements:\n    /// - The denominator cannot be zero.\n    ///\n    /// @param x The numerator as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The denominator as an unsigned 60.18-decimal fixed-point number.\n    /// @param result The quotient as an unsigned 60.18-decimal fixed-point number.\n    function div(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        result = PRBMath.mulDiv(x, SCALE, y);\n    }\n\n    /// @notice Returns Euler's number as an unsigned 60.18-decimal fixed-point number.\n    /// @dev See https://en.wikipedia.org/wiki/E_(mathematical_constant).\n    function e() internal pure returns (uint256 result) {\n        result = 2718281828459045235;\n    }\n\n    /// @notice Calculates the natural exponent of x.\n    ///\n    /// @dev Based on the insight that e^x = 2^(x * log2(e)).\n    ///\n    /// Requirements:\n    /// - All from \"log2\".\n    /// - x must be less than 133.084258667509499441.\n    ///\n    /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function exp(uint256 x) internal pure returns (uint256 result) {\n        // Without this check, the value passed to \"exp2\" would be greater than 192.\n        if (x >= 133084258667509499441) {\n            revert PRBMathUD60x18__ExpInputTooBig(x);\n        }\n\n        // Do the fixed-point multiplication inline to save gas.\n        unchecked {\n            uint256 doubleScaleProduct = x * LOG2_E;\n            result = exp2((doubleScaleProduct + HALF_SCALE) / SCALE);\n        }\n    }\n\n    /// @notice Calculates the binary exponent of x using the binary fraction method.\n    ///\n    /// @dev See https://ethereum.stackexchange.com/q/79903/24693.\n    ///\n    /// Requirements:\n    /// - x must be 192 or less.\n    /// - The result must fit within MAX_UD60x18.\n    ///\n    /// @param x The exponent as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function exp2(uint256 x) internal pure returns (uint256 result) {\n        // 2^192 doesn't fit within the 192.64-bit format used internally in this function.\n        if (x >= 192e18) {\n            revert PRBMathUD60x18__Exp2InputTooBig(x);\n        }\n\n        unchecked {\n            // Convert x to the 192.64-bit fixed-point format.\n            uint256 x192x64 = (x << 64) / SCALE;\n\n            // Pass x to the PRBMath.exp2 function, which uses the 192.64-bit fixed-point number representation.\n            result = PRBMath.exp2(x192x64);\n        }\n    }\n\n    /// @notice Yields the greatest unsigned 60.18 decimal fixed-point number less than or equal to x.\n    /// @dev Optimised for fractional value inputs, because for every whole value there are (1e18 - 1) fractional counterparts.\n    /// See https://en.wikipedia.org/wiki/Floor_and_ceiling_functions.\n    /// @param x The unsigned 60.18-decimal fixed-point number to floor.\n    /// @param result The greatest integer less than or equal to x, as an unsigned 60.18-decimal fixed-point number.\n    function floor(uint256 x) internal pure returns (uint256 result) {\n        assembly {\n            // Equivalent to \"x % SCALE\" but faster.\n            let remainder := mod(x, SCALE)\n\n            // Equivalent to \"x - remainder * (remainder > 0 ? 1 : 0)\" but faster.\n            result := sub(x, mul(remainder, gt(remainder, 0)))\n        }\n    }\n\n    /// @notice Yields the excess beyond the floor of x.\n    /// @dev Based on the odd function definition https://en.wikipedia.org/wiki/Fractional_part.\n    /// @param x The unsigned 60.18-decimal fixed-point number to get the fractional part of.\n    /// @param result The fractional part of x as an unsigned 60.18-decimal fixed-point number.\n    function frac(uint256 x) internal pure returns (uint256 result) {\n        assembly {\n            result := mod(x, SCALE)\n        }\n    }\n\n    /// @notice Converts a number from basic integer form to unsigned 60.18-decimal fixed-point representation.\n    ///\n    /// @dev Requirements:\n    /// - x must be less than or equal to MAX_UD60x18 divided by SCALE.\n    ///\n    /// @param x The basic integer to convert.\n    /// @param result The same number in unsigned 60.18-decimal fixed-point representation.\n    function fromUint(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            if (x > MAX_UD60x18 / SCALE) {\n                revert PRBMathUD60x18__FromUintOverflow(x);\n            }\n            result = x * SCALE;\n        }\n    }\n\n    /// @notice Calculates geometric mean of x and y, i.e. sqrt(x * y), rounding down.\n    ///\n    /// @dev Requirements:\n    /// - x * y must fit within MAX_UD60x18, lest it overflows.\n    ///\n    /// @param x The first operand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The second operand as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function gm(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        if (x == 0) {\n            return 0;\n        }\n\n        unchecked {\n            // Checking for overflow this way is faster than letting Solidity do it.\n            uint256 xy = x * y;\n            if (xy / x != y) {\n                revert PRBMathUD60x18__GmOverflow(x, y);\n            }\n\n            // We don't need to multiply by the SCALE here because the x*y product had already picked up a factor of SCALE\n            // during multiplication. See the comments within the \"sqrt\" function.\n            result = PRBMath.sqrt(xy);\n        }\n    }\n\n    /// @notice Calculates 1 / x, rounding towards zero.\n    ///\n    /// @dev Requirements:\n    /// - x cannot be zero.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the inverse.\n    /// @return result The inverse as an unsigned 60.18-decimal fixed-point number.\n    function inv(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            // 1e36 is SCALE * SCALE.\n            result = 1e36 / x;\n        }\n    }\n\n    /// @notice Calculates the natural logarithm of x.\n    ///\n    /// @dev Based on the insight that ln(x) = log2(x) / log2(e).\n    ///\n    /// Requirements:\n    /// - All from \"log2\".\n    ///\n    /// Caveats:\n    /// - All from \"log2\".\n    /// - This doesn't return exactly 1 for 2.718281828459045235, for that we would need more fine-grained precision.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the natural logarithm.\n    /// @return result The natural logarithm as an unsigned 60.18-decimal fixed-point number.\n    function ln(uint256 x) internal pure returns (uint256 result) {\n        // Do the fixed-point multiplication inline to save gas. This is overflow-safe because the maximum value that log2(x)\n        // can return is 196205294292027477728.\n        unchecked {\n            result = (log2(x) * SCALE) / LOG2_E;\n        }\n    }\n\n    /// @notice Calculates the common logarithm of x.\n    ///\n    /// @dev First checks if x is an exact power of ten and it stops if yes. If it's not, calculates the common\n    /// logarithm based on the insight that log10(x) = log2(x) / log2(10).\n    ///\n    /// Requirements:\n    /// - All from \"log2\".\n    ///\n    /// Caveats:\n    /// - All from \"log2\".\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the common logarithm.\n    /// @return result The common logarithm as an unsigned 60.18-decimal fixed-point number.\n    function log10(uint256 x) internal pure returns (uint256 result) {\n        if (x < SCALE) {\n            revert PRBMathUD60x18__LogInputTooSmall(x);\n        }\n\n        // Note that the \"mul\" in this block is the assembly multiplication operation, not the \"mul\" function defined\n        // in this contract.\n        // prettier-ignore\n        assembly {\n            switch x\n            case 1 { result := mul(SCALE, sub(0, 18)) }\n            case 10 { result := mul(SCALE, sub(1, 18)) }\n            case 100 { result := mul(SCALE, sub(2, 18)) }\n            case 1000 { result := mul(SCALE, sub(3, 18)) }\n            case 10000 { result := mul(SCALE, sub(4, 18)) }\n            case 100000 { result := mul(SCALE, sub(5, 18)) }\n            case 1000000 { result := mul(SCALE, sub(6, 18)) }\n            case 10000000 { result := mul(SCALE, sub(7, 18)) }\n            case 100000000 { result := mul(SCALE, sub(8, 18)) }\n            case 1000000000 { result := mul(SCALE, sub(9, 18)) }\n            case 10000000000 { result := mul(SCALE, sub(10, 18)) }\n            case 100000000000 { result := mul(SCALE, sub(11, 18)) }\n            case 1000000000000 { result := mul(SCALE, sub(12, 18)) }\n            case 10000000000000 { result := mul(SCALE, sub(13, 18)) }\n            case 100000000000000 { result := mul(SCALE, sub(14, 18)) }\n            case 1000000000000000 { result := mul(SCALE, sub(15, 18)) }\n            case 10000000000000000 { result := mul(SCALE, sub(16, 18)) }\n            case 100000000000000000 { result := mul(SCALE, sub(17, 18)) }\n            case 1000000000000000000 { result := 0 }\n            case 10000000000000000000 { result := SCALE }\n            case 100000000000000000000 { result := mul(SCALE, 2) }\n            case 1000000000000000000000 { result := mul(SCALE, 3) }\n            case 10000000000000000000000 { result := mul(SCALE, 4) }\n            case 100000000000000000000000 { result := mul(SCALE, 5) }\n            case 1000000000000000000000000 { result := mul(SCALE, 6) }\n            case 10000000000000000000000000 { result := mul(SCALE, 7) }\n            case 100000000000000000000000000 { result := mul(SCALE, 8) }\n            case 1000000000000000000000000000 { result := mul(SCALE, 9) }\n            case 10000000000000000000000000000 { result := mul(SCALE, 10) }\n            case 100000000000000000000000000000 { result := mul(SCALE, 11) }\n            case 1000000000000000000000000000000 { result := mul(SCALE, 12) }\n            case 10000000000000000000000000000000 { result := mul(SCALE, 13) }\n            case 100000000000000000000000000000000 { result := mul(SCALE, 14) }\n            case 1000000000000000000000000000000000 { result := mul(SCALE, 15) }\n            case 10000000000000000000000000000000000 { result := mul(SCALE, 16) }\n            case 100000000000000000000000000000000000 { result := mul(SCALE, 17) }\n            case 1000000000000000000000000000000000000 { result := mul(SCALE, 18) }\n            case 10000000000000000000000000000000000000 { result := mul(SCALE, 19) }\n            case 100000000000000000000000000000000000000 { result := mul(SCALE, 20) }\n            case 1000000000000000000000000000000000000000 { result := mul(SCALE, 21) }\n            case 10000000000000000000000000000000000000000 { result := mul(SCALE, 22) }\n            case 100000000000000000000000000000000000000000 { result := mul(SCALE, 23) }\n            case 1000000000000000000000000000000000000000000 { result := mul(SCALE, 24) }\n            case 10000000000000000000000000000000000000000000 { result := mul(SCALE, 25) }\n            case 100000000000000000000000000000000000000000000 { result := mul(SCALE, 26) }\n            case 1000000000000000000000000000000000000000000000 { result := mul(SCALE, 27) }\n            case 10000000000000000000000000000000000000000000000 { result := mul(SCALE, 28) }\n            case 100000000000000000000000000000000000000000000000 { result := mul(SCALE, 29) }\n            case 1000000000000000000000000000000000000000000000000 { result := mul(SCALE, 30) }\n            case 10000000000000000000000000000000000000000000000000 { result := mul(SCALE, 31) }\n            case 100000000000000000000000000000000000000000000000000 { result := mul(SCALE, 32) }\n            case 1000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 33) }\n            case 10000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 34) }\n            case 100000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 35) }\n            case 1000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 36) }\n            case 10000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 37) }\n            case 100000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 38) }\n            case 1000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 39) }\n            case 10000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 40) }\n            case 100000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 41) }\n            case 1000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 42) }\n            case 10000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 43) }\n            case 100000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 44) }\n            case 1000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 45) }\n            case 10000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 46) }\n            case 100000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 47) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 48) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 49) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 50) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 51) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 52) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 53) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 54) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 55) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 56) }\n            case 1000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 57) }\n            case 10000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 58) }\n            case 100000000000000000000000000000000000000000000000000000000000000000000000000000 { result := mul(SCALE, 59) }\n            default {\n                result := MAX_UD60x18\n            }\n        }\n\n        if (result == MAX_UD60x18) {\n            // Do the fixed-point division inline to save gas. The denominator is log2(10).\n            unchecked {\n                result = (log2(x) * SCALE) / 3321928094887362347;\n            }\n        }\n    }\n\n    /// @notice Calculates the binary logarithm of x.\n    ///\n    /// @dev Based on the iterative approximation algorithm.\n    /// https://en.wikipedia.org/wiki/Binary_logarithm#Iterative_approximation\n    ///\n    /// Requirements:\n    /// - x must be greater than or equal to SCALE, otherwise the result would be negative.\n    ///\n    /// Caveats:\n    /// - The results are nor perfectly accurate to the last decimal, due to the lossy precision of the iterative approximation.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the binary logarithm.\n    /// @return result The binary logarithm as an unsigned 60.18-decimal fixed-point number.\n    function log2(uint256 x) internal pure returns (uint256 result) {\n        if (x < SCALE) {\n            revert PRBMathUD60x18__LogInputTooSmall(x);\n        }\n        unchecked {\n            // Calculate the integer part of the logarithm and add it to the result and finally calculate y = x * 2^(-n).\n            uint256 n = PRBMath.mostSignificantBit(x / SCALE);\n\n            // The integer part of the logarithm as an unsigned 60.18-decimal fixed-point number. The operation can't overflow\n            // because n is maximum 255 and SCALE is 1e18.\n            result = n * SCALE;\n\n            // This is y = x * 2^(-n).\n            uint256 y = x >> n;\n\n            // If y = 1, the fractional part is zero.\n            if (y == SCALE) {\n                return result;\n            }\n\n            // Calculate the fractional part via the iterative approximation.\n            // The \"delta >>= 1\" part is equivalent to \"delta /= 2\", but shifting bits is faster.\n            for (uint256 delta = HALF_SCALE; delta > 0; delta >>= 1) {\n                y = (y * y) / SCALE;\n\n                // Is y^2 > 2 and so in the range [2,4)?\n                if (y >= 2 * SCALE) {\n                    // Add the 2^(-m) factor to the logarithm.\n                    result += delta;\n\n                    // Corresponds to z/2 on Wikipedia.\n                    y >>= 1;\n                }\n            }\n        }\n    }\n\n    /// @notice Multiplies two unsigned 60.18-decimal fixed-point numbers together, returning a new unsigned 60.18-decimal\n    /// fixed-point number.\n    /// @dev See the documentation for the \"PRBMath.mulDivFixedPoint\" function.\n    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.\n    /// @return result The product as an unsigned 60.18-decimal fixed-point number.\n    function mul(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        result = PRBMath.mulDivFixedPoint(x, y);\n    }\n\n    /// @notice Returns PI as an unsigned 60.18-decimal fixed-point number.\n    function pi() internal pure returns (uint256 result) {\n        result = 3141592653589793238;\n    }\n\n    /// @notice Raises x to the power of y.\n    ///\n    /// @dev Based on the insight that x^y = 2^(log2(x) * y).\n    ///\n    /// Requirements:\n    /// - All from \"exp2\", \"log2\" and \"mul\".\n    ///\n    /// Caveats:\n    /// - All from \"exp2\", \"log2\" and \"mul\".\n    /// - Assumes 0^0 is 1.\n    ///\n    /// @param x Number to raise to given power y, as an unsigned 60.18-decimal fixed-point number.\n    /// @param y Exponent to raise x to, as an unsigned 60.18-decimal fixed-point number.\n    /// @return result x raised to power y, as an unsigned 60.18-decimal fixed-point number.\n    function pow(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        if (x == 0) {\n            result = y == 0 ? SCALE : uint256(0);\n        } else {\n            result = exp2(mul(log2(x), y));\n        }\n    }\n\n    /// @notice Raises x (unsigned 60.18-decimal fixed-point number) to the power of y (basic unsigned integer) using the\n    /// famous algorithm \"exponentiation by squaring\".\n    ///\n    /// @dev See https://en.wikipedia.org/wiki/Exponentiation_by_squaring\n    ///\n    /// Requirements:\n    /// - The result must fit within MAX_UD60x18.\n    ///\n    /// Caveats:\n    /// - All from \"mul\".\n    /// - Assumes 0^0 is 1.\n    ///\n    /// @param x The base as an unsigned 60.18-decimal fixed-point number.\n    /// @param y The exponent as an uint256.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point number.\n    function powu(uint256 x, uint256 y) internal pure returns (uint256 result) {\n        // Calculate the first iteration of the loop in advance.\n        result = y & 1 > 0 ? x : SCALE;\n\n        // Equivalent to \"for(y /= 2; y > 0; y /= 2)\" but faster.\n        for (y >>= 1; y > 0; y >>= 1) {\n            x = PRBMath.mulDivFixedPoint(x, x);\n\n            // Equivalent to \"y % 2 == 1\" but faster.\n            if (y & 1 > 0) {\n                result = PRBMath.mulDivFixedPoint(result, x);\n            }\n        }\n    }\n\n    /// @notice Returns 1 as an unsigned 60.18-decimal fixed-point number.\n    function scale() internal pure returns (uint256 result) {\n        result = SCALE;\n    }\n\n    /// @notice Calculates the square root of x, rounding down.\n    /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.\n    ///\n    /// Requirements:\n    /// - x must be less than MAX_UD60x18 / SCALE.\n    ///\n    /// @param x The unsigned 60.18-decimal fixed-point number for which to calculate the square root.\n    /// @return result The result as an unsigned 60.18-decimal fixed-point .\n    function sqrt(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            if (x > MAX_UD60x18 / SCALE) {\n                revert PRBMathUD60x18__SqrtOverflow(x);\n            }\n            // Multiply x by the SCALE to account for the factor of SCALE that is picked up when multiplying two unsigned\n            // 60.18-decimal fixed-point numbers together (in this case, those two numbers are both the square root).\n            result = PRBMath.sqrt(x * SCALE);\n        }\n    }\n\n    /// @notice Converts a unsigned 60.18-decimal fixed-point number to basic integer form, rounding down in the process.\n    /// @param x The unsigned 60.18-decimal fixed-point number to convert.\n    /// @return result The same number in basic integer form.\n    function toUint(uint256 x) internal pure returns (uint256 result) {\n        unchecked {\n            result = x / SCALE;\n        }\n    }\n}\n"
    },
    "contracts/interfaces/IOperatable.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./IOperatorStore.sol\";\n\ninterface IOperatable {\n    function operatorStore() external view returns (IOperatorStore);\n}\n"
    },
    "contracts/TicketBooth.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITicketBooth.sol\";\nimport \"./abstract/Operatable.sol\";\nimport \"./abstract/TerminalUtility.sol\";\n\nimport \"./libraries/Operations.sol\";\n\nimport \"./Tickets.sol\";\n\n/** \n  @notice \n  Manage Ticket printing, redemption, and account balances.\n\n  @dev\n  Tickets can be either represented internally staked, or as unstaked ERC-20s.\n  This contract manages these two representations and the conversion between the two.\n\n  @dev\n  The total supply of a project's tickets and the balance of each account are calculated in this contract.\n*/\ncontract TicketBooth is TerminalUtility, Operatable, ITicketBooth {\n    // --- public immutable stored properties --- //\n\n    /// @notice The Projects contract which mints ERC-721's that represent project ownership and transfers.\n    IProjects public immutable override projects;\n\n    // --- public stored properties --- //\n\n    // Each project's ERC20 Ticket tokens.\n    mapping(uint256 => ITickets) public override ticketsOf;\n\n    // Each holder's balance of staked Tickets for each project.\n    mapping(address => mapping(uint256 => uint256))\n        public\n        override stakedBalanceOf;\n\n    // The total supply of 1155 tickets for each project.\n    mapping(uint256 => uint256) public override stakedTotalSupplyOf;\n\n    // The amount of each holders tickets that are locked.\n    mapping(address => mapping(uint256 => uint256))\n        public\n        override lockedBalanceOf;\n\n    // The amount of each holders tickets that are locked by each address.\n    mapping(address => mapping(address => mapping(uint256 => uint256)))\n        public\n        override lockedBalanceBy;\n\n    // --- external views --- //\n\n    /** \n      @notice \n      The total supply of tickets for each project, including staked and unstaked tickets.\n\n      @param _projectId The ID of the project to get the total supply of.\n\n      @return supply The total supply.\n    */\n    function totalSupplyOf(uint256 _projectId)\n        external\n        view\n        override\n        returns (uint256 supply)\n    {\n        supply = stakedTotalSupplyOf[_projectId];\n        ITickets _tickets = ticketsOf[_projectId];\n        if (_tickets != ITickets(address(0)))\n            supply = supply + _tickets.totalSupply();\n    }\n\n    /** \n      @notice \n      The total balance of tickets a holder has for a specified project, including staked and unstaked tickets.\n\n      @param _holder The ticket holder to get a balance for.\n      @param _projectId The project to get the `_hodler`s balance of.\n\n      @return balance The balance.\n    */\n    function balanceOf(address _holder, uint256 _projectId)\n        external\n        view\n        override\n        returns (uint256 balance)\n    {\n        balance = stakedBalanceOf[_holder][_projectId];\n        ITickets _ticket = ticketsOf[_projectId];\n        if (_ticket != ITickets(address(0)))\n            balance = balance + _ticket.balanceOf(_holder);\n    }\n\n    // --- external transactions --- //\n\n    /** \n      @param _projects A Projects contract which mints ERC-721's that represent project ownership and transfers.\n      @param _operatorStore A contract storing operator assignments.\n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n    constructor(\n        IProjects _projects,\n        IOperatorStore _operatorStore,\n        ITerminalDirectory _terminalDirectory\n    ) Operatable(_operatorStore) TerminalUtility(_terminalDirectory) {\n        projects = _projects;\n    }\n\n    /**\n        @notice \n        Issues an owner's ERC-20 Tickets that'll be used when unstaking tickets.\n\n        @dev \n        Deploys an owner's Ticket ERC-20 token contract.\n\n        @param _projectId The ID of the project being issued tickets.\n        @param _name The ERC-20's name. \" Juicebox ticket\" will be appended.\n        @param _symbol The ERC-20's symbol. \"j\" will be prepended.\n    */\n    function issue(\n        uint256 _projectId,\n        string calldata _name,\n        string calldata _symbol\n    )\n        external\n        override\n        requirePermission(\n            projects.ownerOf(_projectId),\n            _projectId,\n            Operations.Issue\n        )\n    {\n        // There must be a name.\n        require((bytes(_name).length > 0), \"TicketBooth::issue: EMPTY_NAME\");\n\n        // There must be a symbol.\n        require(\n            (bytes(_symbol).length > 0),\n            \"TicketBooth::issue: EMPTY_SYMBOL\"\n        );\n\n        // Only one ERC20 ticket can be issued.\n        require(\n            ticketsOf[_projectId] == ITickets(address(0)),\n            \"TicketBooth::issue: ALREADY_ISSUED\"\n        );\n\n        // Create the contract in this TerminalV1 contract in order to have mint and burn privileges.\n        // Prepend the strings with standards.\n        ticketsOf[_projectId] = new Tickets(_name, _symbol);\n\n        emit Issue(_projectId, _name, _symbol, msg.sender);\n    }\n\n    /** \n      @notice \n      Print new tickets.\n\n      @dev\n      Only a project's current terminal can print its tickets.\n\n      @param _holder The address receiving the new tickets.\n      @param _projectId The project to which the tickets belong.\n      @param _amount The amount to print.\n      @param _preferUnstakedTickets Whether ERC20's should be converted automatically if they have been issued.\n    */\n    function print(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount,\n        bool _preferUnstakedTickets\n    ) external override onlyTerminal(_projectId) {\n        // An amount must be specified.\n        require(_amount > 0, \"TicketBooth::print: NO_OP\");\n\n        // Get a reference to the project's ERC20 tickets.\n        ITickets _tickets = ticketsOf[_projectId];\n\n        // If there exists ERC-20 tickets and the caller prefers these unstaked tickets.\n        bool _shouldUnstakeTickets = _preferUnstakedTickets &&\n            _tickets != ITickets(address(0));\n\n        if (_shouldUnstakeTickets) {\n            // Print the equivalent amount of ERC20s.\n            _tickets.print(_holder, _amount);\n        } else {\n            // Add to the staked balance and total supply.\n            stakedBalanceOf[_holder][_projectId] =\n                stakedBalanceOf[_holder][_projectId] +\n                _amount;\n            stakedTotalSupplyOf[_projectId] =\n                stakedTotalSupplyOf[_projectId] +\n                _amount;\n        }\n\n        emit Print(\n            _holder,\n            _projectId,\n            _amount,\n            _shouldUnstakeTickets,\n            _preferUnstakedTickets,\n            msg.sender\n        );\n    }\n\n    /** \n      @notice \n      Redeems tickets.\n\n      @dev\n      Only a project's current terminal can redeem its tickets.\n\n      @param _holder The address that owns the tickets being redeemed.\n      @param _projectId The ID of the project of the tickets being redeemed.\n      @param _amount The amount of tickets being redeemed.\n      @param _preferUnstaked If the preference is to redeem tickets that have been converted to ERC-20s.\n    */\n    function redeem(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount,\n        bool _preferUnstaked\n    ) external override onlyTerminal(_projectId) {\n        // Get a reference to the project's ERC20 tickets.\n        ITickets _tickets = ticketsOf[_projectId];\n\n        // Get a reference to the staked amount.\n        uint256 _unlockedStakedBalance = stakedBalanceOf[_holder][_projectId] -\n            lockedBalanceOf[_holder][_projectId];\n\n        // Get a reference to the number of tickets there are.\n        uint256 _unstakedBalanceOf = _tickets == ITickets(address(0))\n            ? 0\n            : _tickets.balanceOf(_holder);\n\n        // There must be enough tickets.\n        // Prevent potential overflow by not relying on addition.\n        require(\n            (_amount < _unstakedBalanceOf &&\n                _amount < _unlockedStakedBalance) ||\n                (_amount >= _unstakedBalanceOf &&\n                    _unlockedStakedBalance >= _amount - _unstakedBalanceOf) ||\n                (_amount >= _unlockedStakedBalance &&\n                    _unstakedBalanceOf >= _amount - _unlockedStakedBalance),\n            \"TicketBooth::redeem: INSUFFICIENT_FUNDS\"\n        );\n\n        // The amount of tickets to redeem.\n        uint256 _unstakedTicketsToRedeem;\n\n        // If there's no balance, redeem no tickets\n        if (_unstakedBalanceOf == 0) {\n            _unstakedTicketsToRedeem = 0;\n            // If prefer converted, redeem tickets before redeeming staked tickets.\n        } else if (_preferUnstaked) {\n            _unstakedTicketsToRedeem = _unstakedBalanceOf >= _amount\n                ? _amount\n                : _unstakedBalanceOf;\n            // Otherwise, redeem staked tickets before unstaked tickets.\n        } else {\n            _unstakedTicketsToRedeem = _unlockedStakedBalance >= _amount\n                ? 0\n                : _amount - _unlockedStakedBalance;\n        }\n\n        // The amount of staked tickets to redeem.\n        uint256 _stakedTicketsToRedeem = _amount - _unstakedTicketsToRedeem;\n\n        // Redeem the tickets.\n        if (_unstakedTicketsToRedeem > 0)\n            _tickets.redeem(_holder, _unstakedTicketsToRedeem);\n        if (_stakedTicketsToRedeem > 0) {\n            // Reduce the holders balance and the total supply.\n            stakedBalanceOf[_holder][_projectId] =\n                stakedBalanceOf[_holder][_projectId] -\n                _stakedTicketsToRedeem;\n            stakedTotalSupplyOf[_projectId] =\n                stakedTotalSupplyOf[_projectId] -\n                _stakedTicketsToRedeem;\n        }\n\n        emit Redeem(\n            _holder,\n            _projectId,\n            _amount,\n            _unlockedStakedBalance,\n            _preferUnstaked,\n            msg.sender\n        );\n    }\n\n    /**\n      @notice \n      Stakes ERC20 tickets by burning their supply and creating an internal staked version.\n\n      @dev\n      Only a ticket holder or an operator can stake its tickets.\n\n      @param _holder The owner of the tickets to stake.\n      @param _projectId The ID of the project whos tickets are being staked.\n      @param _amount The amount of tickets to stake.\n     */\n    function stake(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    )\n        external\n        override\n        requirePermissionAllowingWildcardDomain(\n            _holder,\n            _projectId,\n            Operations.Stake\n        )\n    {\n        // Get a reference to the project's ERC20 tickets.\n        ITickets _tickets = ticketsOf[_projectId];\n\n        // Tickets must have been issued.\n        require(\n            _tickets != ITickets(address(0)),\n            \"TicketBooth::stake: NOT_FOUND\"\n        );\n\n        // Get a reference to the holder's current balance.\n        uint256 _unstakedBalanceOf = _tickets.balanceOf(_holder);\n\n        // There must be enough balance to stake.\n        require(\n            _unstakedBalanceOf >= _amount,\n            \"TicketBooth::stake: INSUFFICIENT_FUNDS\"\n        );\n\n        // Redeem the equivalent amount of ERC20s.\n        _tickets.redeem(_holder, _amount);\n\n        // Add the staked amount from the holder's balance.\n        stakedBalanceOf[_holder][_projectId] =\n            stakedBalanceOf[_holder][_projectId] +\n            _amount;\n\n        // Add the staked amount from the project's total supply.\n        stakedTotalSupplyOf[_projectId] =\n            stakedTotalSupplyOf[_projectId] +\n            _amount;\n\n        emit Stake(_holder, _projectId, _amount, msg.sender);\n    }\n\n    /**\n      @notice \n      Unstakes internal tickets by creating and distributing ERC20 tickets.\n\n      @dev\n      Only a ticket holder or an operator can unstake its tickets.\n\n      @param _holder The owner of the tickets to unstake.\n      @param _projectId The ID of the project whos tickets are being unstaked.\n      @param _amount The amount of tickets to unstake.\n     */\n    function unstake(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    )\n        external\n        override\n        requirePermissionAllowingWildcardDomain(\n            _holder,\n            _projectId,\n            Operations.Unstake\n        )\n    {\n        // Get a reference to the project's ERC20 tickets.\n        ITickets _tickets = ticketsOf[_projectId];\n\n        // Tickets must have been issued.\n        require(\n            _tickets != ITickets(address(0)),\n            \"TicketBooth::unstake: NOT_FOUND\"\n        );\n\n        // Get a reference to the amount of unstaked tickets.\n        uint256 _unlockedStakedTickets = stakedBalanceOf[_holder][_projectId] -\n            lockedBalanceOf[_holder][_projectId];\n\n        // There must be enough unlocked staked tickets to unstake.\n        require(\n            _unlockedStakedTickets >= _amount,\n            \"TicketBooth::unstake: INSUFFICIENT_FUNDS\"\n        );\n\n        // Subtract the unstaked amount from the holder's balance.\n        stakedBalanceOf[_holder][_projectId] =\n            stakedBalanceOf[_holder][_projectId] -\n            _amount;\n\n        // Subtract the unstaked amount from the project's total supply.\n        stakedTotalSupplyOf[_projectId] =\n            stakedTotalSupplyOf[_projectId] -\n            _amount;\n\n        // Print the equivalent amount of ERC20s.\n        _tickets.print(_holder, _amount);\n\n        emit Unstake(_holder, _projectId, _amount, msg.sender);\n    }\n\n    /** \n      @notice \n      Lock a project's tickets, preventing them from being redeemed and from converting to ERC20s.\n\n      @dev\n      Only a ticket holder or an operator can lock its tickets.\n\n      @param _holder The holder to lock tickets from.\n      @param _projectId The ID of the project whos tickets are being locked.\n      @param _amount The amount of tickets to lock.\n    */\n    function lock(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    )\n        external\n        override\n        requirePermissionAllowingWildcardDomain(\n            _holder,\n            _projectId,\n            Operations.Lock\n        )\n    {\n        // Amount must be greater than 0.\n        require(_amount > 0, \"TicketBooth::lock: NO_OP\");\n\n        // The holder must have enough tickets to lock.\n        require(\n            stakedBalanceOf[_holder][_projectId] -\n                lockedBalanceOf[_holder][_projectId] >=\n                _amount,\n            \"TicketBooth::lock: INSUFFICIENT_FUNDS\"\n        );\n\n        // Update the lock.\n        lockedBalanceOf[_holder][_projectId] =\n            lockedBalanceOf[_holder][_projectId] +\n            _amount;\n        lockedBalanceBy[msg.sender][_holder][_projectId] =\n            lockedBalanceBy[msg.sender][_holder][_projectId] +\n            _amount;\n\n        emit Lock(_holder, _projectId, _amount, msg.sender);\n    }\n\n    /** \n      @notice \n      Unlock a project's tickets.\n\n      @dev\n      The address that locked the tickets must be the address that unlocks the tickets.\n\n      @param _holder The holder to unlock tickets from.\n      @param _projectId The ID of the project whos tickets are being unlocked.\n      @param _amount The amount of tickets to unlock.\n    */\n    function unlock(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount\n    ) external override {\n        // Amount must be greater than 0.\n        require(_amount > 0, \"TicketBooth::unlock: NO_OP\");\n\n        // There must be enough locked tickets to unlock.\n        require(\n            lockedBalanceBy[msg.sender][_holder][_projectId] >= _amount,\n            \"TicketBooth::unlock: INSUFFICIENT_FUNDS\"\n        );\n\n        // Update the lock.\n        lockedBalanceOf[_holder][_projectId] =\n            lockedBalanceOf[_holder][_projectId] -\n            _amount;\n        lockedBalanceBy[msg.sender][_holder][_projectId] =\n            lockedBalanceBy[msg.sender][_holder][_projectId] -\n            _amount;\n\n        emit Unlock(_holder, _projectId, _amount, msg.sender);\n    }\n\n    /** \n      @notice \n      Allows a ticket holder to transfer its tickets to another account, without unstaking to ERC-20s.\n\n      @dev\n      Only a ticket holder or an operator can transfer its tickets.\n\n      @param _holder The holder to transfer tickets from.\n      @param _projectId The ID of the project whos tickets are being transfered.\n      @param _amount The amount of tickets to transfer.\n      @param _recipient The recipient of the tickets.\n    */\n    function transfer(\n        address _holder,\n        uint256 _projectId,\n        uint256 _amount,\n        address _recipient\n    )\n        external\n        override\n        requirePermissionAllowingWildcardDomain(\n            _holder,\n            _projectId,\n            Operations.Transfer\n        )\n    {\n        // Can't transfer to the zero address.\n        require(\n            _recipient != address(0),\n            \"TicketBooth::transfer: ZERO_ADDRESS\"\n        );\n\n        // An address can't transfer to itself.\n        require(_holder != _recipient, \"TicketBooth::transfer: IDENTITY\");\n\n        // There must be an amount to transfer.\n        require(_amount > 0, \"TicketBooth::transfer: NO_OP\");\n\n        // Get a reference to the amount of unlocked staked tickets.\n        uint256 _unlockedStakedTickets = stakedBalanceOf[_holder][_projectId] -\n            lockedBalanceOf[_holder][_projectId];\n\n        // There must be enough unlocked staked tickets to transfer.\n        require(\n            _amount <= _unlockedStakedTickets,\n            \"TicketBooth::transfer: INSUFFICIENT_FUNDS\"\n        );\n\n        // Subtract from the holder.\n        stakedBalanceOf[_holder][_projectId] =\n            stakedBalanceOf[_holder][_projectId] -\n            _amount;\n\n        // Add the tickets to the recipient.\n        stakedBalanceOf[_recipient][_projectId] =\n            stakedBalanceOf[_recipient][_projectId] +\n            _amount;\n\n        emit Transfer(_holder, _projectId, _recipient, _amount, msg.sender);\n    }\n}\n"
    },
    "contracts/abstract/TerminalUtility.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./../interfaces/ITerminalUtility.sol\";\n\nabstract contract TerminalUtility is ITerminalUtility {\n    modifier onlyTerminal(uint256 _projectId) {\n        require(\n            address(terminalDirectory.terminalOf(_projectId)) == msg.sender,\n            \"TerminalUtility: UNAUTHORIZED\"\n        );\n        _;\n    }\n\n    /// @notice The direct deposit terminals.\n    ITerminalDirectory public immutable override terminalDirectory;\n\n    /** \n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n    constructor(ITerminalDirectory _terminalDirectory) {\n        terminalDirectory = _terminalDirectory;\n    }\n}\n"
    },
    "contracts/Tickets.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\";\nimport \"@paulrberg/contracts/token/erc20/Erc20Permit.sol\";\n\nimport \"./interfaces/ITickets.sol\";\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract Tickets is ERC20, ERC20Permit, Ownable, ITickets {\n    constructor(string memory _name, string memory _symbol)\n        ERC20(_name, _symbol)\n        ERC20Permit(_name)\n    {}\n\n    function print(address _account, uint256 _amount)\n        external\n        override\n        onlyOwner\n    {\n        return _mint(_account, _amount);\n    }\n\n    function redeem(address _account, uint256 _amount)\n        external\n        override\n        onlyOwner\n    {\n        return _burn(_account, _amount);\n    }\n}\n"
    },
    "contracts/interfaces/ITerminalUtility.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./ITerminalDirectory.sol\";\n\ninterface ITerminalUtility {\n    function terminalDirectory() external view returns (ITerminalDirectory);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n        _transfer(_msgSender(), recipient, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        _approve(_msgSender(), spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * Requirements:\n     *\n     * - `sender` and `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``sender``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        _transfer(sender, recipient, amount);\n\n        uint256 currentAllowance = _allowances[sender][_msgSender()];\n        require(currentAllowance >= amount, \"ERC20: transfer amount exceeds allowance\");\n        unchecked {\n            _approve(sender, _msgSender(), currentAllowance - amount);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        uint256 currentAllowance = _allowances[_msgSender()][spender];\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(_msgSender(), spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `sender` to `recipient`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal virtual {\n        require(sender != address(0), \"ERC20: transfer from the zero address\");\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(sender, recipient, amount);\n\n        uint256 senderBalance = _balances[sender];\n        require(senderBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[sender] = senderBalance - amount;\n        }\n        _balances[recipient] += amount;\n\n        emit Transfer(sender, recipient, amount);\n\n        _afterTokenTransfer(sender, recipient, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        _balances[account] += amount;\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n        }\n        _totalSupply -= amount;\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/draft-EIP712.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private immutable _PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    constructor(string memory name) EIP712(name, \"1\") {}\n\n    /**\n     * @dev See {IERC20Permit-permit}.\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    ) public virtual override {\n        require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == owner, \"ERC20Permit: invalid signature\");\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @dev See {IERC20Permit-nonces}.\n     */\n    function nonces(address owner) public view virtual override returns (uint256) {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    /**\n     * @dev \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useNonce(address owner) internal virtual returns (uint256 current) {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n}\n"
    },
    "@paulrberg/contracts/token/erc20/Erc20Permit.sol": {
      "content": "// SPDX-License-Identifier: WTFPL\n// solhint-disable var-name-mixedcase\npragma solidity >=0.8.4;\n\nimport \"./Erc20.sol\";\nimport \"./IErc20Permit.sol\";\n\n/// @notice Emitted when the recovered owner does not match the actual owner.\nerror Erc20Permit__InvalidSignature(uint8 v, bytes32 r, bytes32 s);\n\n/// @notice Emitted when the owner is the zero address.\nerror Erc20Permit__OwnerZeroAddress();\n\n/// @notice Emitted when the permit expired.\nerror Erc20Permit__PermitExpired(uint256 deadline);\n\n/// @notice Emitted when the recovered owner is the zero address.\nerror Erc20Permit__RecoveredOwnerZeroAddress();\n\n/// @notice Emitted when the spender is the zero address.\nerror Erc20Permit__SpenderZeroAddress();\n\n/// @title Erc20Permit\n/// @author Paul Razvan Berg\ncontract Erc20Permit is\n    IErc20Permit, // one dependency\n    Erc20 // one dependency\n{\n    /// PUBLIC STORAGE ///\n\n    /// @inheritdoc IErc20Permit\n    bytes32 public immutable override DOMAIN_SEPARATOR;\n\n    /// @inheritdoc IErc20Permit\n    bytes32 public constant override PERMIT_TYPEHASH =\n        0xfc77c2b9d30fe91687fd39abb7d16fcdfe1472d065740051ab8b13e4bf4a617f;\n\n    /// @inheritdoc IErc20Permit\n    mapping(address => uint256) public override nonces;\n\n    /// @inheritdoc IErc20Permit\n    string public constant override version = \"1\";\n\n    /// CONSTRUCTOR ///\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals\n    ) Erc20(_name, _symbol, _decimals) {\n        uint256 chainId;\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            chainId := chainid()\n        }\n        DOMAIN_SEPARATOR = keccak256(\n            abi.encode(\n                keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                keccak256(bytes(name)),\n                keccak256(bytes(version)),\n                chainId,\n                address(this)\n            )\n        );\n    }\n\n    /// PUBLIC NON-CONSTANT FUNCTIONS ///\n\n    /// @inheritdoc IErc20Permit\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external override {\n        if (owner == address(0)) {\n            revert Erc20Permit__OwnerZeroAddress();\n        }\n        if (spender == address(0)) {\n            revert Erc20Permit__SpenderZeroAddress();\n        }\n        if (deadline < block.timestamp) {\n            revert Erc20Permit__PermitExpired(deadline);\n        }\n\n        // It's safe to use the \"+\" operator here because the nonce cannot realistically overflow, ever.\n        bytes32 hashStruct = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, amount, nonces[owner]++, deadline));\n        bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", DOMAIN_SEPARATOR, hashStruct));\n        address recoveredOwner = ecrecover(digest, v, r, s);\n\n        if (recoveredOwner == address(0)) {\n            revert Erc20Permit__RecoveredOwnerZeroAddress();\n        }\n        if (recoveredOwner != owner) {\n            revert Erc20Permit__InvalidSignature(v, r, s);\n        }\n\n        approveInternal(owner, spender, amount);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\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/draft-IERC20Permit.sol": {
      "content": "// SPDX-License-Identifier: MIT\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/utils/cryptography/draft-EIP712.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n    /* solhint-disable var-name-mixedcase */\n    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n    // invalidate the cached domain separator if the chain id changes.\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n    uint256 private immutable _CACHED_CHAIN_ID;\n\n    bytes32 private immutable _HASHED_NAME;\n    bytes32 private immutable _HASHED_VERSION;\n    bytes32 private immutable _TYPE_HASH;\n\n    /* solhint-enable var-name-mixedcase */\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    constructor(string memory name, string memory version) {\n        bytes32 hashedName = keccak256(bytes(name));\n        bytes32 hashedVersion = keccak256(bytes(version));\n        bytes32 typeHash = keccak256(\n            \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n        );\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _TYPE_HASH = typeHash;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(\n        bytes32 typeHash,\n        bytes32 nameHash,\n        bytes32 versionHash\n    ) private view returns (bytes32) {\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        // Check the signature length\n        // - case 65: r,s,v signature (standard)\n        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return recover(hash, v, r, s);\n        } else if (signature.length == 64) {\n            bytes32 r;\n            bytes32 vs;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            assembly {\n                r := mload(add(signature, 0x20))\n                vs := mload(add(signature, 0x40))\n            }\n            return recover(hash, r, vs);\n        } else {\n            revert(\"ECDSA: invalid signature length\");\n        }\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        bytes32 s;\n        uint8 v;\n        assembly {\n            s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n            v := add(shr(255, vs), 27)\n        }\n        return recover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        require(\n            uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,\n            \"ECDSA: invalid signature 's' value\"\n        );\n        require(v == 27 || v == 28, \"ECDSA: invalid signature 'v' value\");\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        require(signer != address(0), \"ECDSA: invalid signature\");\n\n        return signer;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Counters.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n    struct Counter {\n        // This variable should never be directly accessed by users of the library: interactions must be restricted to\n        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n        // this feature: see https://github.com/ethereum/solidity/issues/4637\n        uint256 _value; // default: 0\n    }\n\n    function current(Counter storage counter) internal view returns (uint256) {\n        return counter._value;\n    }\n\n    function increment(Counter storage counter) internal {\n        unchecked {\n            counter._value += 1;\n        }\n    }\n\n    function decrement(Counter storage counter) internal {\n        uint256 value = counter._value;\n        require(value > 0, \"Counter: decrement overflow\");\n        unchecked {\n            counter._value = value - 1;\n        }\n    }\n\n    function reset(Counter storage counter) internal {\n        counter._value = 0;\n    }\n}\n"
    },
    "@paulrberg/contracts/token/erc20/Erc20.sol": {
      "content": "// SPDX-License-Identifier: WTFPL\npragma solidity >=0.8.4;\n\nimport \"./IErc20.sol\";\n\n/// @notice Emitted when the owner is the zero address.\nerror Erc20__ApproveOwnerZeroAddress();\n\n/// @notice Emitted when the spender is the zero address.\nerror Erc20__ApproveSpenderZeroAddress();\n\n/// @notice Emitted when burning more tokens than are in the account.\nerror Erc20__BurnUnderflow(uint256 accountBalance, uint256 burnAmount);\n\n/// @notice Emitted when the holder is the zero address.\nerror Erc20__BurnZeroAddress();\n\n/// @notice Emitted when the sender did not give the caller a sufficient allowance.\nerror Erc20__InsufficientAllowance(uint256 allowance, uint256 amount);\n\n/// @notice Emitted when the beneficiary is the zero address.\nerror Erc20__MintZeroAddress();\n\n/// @notice Emitted when tranferring more tokens than there are in the account.\nerror Erc20__TransferUnderflow(uint256 senderBalance, uint256 amount);\n\n/// @notice Emitted when the sender is the zero address.\nerror Erc20__TransferSenderZeroAddress();\n\n/// @notice Emitted when the recipient is the zero address.\nerror Erc20__TransferRecipientZeroAddress();\n\n/// @title Erc20\n/// @author Paul Razvan Berg\ncontract Erc20 is IErc20 {\n    /// PUBLIC STORAGE ///\n\n    /// @inheritdoc IErc20\n    string public override name;\n\n    /// @inheritdoc IErc20\n    string public override symbol;\n\n    /// @inheritdoc IErc20\n    uint8 public immutable override decimals;\n\n    /// @inheritdoc IErc20\n    uint256 public override totalSupply;\n\n    /// @inheritdoc IErc20\n    mapping(address => uint256) public override balanceOf;\n\n    /// @inheritdoc IErc20\n    mapping(address => mapping(address => uint256)) public override allowance;\n\n    /// CONSTRUCTOR ///\n\n    /// @notice All three of these values are immutable: they can only be set once during construction.\n    /// @param _name Erc20 name of this token.\n    /// @param _symbol Erc20 symbol of this token.\n    /// @param _decimals Erc20 decimal precision of this token.\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals\n    ) {\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n    }\n\n    /// PUBLIC NON-CONSTANT FUNCTIONS ///\n\n    /// @inheritdoc IErc20\n    function approve(address spender, uint256 amount) external virtual override returns (bool) {\n        approveInternal(msg.sender, spender, amount);\n        return true;\n    }\n\n    /// @inheritdoc IErc20\n    function decreaseAllowance(address spender, uint256 subtractedValue) external virtual override returns (bool) {\n        uint256 newAllowance = allowance[msg.sender][spender] - subtractedValue;\n        approveInternal(msg.sender, spender, newAllowance);\n        return true;\n    }\n\n    /// @inheritdoc IErc20\n    function increaseAllowance(address spender, uint256 addedValue) external virtual override returns (bool) {\n        uint256 newAllowance = allowance[msg.sender][spender] + addedValue;\n        approveInternal(msg.sender, spender, newAllowance);\n        return true;\n    }\n\n    /// @inheritdoc IErc20\n    function transfer(address recipient, uint256 amount) external virtual override returns (bool) {\n        transferInternal(msg.sender, recipient, amount);\n        return true;\n    }\n\n    /// @inheritdoc IErc20\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external virtual override returns (bool) {\n        transferInternal(sender, recipient, amount);\n\n        uint256 currentAllowance = allowance[sender][msg.sender];\n        if (currentAllowance < amount) {\n            revert Erc20__InsufficientAllowance(currentAllowance, amount);\n        }\n        approveInternal(sender, msg.sender, currentAllowance);\n        return true;\n    }\n\n    /// INTERNAL NON-CONSTANT FUNCTIONS ///\n\n    /// @notice Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n    ///\n    /// @dev Emits an {Approval} event.\n    ///\n    /// This is internal function is equivalent to `approve`, and can be used to e.g. set automatic\n    /// allowances for certain subsystems, etc.\n    ///\n    /// Requirements:\n    ///\n    /// - `owner` cannot be the zero address.\n    /// - `spender` cannot be the zero address.\n    function approveInternal(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        if (owner == address(0)) {\n            revert Erc20__ApproveOwnerZeroAddress();\n        }\n        if (spender == address(0)) {\n            revert Erc20__ApproveSpenderZeroAddress();\n        }\n\n        allowance[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /// @notice Destroys `burnAmount` tokens from `holder`, reducing the token supply.\n    ///\n    /// @dev Emits a {Transfer} event.\n    ///\n    /// Requirements:\n    ///\n    /// - `holder` must have at least `amount` tokens.\n    function burnInternal(address holder, uint256 burnAmount) internal {\n        if (holder == address(0)) {\n            revert Erc20__BurnZeroAddress();\n        }\n\n        uint256 accountBalance = balanceOf[holder];\n        if (accountBalance < burnAmount) {\n            revert Erc20__BurnUnderflow(accountBalance, burnAmount);\n        }\n\n        // Burn the tokens.\n        unchecked {\n            balanceOf[holder] = accountBalance - burnAmount;\n        }\n\n        // Reduce the total supply.\n        totalSupply -= burnAmount;\n\n        emit Transfer(holder, address(0), burnAmount);\n    }\n\n    /// @notice Prints new tokens into existence and assigns them to `beneficiary`, increasing the\n    /// total supply.\n    ///\n    /// @dev Emits a {Transfer} event.\n    ///\n    /// Requirements:\n    ///\n    /// - The beneficiary's balance and the total supply cannot overflow.\n    function mintInternal(address beneficiary, uint256 mintAmount) internal {\n        if (beneficiary == address(0)) {\n            revert Erc20__MintZeroAddress();\n        }\n\n        /// Mint the new tokens.\n        balanceOf[beneficiary] += mintAmount;\n\n        /// Increase the total supply.\n        totalSupply += mintAmount;\n\n        emit Transfer(address(0), beneficiary, mintAmount);\n    }\n\n    /// @notice Moves `amount` tokens from `sender` to `recipient`.\n    ///\n    /// @dev This is internal function is equivalent to {transfer}, and can be used to e.g. implement\n    /// automatic token fees, slashing mechanisms, etc.\n    ///\n    /// Emits a {Transfer} event.\n    ///\n    /// Requirements:\n    ///\n    /// - `sender` cannot be the zero address.\n    /// - `recipient` cannot be the zero address.\n    /// - `sender` must have a balance of at least `amount`.\n    function transferInternal(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal virtual {\n        if (sender == address(0)) {\n            revert Erc20__TransferSenderZeroAddress();\n        }\n        if (recipient == address(0)) {\n            revert Erc20__TransferRecipientZeroAddress();\n        }\n\n        uint256 senderBalance = balanceOf[sender];\n        if (senderBalance < amount) {\n            revert Erc20__TransferUnderflow(senderBalance, amount);\n        }\n        unchecked {\n            balanceOf[sender] = senderBalance - amount;\n        }\n\n        balanceOf[recipient] += amount;\n\n        emit Transfer(sender, recipient, amount);\n    }\n}\n"
    },
    "@paulrberg/contracts/token/erc20/IErc20Permit.sol": {
      "content": "// SPDX-License-Identifier: WTFPL\n// solhint-disable func-name-mixedcase\npragma solidity >=0.8.4;\n\nimport \"./IErc20.sol\";\n\n/// @title IErc20Permit\n/// @author Paul Razvan Berg\n/// @notice Extension of Erc20 that allows token holders to use their tokens without sending any\n/// transactions by setting the allowance with a signature using the `permit` method, and then spend\n/// them via `transferFrom`.\n/// @dev See https://eips.ethereum.org/EIPS/eip-2612.\ninterface IErc20Permit is IErc20 {\n    /// NON-CONSTANT FUNCTIONS ///\n\n    /// @notice Sets `amount` as the allowance of `spender` over `owner`'s tokens, assuming the latter's\n    /// signed approval.\n    ///\n    /// @dev Emits an {Approval} event.\n    ///\n    /// IMPORTANT: The same issues Erc20 `approve` has related to transaction\n    /// ordering also apply here.\n    ///\n    /// Requirements:\n    ///\n    /// - `owner` cannot be the zero address.\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` over the Eip712-formatted\n    /// function arguments.\n    /// - The signature must use `owner`'s current nonce.\n    function permit(\n        address owner,\n        address spender,\n        uint256 amount,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /// CONSTANT FUNCTIONS ///\n\n    /// @notice The Eip712 domain's keccak256 hash.\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    /// @notice Provides replay protection.\n    function nonces(address account) external view returns (uint256);\n\n    /// @notice keccak256(\"Permit(address owner,address spender,uint256 amount,uint256 nonce,uint256 deadline)\");\n    function PERMIT_TYPEHASH() external view returns (bytes32);\n\n    /// @notice Eip712 version of this implementation.\n    function version() external view returns (string memory);\n}\n"
    },
    "@paulrberg/contracts/token/erc20/IErc20.sol": {
      "content": "// SPDX-License-Identifier: WTFPL\npragma solidity >=0.8.4;\n\n/// @title IErc20\n/// @author Paul Razvan Berg\n/// @notice Implementation for the Erc20 standard.\n///\n/// We have followed general OpenZeppelin guidelines: functions revert instead of returning\n/// `false` on failure. This behavior is nonetheless conventional and does not conflict with\n/// the with the expectations of Erc20 applications.\n///\n/// Additionally, an {Approval} event is emitted on calls to {transferFrom}. This allows\n/// applications to reconstruct the allowance for all accounts just by listening to said\n/// events. Other implementations of the Erc may not emit these events, as it isn't\n/// required by the specification.\n///\n/// Finally, the non-standard {decreaseAllowance} and {increaseAllowance} functions have been\n/// added to mitigate the well-known issues around setting allowances.\n///\n/// @dev Forked from OpenZeppelin\n/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/ERC20.sol\ninterface IErc20 {\n    /// EVENTS ///\n\n    /// @notice Emitted when an approval happens.\n    /// @param owner The address of the owner of the tokens.\n    /// @param spender The address of the spender.\n    /// @param amount The maximum amount that can be spent.\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /// @notice Emitted when a transfer happens.\n    /// @param from The account sending the tokens.\n    /// @param to The account receiving the tokens.\n    /// @param amount The amount of tokens transferred.\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    /// CONSTANT FUNCTIONS ///\n\n    /// @notice Returns the remaining number of tokens that `spender` will be allowed to spend\n    /// on behalf of `owner` through {transferFrom}. This is zero by default.\n    ///\n    /// @dev This value changes when {approve} or {transferFrom} are called.\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /// @notice Returns the amount of tokens owned by `account`.\n    function balanceOf(address account) external view returns (uint256);\n\n    /// @notice Returns the number of decimals used to get its user representation.\n    function decimals() external view returns (uint8);\n\n    /// @notice Returns the name of the token.\n    function name() external view returns (string memory);\n\n    /// @notice Returns the symbol of the token, usually a shorter version of the name.\n    function symbol() external view returns (string memory);\n\n    /// @notice Returns the amount of tokens in existence.\n    function totalSupply() external view returns (uint256);\n\n    /// NON-CONSTANT FUNCTIONS ///\n\n    /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.\n    ///\n    /// @dev Emits an {Approval} event.\n    ///\n    /// IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may\n    /// use both the old and the new allowance by unfortunate transaction ordering. One possible solution\n    /// to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired\n    /// value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n    ///\n    /// Requirements:\n    ///\n    /// - `spender` cannot be the zero address.\n    ///\n    /// @return a boolean value indicating whether the operation succeeded.\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /// @notice Atomically decreases the allowance granted to `spender` by the caller.\n    ///\n    /// @dev Emits an {Approval} event indicating the updated allowance.\n    ///\n    /// This is an alternative to {approve} that can be used as a mitigation for problems described\n    /// in {Erc20Interface-approve}.\n    ///\n    /// Requirements:\n    ///\n    /// - `spender` cannot be the zero address.\n    /// - `spender` must have allowance for the caller of at least `subtractedValue`.\n    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\n\n    /// @notice Atomically increases the allowance granted to `spender` by the caller.\n    ///\n    /// @dev Emits an {Approval} event indicating the updated allowance.\n    ///\n    /// This is an alternative to {approve} that can be used as a mitigation for the problems described above.\n    ///\n    /// Requirements:\n    ///\n    /// - `spender` cannot be the zero address.\n    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\n\n    /// @notice Moves `amount` tokens from the caller's account to `recipient`.\n    ///\n    /// @dev Emits a {Transfer} event.\n    ///\n    /// Requirements:\n    ///\n    /// - `recipient` cannot be the zero address.\n    /// - The caller must have a balance of at least `amount`.\n    ///\n    /// @return a boolean value indicating whether the operation succeeded.\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /// @notice Moves `amount` tokens from `sender` to `recipient` using the allowance mechanism. `amount`\n    /// `is then deducted from the caller's allowance.\n    ///\n    /// @dev Emits a {Transfer} event and an {Approval} event indicating the updated allowance. This is\n    /// not required by the Erc. See the note at the beginning of {Erc20}.\n    ///\n    /// Requirements:\n    ///\n    /// - `sender` and `recipient` cannot be the zero address.\n    /// - `sender` must have a balance of at least `amount`.\n    /// - The caller must have approed `sender` to spent at least `amount` tokens.\n    ///\n    /// @return a boolean value indicating whether the operation succeeded.\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n}\n"
    },
    "contracts/TokenRepresentationProxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\nimport \"./TicketBooth.sol\";\n\n/** \n  @notice\n  ERC20 wrapper for TicketBooth calls that return both staked + unstaked for a project's token supply.\n*/\ncontract TokenRepresentationProxy is ERC20 {\n    ITicketBooth ticketBooth;\n    uint256 projectId;\n\n    constructor(\n        ITicketBooth _ticketBooth,\n        uint256 _projectId,\n        string memory name,\n        string memory ticker\n    ) ERC20(name, ticker) {\n        ticketBooth = _ticketBooth;\n        projectId = _projectId;\n    }\n\n    function totalSupply() public view virtual override returns (uint256) {\n        return ticketBooth.totalSupplyOf(projectId);\n    }\n\n    function balanceOf(address _account) public view virtual override returns (uint256) {\n        return ticketBooth.balanceOf(_account, projectId);\n    }\n}"
    },
    "contracts/YearnYielder.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"@paulrberg/contracts/math/PRBMath.sol\";\n\nimport \"./interfaces/IYielder.sol\";\nimport \"./interfaces/ITerminalV1.sol\";\nimport \"./interfaces/IyVaultV2.sol\";\nimport \"./interfaces/IWETH.sol\";\n\ncontract YearnYielder is IYielder, Ownable {\n    using SafeERC20 for IERC20;\n\n    IyVaultV2 public wethVault =\n        IyVaultV2(0xa9fE4601811213c340e850ea305481afF02f5b28);\n\n    address public weth;\n\n    uint256 public override deposited = 0;\n\n    uint256 public decimals;\n\n    constructor(address _weth) {\n        require(wethVault.token() == _weth, \"YearnYielder: INCOMPATIBLE\");\n        weth = _weth;\n        decimals = IWETH(weth).decimals();\n        updateApproval();\n    }\n\n    function getCurrentBalance() public view override returns (uint256) {\n        return _sharesToTokens(wethVault.balanceOf(address(this)));\n    }\n\n    function deposit() external payable override onlyOwner {\n        IWETH(weth).deposit{value: msg.value}();\n        wethVault.deposit(msg.value);\n        deposited = deposited + msg.value;\n    }\n\n    function withdraw(uint256 _amount, address payable _beneficiary)\n        public\n        override\n        onlyOwner\n    {\n        // Reduce the proportional amount that has been deposited before the withdrawl.\n        deposited =\n            deposited -\n            PRBMath.mulDiv(_amount, deposited, getCurrentBalance());\n\n        // Withdraw the amount of tokens from the vault.\n        wethVault.withdraw(_tokensToShares(_amount));\n\n        // Convert weth back to eth.\n        IWETH(weth).withdraw(_amount);\n\n        // Move the funds to the TerminalV1.\n        _beneficiary.transfer(_amount);\n    }\n\n    function withdrawAll(address payable _beneficiary)\n        external\n        override\n        onlyOwner\n        returns (uint256 _balance)\n    {\n        _balance = getCurrentBalance();\n        withdraw(_balance, _beneficiary);\n    }\n\n    /// @dev Updates the vaults approval of the token to be the maximum value.\n    function updateApproval() public {\n        IERC20(weth).safeApprove(address(wethVault), type(uint256).max);\n    }\n\n    /// @dev Computes the number of tokens an amount of shares is worth.\n    ///\n    /// @param _sharesAmount the amount of shares.\n    ///\n    /// @return the number of tokens the shares are worth.\n    function _sharesToTokens(uint256 _sharesAmount)\n        private\n        view\n        returns (uint256)\n    {\n        return\n            PRBMath.mulDiv(\n                _sharesAmount,\n                wethVault.pricePerShare(),\n                10**decimals\n            );\n    }\n\n    /// @dev Computes the number of shares an amount of tokens is worth.\n    ///\n    /// @param _tokensAmount the amount of shares.\n    ///\n    /// @return the number of shares the tokens are worth.\n    function _tokensToShares(uint256 _tokensAmount)\n        private\n        view\n        returns (uint256)\n    {\n        return\n            PRBMath.mulDiv(\n                _tokensAmount,\n                10**decimals,\n                wethVault.pricePerShare()\n            );\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
    },
    "contracts/interfaces/IyVaultV2.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IyVaultV2 is IERC20 {\n    function token() external view returns (address);\n\n    function deposit() external returns (uint256);\n\n    function deposit(uint256) external returns (uint256);\n\n    function deposit(uint256, address) external returns (uint256);\n\n    function withdraw() external returns (uint256);\n\n    function withdraw(uint256) external returns (uint256);\n\n    function withdraw(uint256, address) external returns (uint256);\n\n    function withdraw(\n        uint256,\n        address,\n        uint256\n    ) external returns (uint256);\n\n    function permit(\n        address,\n        address,\n        uint256,\n        uint256,\n        bytes32\n    ) external view returns (bool);\n\n    function pricePerShare() external view returns (uint256);\n\n    function apiVersion() external view returns (string memory);\n\n    function totalAssets() external view returns (uint256);\n\n    function maxAvailableShares() external view returns (uint256);\n\n    function debtOutstanding() external view returns (uint256);\n\n    function debtOutstanding(address strategy) external view returns (uint256);\n\n    function creditAvailable() external view returns (uint256);\n\n    function creditAvailable(address strategy) external view returns (uint256);\n\n    function availableDepositLimit() external view returns (uint256);\n\n    function expectedReturn() external view returns (uint256);\n\n    function expectedReturn(address strategy) external view returns (uint256);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint256);\n\n    function balanceOf(address owner) external view override returns (uint256);\n\n    function totalSupply() external view override returns (uint256);\n\n    function governance() external view returns (address);\n\n    function management() external view returns (address);\n\n    function guardian() external view returns (address);\n\n    function guestList() external view returns (address);\n\n    function strategies(address)\n        external\n        view\n        returns (\n            uint256,\n            uint256,\n            uint256,\n            uint256,\n            uint256,\n            uint256,\n            uint256,\n            uint256\n        );\n\n    function withdrawalQueue(uint256) external view returns (address);\n\n    function emergencyShutdown() external view returns (bool);\n\n    function depositLimit() external view returns (uint256);\n\n    function debtRatio() external view returns (uint256);\n\n    function totalDebt() external view returns (uint256);\n\n    function lastReport() external view returns (uint256);\n\n    function activation() external view returns (uint256);\n\n    function rewards() external view returns (address);\n\n    function managementFee() external view returns (uint256);\n\n    function performanceFee() external view returns (uint256);\n}\n"
    },
    "contracts/interfaces/IWETH.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\ninterface IWETH {\n    function decimals() external view returns (uint256);\n\n    function deposit() external payable;\n\n    function withdraw(uint256 wad) external;\n\n    event Deposit(address indexed dst, uint256 wad);\n    event Withdrawal(address indexed src, uint256 wad);\n}\n"
    },
    "contracts/TerminalV1_1.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport '@openzeppelin/contracts/security/ReentrancyGuard.sol';\nimport '@openzeppelin/contracts/utils/Address.sol';\n\nimport '@paulrberg/contracts/math/PRBMath.sol';\nimport '@paulrberg/contracts/math/PRBMathUD60x18.sol';\n\nimport './interfaces/ITerminalV1_1.sol';\nimport './abstract/JuiceboxProject.sol';\nimport './abstract/Operatable.sol';\n\nimport './libraries/Operations.sol';\n\n/**\n  ─────────────────────────────────────────────────────────────────────────────────────────────────\n  ─────────██████──███████──██████──██████████──██████████████──██████████████──████████████████───\n  ─────────██░░██──███░░██──██░░██──██░░░░░░██──██░░░░░░░░░░██──██░░░░░░░░░░██──██░░░░░░░░░░░░██───\n  ─────────██░░██──███░░██──██░░██──████░░████──██░░██████████──██░░██████████──██░░████████░░██───\n  ─────────██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██──────────██░░██────██░░██───\n  ─────────██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██████████──██░░████████░░██───\n  ─────────██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░░░░░░░░░██──██░░░░░░░░░░░░██───\n  ─██████──██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██████████──██░░██████░░████───\n  ─██░░██──██░░██──███░░██──██░░██────██░░██────██░░██──────────██░░██──────────██░░██──██░░██─────\n  ─██░░██████░░██──███░░██████░░██──████░░████──██░░██████████──██░░██████████──██░░██──██░░██████─\n  ─██░░░░░░░░░░██──███░░░░░░░░░░██──██░░░░░░██──██░░░░░░░░░░██──██░░░░░░░░░░██──██░░██──██░░░░░░██─\n  ─██████████████──███████████████──██████████──██████████████──██████████████──██████──██████████─\n  ───────────────────────────────────────────────────────────────────────────────────────────\n\n  @notice \n  This contract manages the Juicebox ecosystem, serves as a payment terminal, and custodies all funds.\n\n  @dev \n  A project can transfer its funds, along with the power to reconfigure and mint/burn their Tickets, from this contract to another allowed terminal contract at any time.\n*/\ncontract TerminalV1_1 is Operatable, ITerminalV1_1, ITerminal, ReentrancyGuard {\n  // Modifier to only allow governance to call the function.\n  modifier onlyGov() {\n    require(msg.sender == governance, 'TerminalV1_1: UNAUTHORIZED');\n    _;\n  }\n\n  // --- private stored properties --- //\n\n  // The difference between the processed ticket tracker of a project and the project's ticket's total supply is the amount of tickets that\n  // still need to have reserves printed against them.\n  mapping(uint256 => int256) private _processedTicketTrackerOf;\n\n  // --- public immutable stored properties --- //\n\n  /// @notice The Projects contract which mints ERC-721's that represent project ownership and transfers.\n  IProjects public immutable override projects;\n\n  /// @notice The contract storing all funding cycle configurations.\n  IFundingCycles public immutable override fundingCycles;\n\n  /// @notice The contract that manages Ticket printing and redeeming.\n  ITicketBooth public immutable override ticketBooth;\n\n  /// @notice The contract that stores mods for each project.\n  IModStore public immutable override modStore;\n\n  /// @notice The prices feeds.\n  IPrices public immutable override prices;\n\n  /// @notice The directory of terminals.\n  ITerminalDirectory public immutable override terminalDirectory;\n\n  // --- public stored properties --- //\n\n  /// @notice The amount of ETH that each project is responsible for.\n  mapping(uint256 => uint256) public override balanceOf;\n\n  /// @notice The percent fee the Juicebox project takes from tapped amounts. Out of 200.\n  uint256 public override fee = 10;\n\n  /// @notice The governance of the contract who makes fees and can allow new TerminalV1 contracts to be migrated to by project owners.\n  address payable public override governance;\n\n  /// @notice The governance of the contract who makes fees and can allow new TerminalV1 contracts to be migrated to by project owners.\n  address payable public override pendingGovernance;\n\n  // Whether or not a particular contract is available for projects to migrate their funds and Tickets to.\n  mapping(ITerminal => bool) public override migrationIsAllowed;\n\n  // --- external views --- //\n\n  /** \n      @notice \n      Gets the current overflowed amount for a specified project.\n\n      @param _projectId The ID of the project to get overflow for.\n\n      @return overflow The current overflow of funds for the project.\n    */\n  function currentOverflowOf(uint256 _projectId) external view override returns (uint256 overflow) {\n    // Get a reference to the project's current funding cycle.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    return _overflowFrom(_fundingCycle);\n  }\n\n  /** \n      @notice \n      Gets the amount of reserved tickets that a project has.\n\n      @param _projectId The ID of the project to get overflow for.\n      @param _reservedRate The reserved rate to use to make the calculation.\n\n      @return amount overflow The current overflow of funds for the project.\n    */\n  function reservedTicketBalanceOf(uint256 _projectId, uint256 _reservedRate)\n    external\n    view\n    override\n    returns (uint256)\n  {\n    return\n      _reservedTicketAmountFrom(\n        _processedTicketTrackerOf[_projectId],\n        _reservedRate,\n        ticketBooth.totalSupplyOf(_projectId)\n      );\n  }\n\n  // --- public views --- //\n\n  /**\n      @notice \n      The amount of tokens that can be claimed by the given address.\n\n      @dev The _account must have at least _count tickets for the specified project.\n      @dev If there is a funding cycle reconfiguration ballot open for the project, the project's current bonding curve is bypassed.\n\n      @param _account The address to get an amount for.\n      @param _projectId The ID of the project to get a claimable amount for.\n      @param _count The number of Tickets that would be redeemed to get the resulting amount.\n\n      @return amount The amount of tokens that can be claimed.\n    */\n  function claimableOverflowOf(\n    address _account,\n    uint256 _projectId,\n    uint256 _count\n  ) public view override returns (uint256) {\n    // The holder must have the specified number of the project's tickets.\n    require(\n      ticketBooth.balanceOf(_account, _projectId) >= _count,\n      'TV1_1::claimableOverflow: INSUFFICIENT_TICKETS'\n    );\n\n    // Get a reference to the current funding cycle for the project.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // There's no overflow if there's no funding cycle.\n    if (_fundingCycle.id == 0) return 0;\n\n    // Get the amount of current overflow.\n    uint256 _redeemableOverflow = _overflowFrom(_fundingCycle);\n\n    if (uint160(_fundingCycle.metadata >> 34) != 0)\n      _redeemableOverflow =\n        _redeemableOverflow +\n        ITreasuryExtension(address(uint160(_fundingCycle.metadata >> 34))).ETHValue();\n\n    // If there is no redeemable overflow, nothing is claimable.\n    if (_redeemableOverflow == 0) return 0;\n\n    // Get the total number of tickets in circulation.\n    uint256 _totalSupply = ticketBooth.totalSupplyOf(_projectId);\n\n    // Get the number of reserved tickets the project has.\n    // The reserved rate is in bits 8-15 of the metadata.\n    uint256 _reservedTicketAmount = _reservedTicketAmountFrom(\n      _processedTicketTrackerOf[_projectId],\n      uint256(uint8(_fundingCycle.metadata >> 8)),\n      _totalSupply\n    );\n\n    // If there are reserved tickets, add them to the total supply.\n    if (_reservedTicketAmount > 0) _totalSupply = _totalSupply + _reservedTicketAmount;\n\n    // If the amount being redeemed is the the total supply, return the rest of the overflow.\n    if (_count == _totalSupply) return _redeemableOverflow;\n\n    // Get a reference to the linear proportion.\n    uint256 _base = PRBMath.mulDiv(_redeemableOverflow, _count, _totalSupply);\n\n    // Use the reconfiguration bonding curve if the queued cycle is pending approval according to the previous funding cycle's ballot.\n    uint256 _bondingCurveRate = fundingCycles.currentBallotStateOf(_projectId) == BallotState.Active // The reconfiguration bonding curve rate is stored in bytes 24-31 of the metadata property.\n      ? uint256(uint8(_fundingCycle.metadata >> 24)) // The bonding curve rate is stored in bytes 16-23 of the data property after.\n      : uint256(uint8(_fundingCycle.metadata >> 16));\n\n    // The bonding curve formula.\n    // https://www.desmos.com/calculator/sp9ru6zbpk\n    // where x is _count, o is _currentOverflow, s is _totalSupply, and r is _bondingCurveRate.\n\n    // These conditions are all part of the same curve. Edge conditions are separated because fewer operation are necessary.\n    if (_bondingCurveRate == 200) return _base;\n    if (_bondingCurveRate == 0) return PRBMath.mulDiv(_base, _count, _totalSupply);\n    return\n      PRBMath.mulDiv(\n        _base,\n        _bondingCurveRate + PRBMath.mulDiv(_count, 200 - _bondingCurveRate, _totalSupply),\n        200\n      );\n  }\n\n  // --- external transactions --- //\n\n  /** \n      @param _projects A Projects contract which mints ERC-721's that represent project ownership and transfers.\n      @param _fundingCycles A funding cycle configuration store.\n      @param _ticketBooth A contract that manages Ticket printing and redeeming.\n      @param _operatorStore A contract storing operator assignments.\n      @param _modStore A storage for a project's mods.\n      @param _prices A price feed contract to use.\n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n  constructor(\n    IProjects _projects,\n    IFundingCycles _fundingCycles,\n    ITicketBooth _ticketBooth,\n    IOperatorStore _operatorStore,\n    IModStore _modStore,\n    IPrices _prices,\n    ITerminalDirectory _terminalDirectory,\n    address payable _governance\n  ) Operatable(_operatorStore) {\n    require(\n      _projects != IProjects(address(0)) &&\n        _fundingCycles != IFundingCycles(address(0)) &&\n        _ticketBooth != ITicketBooth(address(0)) &&\n        _modStore != IModStore(address(0)) &&\n        _prices != IPrices(address(0)) &&\n        _terminalDirectory != ITerminalDirectory(address(0)) &&\n        _governance != address(address(0)),\n      'TerminalV1: ZERO_ADDRESS'\n    );\n    projects = _projects;\n    fundingCycles = _fundingCycles;\n    ticketBooth = _ticketBooth;\n    modStore = _modStore;\n    prices = _prices;\n    terminalDirectory = _terminalDirectory;\n    governance = _governance;\n  }\n\n  /**\n      @notice \n      Deploys a project. This will mint an ERC-721 into the `_owner`'s account, configure a first funding cycle, and set up any mods.\n\n      @dev\n      Each operation withing this transaction can be done in sequence separately.\n\n      @dev\n      Anyone can deploy a project on an owner's behalf.\n\n      @param _owner The address that will own the project.\n      @param _handle The project's unique handle.\n      @param _uri A link to information about the project and this funding cycle.\n      @param _properties The funding cycle configuration.\n        @dev _properties.target The amount that the project wants to receive in this funding cycle. Sent as a wad.\n        @dev _properties.currency The currency of the `target`. Send 0 for ETH or 1 for USD.\n        @dev _properties.duration The duration of the funding stage for which the `target` amount is needed. Measured in days. Send 0 for a boundless cycle reconfigurable at any time.\n        @dev _properties.cycleLimit The number of cycles that this configuration should last for before going back to the last permanent. This has no effect for a project's first funding cycle.\n        @dev _properties.discountRate A number from 0-200 indicating how valuable a contribution to this funding stage is compared to the project's previous funding stage.\n          If it's 200, each funding stage will have equal weight.\n          If the number is 180, a contribution to the next funding stage will only give you 90% of tickets given to a contribution of the same amount during the current funding stage.\n          If the number is 0, an non-recurring funding stage will get made.\n        @dev _properties.ballot The new ballot that will be used to approve subsequent reconfigurations.\n      @param _metadata A struct specifying the TerminalV1 specific params _bondingCurveRate, and _reservedRate.\n        @dev _metadata.reservedRate A number from 0-200 indicating the percentage of each contribution's tickets that will be reserved for the project owner.\n        @dev _metadata.bondingCurveRate The rate from 0-200 at which a project's Tickets can be redeemed for surplus.\n          The bonding curve formula is https://www.desmos.com/calculator/sp9ru6zbpk\n          where x is _count, o is _currentOverflow, s is _totalSupply, and r is _bondingCurveRate.\n        @dev _metadata.reconfigurationBondingCurveRate The bonding curve rate to apply when there is an active ballot.\n      @param _payoutMods Any payout mods to set.\n      @param _ticketMods Any ticket mods to set.\n    */\n  function deploy(\n    address _owner,\n    bytes32 _handle,\n    string calldata _uri,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata2 calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  ) external override {\n    // Make sure the metadata checks out. If it does, return a packed version of it.\n    uint256 _packedMetadata = _validateAndPackFundingCycleMetadata(_metadata);\n\n    // Create the project for the owner.\n    uint256 _projectId = projects.create(_owner, _handle, _uri, this);\n\n    // Configure the funding stage's state.\n    FundingCycle memory _fundingCycle = fundingCycles.configure(\n      _projectId,\n      _properties,\n      _packedMetadata,\n      fee,\n      true\n    );\n\n    // Set payout mods if there are any.\n    if (_payoutMods.length > 0)\n      modStore.setPayoutMods(_projectId, _fundingCycle.configured, _payoutMods);\n\n    // Set ticket mods if there are any.\n    if (_ticketMods.length > 0)\n      modStore.setTicketMods(_projectId, _fundingCycle.configured, _ticketMods);\n  }\n\n  /**\n      @notice \n      Configures the properties of the current funding cycle if the project hasn't distributed tickets yet, or\n      sets the properties of the proposed funding cycle that will take effect once the current one expires\n      if it is approved by the current funding cycle's ballot.\n\n      @dev\n      Only a project's owner or a designated operator can configure its funding cycles.\n\n      @param _projectId The ID of the project being reconfigured. \n      @param _properties The funding cycle configuration.\n        @dev _properties.target The amount that the project wants to receive in this funding stage. Sent as a wad.\n        @dev _properties.currency The currency of the `target`. Send 0 for ETH or 1 for USD.\n        @dev _properties.duration The duration of the funding stage for which the `target` amount is needed. Measured in days. Send 0 for a boundless cycle reconfigurable at any time.\n        @dev _properties.cycleLimit The number of cycles that this configuration should last for before going back to the last permanent. This has no effect for a project's first funding cycle.\n        @dev _properties.discountRate A number from 0-200 indicating how valuable a contribution to this funding stage is compared to the project's previous funding stage.\n          If it's 200, each funding stage will have equal weight.\n          If the number is 180, a contribution to the next funding stage will only give you 90% of tickets given to a contribution of the same amount during the current funding stage.\n          If the number is 0, an non-recurring funding stage will get made.\n        @dev _properties.ballot The new ballot that will be used to approve subsequent reconfigurations.\n      @param _metadata A struct specifying the TerminalV1 specific params _bondingCurveRate, and _reservedRate.\n        @dev _metadata.reservedRate A number from 0-200 indicating the percentage of each contribution's tickets that will be reserved for the project owner.\n        @dev _metadata.bondingCurveRate The rate from 0-200 at which a project's Tickets can be redeemed for surplus.\n          The bonding curve formula is https://www.desmos.com/calculator/sp9ru6zbpk\n          where x is _count, o is _currentOverflow, s is _totalSupply, and r is _bondingCurveRate.\n        @dev _metadata.reconfigurationBondingCurveRate The bonding curve rate to apply when there is an active ballot.\n\n      @return The ID of the funding cycle that was successfully configured.\n    */\n  function configure(\n    uint256 _projectId,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata2 calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  )\n    external\n    override\n    requirePermission(projects.ownerOf(_projectId), _projectId, Operations.Configure)\n    returns (uint256)\n  {\n    // Make sure the metadata is validated, and pack it into a uint256.\n    uint256 _packedMetadata = _validateAndPackFundingCycleMetadata(_metadata);\n\n    // Configure the funding stage's state.\n    FundingCycle memory _fundingCycle = fundingCycles.configure(\n      _projectId,\n      _properties,\n      _packedMetadata,\n      fee,\n      false\n    );\n\n    // Set payout mods for the new configuration if there are any.\n    if (_payoutMods.length > 0)\n      modStore.setPayoutMods(_projectId, _fundingCycle.configured, _payoutMods);\n\n    // Set payout mods for the new configuration if there are any.\n    if (_ticketMods.length > 0)\n      modStore.setTicketMods(_projectId, _fundingCycle.configured, _ticketMods);\n\n    return _fundingCycle.id;\n  }\n\n  /** \n      @notice \n      Allows a project to print tickets for a specified beneficiary.\n\n      @dev\n      Only a project's owner or a designated operator can print tickets.\n\n      @param _projectId The ID of the project to print tickets for.\n      @param _amount The amount of tickets to print.\n      @param _beneficiary The address to send the printed tickets to.\n      @param _memo A memo to leave with the printing.\n      @param _preferUnstakedTickets If there is a preference to unstake the printed tickets.\n    */\n  function printTickets(\n    uint256 _projectId,\n    uint256 _amount,\n    address _beneficiary,\n    string memory _memo,\n    bool _preferUnstakedTickets\n  )\n    external\n    override\n    requirePermission(projects.ownerOf(_projectId), _projectId, Operations.PrintTickets)\n  {\n    // Can't send to the zero address.\n    require(_beneficiary != address(0), 'TV1_1::printTickets: ZERO_ADDRESS');\n\n    // Get a reference to the current funding cycle for the project.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // Make sure printing is allowed if a funding cycle exists.\n    require(\n      _fundingCycle.number == 0 || ((_fundingCycle.metadata >> 33) & 1) == 1,\n      'TV1_1::printTickets: NOT_ALLOWED'\n    );\n\n    // Set the preconfigure tickets as processed so that reserved tickets cant be minted against them.\n    // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n    require(\n      _processedTicketTrackerOf[_projectId] < 0 ||\n        uint256(_processedTicketTrackerOf[_projectId]) + _amount <= uint256(type(int256).max),\n      'TV1_1::printTickets: INT_LIMIT_REACHED'\n    );\n\n    _processedTicketTrackerOf[_projectId] = _processedTicketTrackerOf[_projectId] + int256(_amount);\n\n    // Print the project's tickets for the beneficiary.\n    ticketBooth.print(_beneficiary, _projectId, _amount, _preferUnstakedTickets);\n\n    emit PrintTickets(_projectId, _beneficiary, _amount, _memo, msg.sender);\n  }\n\n  /**\n      @notice \n      Contribute ETH to a project.\n\n      @dev \n      Print's the project's tickets proportional to the amount of the contribution.\n\n      @dev \n      The msg.value is the amount of the contribution in wei.\n\n      @param _projectId The ID of the project being contribute to.\n      @param _beneficiary The address to print Tickets for. \n      @param _memo A memo that will be included in the published event.\n      @param _preferUnstakedTickets Whether ERC20's should be unstaked automatically if they have been issued.\n\n      @return The ID of the funding cycle that the payment was made during.\n    */\n  function pay(\n    uint256 _projectId,\n    address _beneficiary,\n    string calldata _memo,\n    bool _preferUnstakedTickets\n  ) external payable override returns (uint256) {\n    // Positive payments only.\n    require(msg.value > 0, 'TV1_1::pay: BAD_AMOUNT');\n\n    // Cant send tickets to the zero address.\n    require(_beneficiary != address(0), 'TV1_1::pay: ZERO_ADDRESS');\n\n    return _pay(_projectId, msg.value, _beneficiary, _memo, _preferUnstakedTickets);\n  }\n\n  /**\n      @notice \n      Tap into funds that have been contributed to a project's current funding cycle.\n\n      @dev\n      Anyone can tap funds on a project's behalf.\n\n      @param _projectId The ID of the project to which the funding cycle being tapped belongs.\n      @param _amount The amount being tapped, in the funding cycle's currency.\n      @param _currency The expected currency being tapped.\n      @param _minReturnedWei The minimum number of wei that the amount should be valued at.\n\n      @return The ID of the funding cycle that was tapped.\n    */\n  function tap(\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _currency,\n    uint256 _minReturnedWei\n  ) external override nonReentrant returns (uint256) {\n    // Register the funds as tapped. Get the ID of the funding cycle that was tapped.\n    FundingCycle memory _fundingCycle = fundingCycles.tap(_projectId, _amount);\n\n    // If there's no funding cycle, there are no funds to tap.\n    if (_fundingCycle.id == 0) return 0;\n\n    // Make sure the currency's match.\n    require(_currency == _fundingCycle.currency, 'TV1_1::tap: UNEXPECTED_CURRENCY');\n\n    // Get a reference to this project's current balance, including any earned yield.\n    // Get the currency price of ETH.\n    uint256 _ethPrice = prices.getETHPriceFor(_fundingCycle.currency);\n\n    // Get the price of ETH.\n    // The amount of ETH that is being tapped.\n    uint256 _tappedWeiAmount = PRBMathUD60x18.div(_amount, _ethPrice);\n\n    // The amount being tapped must be at least as much as was expected.\n    require(_minReturnedWei <= _tappedWeiAmount, 'TV1_1::tap: INADEQUATE');\n\n    // Get a reference to this project's current balance, including any earned yield.\n    uint256 _balance = balanceOf[_fundingCycle.projectId];\n\n    // The amount being tapped must be available.\n    require(_tappedWeiAmount <= _balance, 'TV1_1::tap: INSUFFICIENT_FUNDS');\n\n    // Removed the tapped funds from the project's balance.\n    balanceOf[_projectId] = _balance - _tappedWeiAmount;\n\n    // Get a reference to the project owner, which will receive the admin's tickets from paying the fee,\n    // and receive any extra tapped funds not allocated to mods.\n    address payable _projectOwner = payable(projects.ownerOf(_fundingCycle.projectId));\n\n    // Get a reference to the handle of the project paying the fee and sending payouts.\n    bytes32 _handle = projects.handleOf(_projectId);\n\n    // Take a fee from the _tappedWeiAmount, if needed.\n    // The project's owner will be the beneficiary of the resulting printed tickets from the governance project.\n    uint256 _feeAmount = _fundingCycle.fee > 0\n      ? _takeFee(\n        _tappedWeiAmount,\n        _fundingCycle.fee,\n        _projectOwner,\n        string(bytes.concat('Fee from @', _handle))\n      )\n      : 0;\n\n    // Payout to mods and get a reference to the leftover transfer amount after all mods have been paid.\n    // The net transfer amount is the tapped amount minus the fee.\n    uint256 _leftoverTransferAmount = _distributeToPayoutMods(\n      _fundingCycle,\n      _tappedWeiAmount - _feeAmount,\n      string(bytes.concat('Payout from @', _handle))\n    );\n\n    // Transfer any remaining balance to the beneficiary.\n    if (_leftoverTransferAmount > 0) Address.sendValue(_projectOwner, _leftoverTransferAmount);\n\n    emit Tap(\n      _fundingCycle.id,\n      _fundingCycle.projectId,\n      _projectOwner,\n      _amount,\n      _fundingCycle.currency,\n      _tappedWeiAmount - _feeAmount,\n      _leftoverTransferAmount,\n      _feeAmount,\n      msg.sender\n    );\n\n    return _fundingCycle.id;\n  }\n\n  /**\n      @notice \n      Addresses can redeem their Tickets to claim the project's overflowed ETH.\n\n      @dev\n      Only a ticket's holder or a designated operator can redeem it.\n\n      @param _account The account to redeem tickets for.\n      @param _projectId The ID of the project to which the Tickets being redeemed belong.\n      @param _count The number of Tickets to redeem.\n      @param _minReturnedWei The minimum amount of Wei expected in return.\n      @param _beneficiary The address to send the ETH to.\n      @param _preferUnstaked If the preference is to redeem tickets that have been converted to ERC-20s.\n\n      @return amount The amount of ETH that the tickets were redeemed for.\n    */\n  function redeem(\n    address _account,\n    uint256 _projectId,\n    uint256 _count,\n    uint256 _minReturnedWei,\n    address payable _beneficiary,\n    bool _preferUnstaked\n  )\n    external\n    override\n    nonReentrant\n    requirePermissionAllowingWildcardDomain(_account, _projectId, Operations.Redeem)\n    returns (uint256 amount)\n  {\n    // There must be an amount specified to redeem.\n    require(_count > 0, 'TV1_1::redeem: NO_OP');\n\n    // Can't send claimed funds to the zero address.\n    require(_beneficiary != address(0), 'TV1_1::redeem: ZERO_ADDRESS');\n\n    // The amount of ETH claimable by the message sender from the specified project by redeeming the specified number of tickets.\n    amount = claimableOverflowOf(_account, _projectId, _count);\n\n    // The amount being claimed must be at least as much as was expected.\n    require(amount >= _minReturnedWei, 'TV1_1::redeem: INADEQUATE');\n\n    if (amount > 0)\n      // Remove the redeemed funds from the project's balance.\n      balanceOf[_projectId] = balanceOf[_projectId] - amount;\n\n    // Get a reference to the processed ticket tracker for the project.\n    int256 _processedTicketTracker = _processedTicketTrackerOf[_projectId];\n\n    // Subtract the count from the processed ticket tracker.\n    // Subtract from processed tickets so that the difference between whats been processed and the\n    // total supply remains the same.\n    // If there are at least as many processed tickets as there are tickets being redeemed,\n    // the processed ticket tracker of the project will be positive. Otherwise it will be negative.\n    _processedTicketTrackerOf[_projectId] = _processedTicketTracker < 0 // If the tracker is negative, add the count and reverse it.\n      ? -int256(uint256(-_processedTicketTracker) + _count) // the tracker is less than the count, subtract it from the count and reverse it.\n      : _processedTicketTracker < int256(_count)\n      ? -(int256(_count) - _processedTicketTracker) // simply subtract otherwise.\n      : _processedTicketTracker - int256(_count);\n\n    // Redeem the tickets, which burns them.\n    ticketBooth.redeem(_account, _projectId, _count, _preferUnstaked);\n\n    if (amount > 0)\n      // Transfer funds to the specified address.\n      Address.sendValue(_beneficiary, amount);\n\n    emit Redeem(_account, _beneficiary, _projectId, _count, amount, msg.sender);\n  }\n\n  /**\n      @notice \n      Allows a project owner to migrate its funds and operations to a new contract.\n\n      @dev\n      Only a project's owner or a designated operator can migrate it.\n\n      @param _projectId The ID of the project being migrated.\n      @param _to The contract that will gain the project's funds.\n    */\n  function migrate(uint256 _projectId, ITerminal _to)\n    external\n    override\n    requirePermission(projects.ownerOf(_projectId), _projectId, Operations.Migrate)\n    nonReentrant\n  {\n    // This TerminalV1 must be the project's current terminal.\n    require(\n      terminalDirectory.terminalOf(_projectId) == this,\n      'TV1_1::migrate: UNAUTHORIZED'\n    );\n\n    // The migration destination must be allowed.\n    require(migrationIsAllowed[_to], 'TV1_1::migrate: NOT_ALLOWED');\n\n    // All reserved tickets must be printed before migrating.\n    if (uint256(_processedTicketTrackerOf[_projectId]) != ticketBooth.totalSupplyOf(_projectId))\n      printReservedTickets(_projectId);\n\n    // Get a reference to this project's current balance, included any earned yield.\n    uint256 _balanceOf = balanceOf[_projectId];\n\n    // Set the balance to 0.\n    balanceOf[_projectId] = 0;\n\n    // Move the funds to the new contract if needed.\n    if (_balanceOf > 0) _to.addToBalance{value: _balanceOf}(_projectId);\n\n    // Switch the direct payment terminal.\n    terminalDirectory.setTerminal(_projectId, _to);\n\n    emit Migrate(_projectId, _to, _balanceOf, msg.sender);\n  }\n\n  /** \n      @notice \n      Receives and allocates funds belonging to the specified project.\n\n      @param _projectId The ID of the project to which the funds received belong.\n    */\n  function addToBalance(uint256 _projectId) external payable override {\n    // The amount must be positive.\n    require(msg.value > 0, 'TV1_1::addToBalance: BAD_AMOUNT');\n\n    // If moving funds over, make sure the tokens moving over are also\n    if (terminalDirectory.terminalOf(_projectId) != this)\n      _processedTicketTrackerOf[_projectId] = int256(ticketBooth.totalSupplyOf(_projectId));\n\n    balanceOf[_projectId] = balanceOf[_projectId] + msg.value;\n    emit AddToBalance(_projectId, msg.value, msg.sender);\n  }\n\n  /**\n      @notice \n      Adds to the contract addresses that projects can migrate their Tickets to.\n\n      @dev\n      Only governance can add a contract to the migration allow list.\n\n      @param _contract The contract to allow.\n    */\n  function allowMigration(ITerminal _contract) external override onlyGov {\n    // Can't allow the zero address.\n    require(_contract != ITerminal(address(0)), 'TV1_1::allowMigration: ZERO_ADDRESS');\n\n    // Can't migrate to this same contract\n    require(_contract != this, 'TV1_1::allowMigration: NO_OP');\n\n    // Set the contract as allowed\n    migrationIsAllowed[_contract] = true;\n\n    emit AllowMigration(_contract);\n  }\n\n  /** \n      @notice \n      Allow the admin to change the fee. \n\n      @dev\n      Only funding cycle reconfigurations after the new fee is set will use the new fee.\n      All future funding cycles based on configurations made in the past will use the fee that was set at the time of the configuration.\n    \n      @dev\n      Only governance can set a new fee.\n\n      @param _fee The new fee percent. Out of 200.\n    */\n  function setFee(uint256 _fee) external override onlyGov {\n    // Fee must be under 100%.\n    require(_fee <= 200, 'TV1_1::setFee: BAD_FEE');\n\n    // Set the fee.\n    fee = _fee;\n\n    emit SetFee(_fee);\n  }\n\n  /** \n      @notice \n      Allows governance to transfer its privileges to another contract.\n\n      @dev\n      Only the currency governance can appoint a new governance.\n\n      @param _pendingGovernance The governance to transition power to. \n        @dev This address will have to accept the responsibility in a subsequent transaction.\n    */\n  function appointGovernance(address payable _pendingGovernance) external override onlyGov {\n    // The new governance can't be the zero address.\n    require(_pendingGovernance != address(0), 'TV1_1::appointGovernance: ZERO_ADDRESS');\n    // The new governance can't be the same as the current governance.\n    require(_pendingGovernance != governance, 'TV1_1::appointGovernance: NO_OP');\n\n    // Set the appointed governance as pending.\n    pendingGovernance = _pendingGovernance;\n\n    emit AppointGovernance(_pendingGovernance);\n  }\n\n  /** \n      @notice \n      Allows contract to accept its appointment as the new governance.\n    */\n  function acceptGovernance() external override {\n    // Only the pending governance address can accept.\n    require(msg.sender == pendingGovernance, 'TV1_1::acceptGovernance: UNAUTHORIZED');\n\n    // Get a reference to the pending governance.\n    address payable _pendingGovernance = pendingGovernance;\n\n    // Set the govenance to the pending value.\n    governance = _pendingGovernance;\n\n    emit AcceptGovernance(_pendingGovernance);\n  }\n\n  // --- public transactions --- //\n\n  /**\n      @notice \n      Prints all reserved tickets for a project.\n\n      @param _projectId The ID of the project to which the reserved tickets belong.\n\n      @return amount The amount of tickets that are being printed.\n    */\n  function printReservedTickets(uint256 _projectId) public override returns (uint256 amount) {\n    // Get the current funding cycle to read the reserved rate from.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // If there's no funding cycle, there's no reserved tickets to print.\n    if (_fundingCycle.id == 0) return 0;\n\n    // Get a reference to new total supply of tickets before printing reserved tickets.\n    uint256 _totalTickets = ticketBooth.totalSupplyOf(_projectId);\n\n    // Get a reference to the number of tickets that need to be printed.\n    // If there's no funding cycle, there's no tickets to print.\n    // The reserved rate is in bits 8-15 of the metadata.\n    amount = _reservedTicketAmountFrom(\n      _processedTicketTrackerOf[_projectId],\n      uint256(uint8(_fundingCycle.metadata >> 8)),\n      _totalTickets\n    );\n\n    // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n    require(\n      _totalTickets + amount <= uint256(type(int256).max),\n      'TV1_1::printReservedTickets: INT_LIMIT_REACHED'\n    );\n\n    // Set the tracker to be the new total supply.\n    _processedTicketTrackerOf[_projectId] = int256(_totalTickets + amount);\n\n    // If needed istribute tickets to mods and get a reference to the leftover amount to print after all mods have had their share printed.\n    uint256 _leftoverTicketAmount = amount == 0\n      ? 0\n      : _distributeToTicketMods(_fundingCycle, amount);\n\n    // Get a reference to the project owner.\n    address _owner = projects.ownerOf(_projectId);\n\n    // Print any remaining reserved tickets to the owner.\n    if (_leftoverTicketAmount > 0)\n      ticketBooth.print(_owner, _projectId, _leftoverTicketAmount, false);\n\n    emit PrintReserveTickets(\n      _fundingCycle.id,\n      _projectId,\n      _owner,\n      amount,\n      _leftoverTicketAmount,\n      msg.sender\n    );\n  }\n\n  // --- private helper functions --- //\n\n  /** \n      @notice\n      Pays out the mods for the specified funding cycle.\n\n      @param _fundingCycle The funding cycle to base the distribution on.\n      @param _amount The total amount being paid out.\n      @param _memo A memo to send along with project payouts.\n\n      @return leftoverAmount If the mod percents dont add up to 100%, the leftover amount is returned.\n\n    */\n  function _distributeToPayoutMods(\n    FundingCycle memory _fundingCycle,\n    uint256 _amount,\n    string memory _memo\n  ) private returns (uint256 leftoverAmount) {\n    // Set the leftover amount to the initial amount.\n    leftoverAmount = _amount;\n\n    // Get a reference to the project's payout mods.\n    PayoutMod[] memory _mods = modStore.payoutModsOf(\n      _fundingCycle.projectId,\n      _fundingCycle.configured\n    );\n\n    if (_mods.length == 0) return leftoverAmount;\n\n    //Transfer between all mods.\n    for (uint256 _i = 0; _i < _mods.length; _i++) {\n      // Get a reference to the mod being iterated on.\n      PayoutMod memory _mod = _mods[_i];\n\n      // The amount to send towards mods. Mods percents are out of 10000.\n      uint256 _modCut = PRBMath.mulDiv(_amount, _mod.percent, 10000);\n\n      if (_modCut > 0) {\n        // Transfer ETH to the mod.\n        // If there's an allocator set, transfer to its `allocate` function.\n        if (_mod.allocator != IModAllocator(address(0))) {\n          _mod.allocator.allocate{value: _modCut}(\n            _fundingCycle.projectId,\n            _mod.projectId,\n            _mod.beneficiary\n          );\n        } else if (_mod.projectId != 0) {\n          // Otherwise, if a project is specified, make a payment to it.\n\n          // Get a reference to the Juicebox terminal being used.\n          ITerminal _terminal = terminalDirectory.terminalOf(_mod.projectId);\n\n          // The project must have a terminal to send funds to.\n          require(_terminal != ITerminal(address(0)), 'TV1_1::tap: BAD_MOD');\n\n          // Save gas if this contract is being used as the terminal.\n          if (_terminal == this) {\n            _pay(_mod.projectId, _modCut, _mod.beneficiary, _memo, _mod.preferUnstaked);\n          } else {\n            _terminal.pay{value: _modCut}(\n              _mod.projectId,\n              _mod.beneficiary,\n              _memo,\n              _mod.preferUnstaked\n            );\n          }\n        } else {\n          // Otherwise, send the funds directly to the beneficiary.\n          Address.sendValue(_mod.beneficiary, _modCut);\n        }\n      }\n\n      // Subtract from the amount to be sent to the beneficiary.\n      leftoverAmount = leftoverAmount - _modCut;\n\n      emit DistributeToPayoutMod(\n        _fundingCycle.id,\n        _fundingCycle.projectId,\n        _mod,\n        _modCut,\n        msg.sender\n      );\n    }\n  }\n\n  /** \n      @notice\n      distributed tickets to the mods for the specified funding cycle.\n\n      @param _fundingCycle The funding cycle to base the ticket distribution on.\n      @param _amount The total amount of tickets to print.\n\n      @return leftoverAmount If the mod percents dont add up to 100%, the leftover amount is returned.\n\n    */\n  function _distributeToTicketMods(FundingCycle memory _fundingCycle, uint256 _amount)\n    private\n    returns (uint256 leftoverAmount)\n  {\n    // Set the leftover amount to the initial amount.\n    leftoverAmount = _amount;\n\n    // Get a reference to the project's ticket mods.\n    TicketMod[] memory _mods = modStore.ticketModsOf(\n      _fundingCycle.projectId,\n      _fundingCycle.configured\n    );\n\n    //Transfer between all mods.\n    for (uint256 _i = 0; _i < _mods.length; _i++) {\n      // Get a reference to the mod being iterated on.\n      TicketMod memory _mod = _mods[_i];\n\n      // The amount to send towards mods. Mods percents are out of 10000.\n      uint256 _modCut = PRBMath.mulDiv(_amount, _mod.percent, 10000);\n\n      // Print tickets for the mod if needed.\n      if (_modCut > 0)\n        ticketBooth.print(_mod.beneficiary, _fundingCycle.projectId, _modCut, _mod.preferUnstaked);\n\n      // Subtract from the amount to be sent to the beneficiary.\n      leftoverAmount = leftoverAmount - _modCut;\n\n      emit DistributeToTicketMod(\n        _fundingCycle.id,\n        _fundingCycle.projectId,\n        _mod,\n        _modCut,\n        msg.sender\n      );\n    }\n  }\n\n  /** \n      @notice \n      See the documentation for 'pay'.\n    */\n  function _pay(\n    uint256 _projectId,\n    uint256 _amount,\n    address _beneficiary,\n    string memory _memo,\n    bool _preferUnstakedTickets\n  ) private returns (uint256) {\n    // Get a reference to the current funding cycle for the project.\n    FundingCycle memory _fundingCycle = fundingCycles.currentOf(_projectId);\n\n    // Make sure its not paused.\n    require(((_fundingCycle.metadata >> 32) & 1) == 0, 'TV1_1::pay: PAUSED');\n\n    // Use the funding cycle's weight if it exists. Otherwise use the base weight.\n    uint256 _weight = _fundingCycle.number == 0\n      ? fundingCycles.BASE_WEIGHT()\n      : _fundingCycle.weight;\n\n    // Multiply the amount by the funding cycle's weight to determine the amount of tickets to print.\n    uint256 _weightedAmount = PRBMathUD60x18.mul(_amount, _weight);\n\n    // Use the funding cycle's reserved rate if it exists. Otherwise don't set a reserved rate.\n    // The reserved rate is stored in bytes 8-15 of the metadata property.\n    uint256 _reservedRate = _fundingCycle.number == 0\n      ? 0\n      : uint256(uint8(_fundingCycle.metadata >> 8));\n\n    // Only print the tickets that are unreserved.\n    uint256 _unreservedWeightedAmount = PRBMath.mulDiv(_weightedAmount, 200 - _reservedRate, 200);\n\n    // Add to the balance of the project.\n    balanceOf[_projectId] = balanceOf[_projectId] + _amount;\n\n    // If theres an unreserved weighted amount, print tickets representing this amount for the beneficiary.\n    if (_unreservedWeightedAmount > 0) {\n      // If there's no funding cycle, track this payment as having been made before a configuration.\n      if (_fundingCycle.number == 0) {\n        // Mark the premined tickets as processed so that reserved tickets can't later be printed against them.\n        // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n        require(\n          _processedTicketTrackerOf[_projectId] < 0 ||\n            uint256(_processedTicketTrackerOf[_projectId]) + uint256(_weightedAmount) <=\n            uint256(type(int256).max),\n          'TV1_1::pay INT_LIMIT_REACHED'\n        );\n        _processedTicketTrackerOf[_projectId] =\n          _processedTicketTrackerOf[_projectId] +\n          int256(_unreservedWeightedAmount);\n      }\n\n      // Print the project's tickets for the beneficiary.\n      ticketBooth.print(\n        _beneficiary,\n        _projectId,\n        _unreservedWeightedAmount,\n        _preferUnstakedTickets\n      );\n    } else if (_weightedAmount > 0) {\n      // If there is no unreserved weight amount but there is a weighted amount,\n      // the full weighted amount should be explicitly tracked as reserved since no unreserved tickets were printed.\n\n      // Subtract the total weighted amount from the tracker so the full reserved ticket amount can be printed later.\n      // Make sure int casting isnt overflowing the int. 2^255 - 1 is the largest number that can be stored in an int.\n      require(\n        _processedTicketTrackerOf[_projectId] > 0 ||\n          uint256(-_processedTicketTrackerOf[_projectId]) + uint256(_weightedAmount) <=\n          uint256(type(int256).max),\n        'TV1_1::printTickets: INT_LIMIT_REACHED'\n      );\n      _processedTicketTrackerOf[_projectId] =\n        _processedTicketTrackerOf[_projectId] -\n        int256(_weightedAmount);\n    }\n\n    emit Pay(\n      _fundingCycle.id,\n      _projectId,\n      _beneficiary,\n      _amount,\n      _unreservedWeightedAmount,\n      _weightedAmount,\n      _memo,\n      msg.sender\n    );\n\n    return _fundingCycle.id;\n  }\n\n  /** \n      @notice \n      Gets the amount overflowed in relation to the provided funding cycle.\n\n      @dev\n      This amount changes as the price of ETH changes against the funding cycle's currency.\n\n      @param _currentFundingCycle The ID of the funding cycle to base the overflow on.\n\n      @return overflow The current overflow of funds.\n    */\n  function _overflowFrom(FundingCycle memory _currentFundingCycle) private view returns (uint256) {\n    // Get the current price of ETH.\n    uint256 _ethPrice = prices.getETHPriceFor(_currentFundingCycle.currency);\n\n    // Get a reference to the amount still tappable in the current funding cycle.\n    uint256 _limit = _currentFundingCycle.target - _currentFundingCycle.tapped;\n\n    // The amount of ETH that the owner could currently still tap if its available. This amount isn't considered overflow.\n    uint256 _ethLimit = _limit == 0 ? 0 : PRBMathUD60x18.div(_limit, _ethPrice);\n\n    // Get the current balance of the project.\n    uint256 _balanceOf = balanceOf[_currentFundingCycle.projectId];\n\n    // Overflow is the balance of this project minus the reserved amount.\n    return _balanceOf < _ethLimit ? 0 : _balanceOf - _ethLimit;\n  }\n\n  /** \n      @notice \n      Gets the amount of reserved tickets currently tracked for a project given a reserved rate.\n\n      @param _processedTicketTracker The tracker to make the calculation with.\n      @param _reservedRate The reserved rate to use to make the calculation.\n      @param _totalEligibleTickets The total amount to make the calculation with.\n\n      @return amount reserved ticket amount.\n    */\n  function _reservedTicketAmountFrom(\n    int256 _processedTicketTracker,\n    uint256 _reservedRate,\n    uint256 _totalEligibleTickets\n  ) private pure returns (uint256) {\n    // Get a reference to the amount of tickets that are unprocessed.\n    uint256 _unprocessedTicketBalanceOf = _processedTicketTracker >= 0 // preconfigure tickets shouldn't contribute to the reserved ticket amount.\n      ? _totalEligibleTickets - uint256(_processedTicketTracker)\n      : _totalEligibleTickets + uint256(-_processedTicketTracker);\n\n    // If there are no unprocessed tickets, return.\n    if (_unprocessedTicketBalanceOf == 0) return 0;\n\n    // If all tickets are reserved, return the full unprocessed amount.\n    if (_reservedRate == 200) return _unprocessedTicketBalanceOf;\n\n    return\n      PRBMath.mulDiv(_unprocessedTicketBalanceOf, 200, 200 - _reservedRate) -\n      _unprocessedTicketBalanceOf;\n  }\n\n  /**\n      @notice \n      Validate and pack the funding cycle metadata.\n\n      @param _metadata The metadata to validate and pack.\n\n      @return packed The packed uint256 of all metadata params. The first 8 bytes specify the version.\n     */\n  function _validateAndPackFundingCycleMetadata(FundingCycleMetadata2 memory _metadata)\n    private\n    pure\n    returns (uint256 packed)\n  {\n    // The reserved project ticket rate must be less than or equal to 200.\n    require(\n      _metadata.reservedRate <= 200,\n      'TV1_1::_validateAndPackFundingCycleMetadata: BAD_RESERVED_RATE'\n    );\n\n    // The bonding curve rate must be between 0 and 200.\n    require(\n      _metadata.bondingCurveRate <= 200,\n      'TV1_1::_validateAndPackFundingCycleMetadata: BAD_BONDING_CURVE_RATE'\n    );\n\n    // The reconfiguration bonding curve rate must be less than or equal to 200.\n    require(\n      _metadata.reconfigurationBondingCurveRate <= 200,\n      'TV1_1::_validateAndPackFundingCycleMetadata: BAD_RECONFIGURATION_BONDING_CURVE_RATE'\n    );\n\n    // version 0 in the first 8 bits.\n    packed = 0;\n    // reserved rate in bits 8-15.\n    packed |= _metadata.reservedRate << 8;\n    // bonding curve in bits 16-23.\n    packed |= _metadata.bondingCurveRate << 16;\n    // reconfiguration bonding curve rate in bits 24-31.\n    packed |= _metadata.reconfigurationBondingCurveRate << 24;\n    // pay paused rate in bit 32.\n    if (_metadata.payIsPaused) packed |= 1 << 32;\n    // ticket printing allowed in bit 33.\n    if (_metadata.ticketPrintingIsAllowed) packed |= 1 << 33;\n    // treasury extension address in bits 68-227.\n    packed |= uint160(address(_metadata.treasuryExtension)) << 34;\n  }\n\n  /** \n      @notice \n      Takes a fee into the Governance contract's project.\n\n      @param _from The amount to take a fee from.\n      @param _percent The percent fee to take. Out of 200.\n      @param _beneficiary The address to print governance's tickets for.\n      @param _memo A memo to send with the fee.\n\n      @return feeAmount The amount of the fee taken.\n    */\n  function _takeFee(\n    uint256 _from,\n    uint256 _percent,\n    address _beneficiary,\n    string memory _memo\n  ) private returns (uint256 feeAmount) {\n    // The amount of ETH from the _tappedAmount to pay as a fee.\n    feeAmount = _from - PRBMath.mulDiv(_from, 200, _percent + 200);\n\n    // Nothing to do if there's no fee to take.\n    if (feeAmount == 0) return 0;\n\n    // When processing the admin fee, save gas if the admin is using this contract as its terminal.\n    if (terminalDirectory.terminalOf(JuiceboxProject(governance).projectId()) == this) {\n      // Use the local pay call.\n      _pay(JuiceboxProject(governance).projectId(), feeAmount, _beneficiary, _memo, false);\n    } else {\n      // Use the external pay call of the governance contract.\n      JuiceboxProject(governance).pay{value: feeAmount}(_beneficiary, _memo, false);\n    }\n  }\n}\n"
    },
    "contracts/interfaces/ITerminalV1_1.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport '@openzeppelin/contracts/token/ERC721/IERC721.sol';\n\nimport './ITicketBooth.sol';\nimport './IFundingCycles.sol';\nimport './IYielder.sol';\nimport './IProjects.sol';\nimport './IModStore.sol';\nimport './ITerminal.sol';\nimport './IOperatorStore.sol';\nimport './ITreasuryExtension.sol';\n\nstruct FundingCycleMetadata2 {\n  uint256 reservedRate;\n  uint256 bondingCurveRate;\n  uint256 reconfigurationBondingCurveRate;\n  bool payIsPaused;\n  bool ticketPrintingIsAllowed;\n  ITreasuryExtension treasuryExtension;\n}\n\ninterface ITerminalV1_1 {\n  event Pay(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 amount,\n    uint256 beneficiaryTokens,\n    uint256 totalTokens,\n    string note,\n    address caller\n  );\n\n  event AddToBalance(uint256 indexed projectId, uint256 value, address caller);\n\n  event AllowMigration(ITerminal allowed);\n\n  event Migrate(uint256 indexed projectId, ITerminal indexed to, uint256 _amount, address caller);\n\n  event Configure(uint256 indexed fundingCycleId, uint256 indexed projectId, address caller);\n\n  event Tap(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 amount,\n    uint256 currency,\n    uint256 netTransferAmount,\n    uint256 beneficiaryTransferAmount,\n    uint256 govFeeAmount,\n    address caller\n  );\n  event Redeem(\n    address indexed holder,\n    address indexed beneficiary,\n    uint256 indexed _projectId,\n    uint256 amount,\n    uint256 returnAmount,\n    address caller\n  );\n\n  event PrintReserveTickets(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 count,\n    uint256 beneficiaryTicketAmount,\n    address caller\n  );\n\n  event DistributeToPayoutMod(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    PayoutMod mod,\n    uint256 modCut,\n    address caller\n  );\n  event DistributeToTicketMod(\n    uint256 indexed fundingCycleId,\n    uint256 indexed projectId,\n    TicketMod mod,\n    uint256 modCut,\n    address caller\n  );\n  event AppointGovernance(address governance);\n\n  event AcceptGovernance(address governance);\n\n  event PrintTickets(\n    uint256 indexed projectId,\n    address indexed beneficiary,\n    uint256 amount,\n    string memo,\n    address caller\n  );\n\n  event Deposit(uint256 amount);\n\n  event EnsureTargetLocalWei(uint256 target);\n\n  event SetYielder(IYielder newYielder);\n\n  event SetFee(uint256 _amount);\n\n  event SetTargetLocalWei(uint256 amount);\n\n  function governance() external view returns (address payable);\n\n  function pendingGovernance() external view returns (address payable);\n\n  function projects() external view returns (IProjects);\n\n  function fundingCycles() external view returns (IFundingCycles);\n\n  function ticketBooth() external view returns (ITicketBooth);\n\n  function prices() external view returns (IPrices);\n\n  function modStore() external view returns (IModStore);\n\n  function reservedTicketBalanceOf(uint256 _projectId, uint256 _reservedRate)\n    external\n    view\n    returns (uint256);\n\n  function balanceOf(uint256 _projectId) external view returns (uint256);\n\n  function currentOverflowOf(uint256 _projectId) external view returns (uint256);\n\n  function claimableOverflowOf(\n    address _account,\n    uint256 _amount,\n    uint256 _projectId\n  ) external view returns (uint256);\n\n  function fee() external view returns (uint256);\n\n  function deploy(\n    address _owner,\n    bytes32 _handle,\n    string calldata _uri,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata2 calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  ) external;\n\n  function configure(\n    uint256 _projectId,\n    FundingCycleProperties calldata _properties,\n    FundingCycleMetadata2 calldata _metadata,\n    PayoutMod[] memory _payoutMods,\n    TicketMod[] memory _ticketMods\n  ) external returns (uint256);\n\n  function printTickets(\n    uint256 _projectId,\n    uint256 _amount,\n    address _beneficiary,\n    string memory _memo,\n    bool _preferUnstakedTickets\n  ) external;\n\n  function tap(\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _currency,\n    uint256 _minReturnedWei\n  ) external returns (uint256);\n\n  function redeem(\n    address _account,\n    uint256 _projectId,\n    uint256 _amount,\n    uint256 _minReturnedWei,\n    address payable _beneficiary,\n    bool _preferUnstaked\n  ) external returns (uint256 returnAmount);\n\n  function printReservedTickets(uint256 _projectId)\n    external\n    returns (uint256 reservedTicketsToPrint);\n\n  function setFee(uint256 _fee) external;\n\n  function appointGovernance(address payable _pendingGovernance) external;\n\n  function acceptGovernance() external;\n}\n"
    },
    "contracts/interfaces/ITreasuryExtension.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\ninterface ITreasuryExtension {\n  function ETHValue() external view returns (uint256);\n}\n"
    },
    "contracts/TerminalDirectory.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport './interfaces/ITerminal.sol';\nimport './interfaces/ITerminalDirectory.sol';\nimport './interfaces/IProjects.sol';\n\nimport './abstract/Operatable.sol';\n\nimport './libraries/Operations.sol';\n\nimport './DirectPaymentAddress.sol';\n\n/**\n  @notice\n  Allows project owners to deploy proxy contracts that can pay them when receiving funds directly.\n*/\ncontract TerminalDirectory is ITerminalDirectory, Operatable {\n  // --- private stored properties --- //\n\n  // A list of contracts for each project ID that can receive funds directly.\n  mapping(uint256 => IDirectPaymentAddress[]) private _addressesOf;\n\n  // --- public immutable stored properties --- //\n\n  /// @notice The Projects contract which mints ERC-721's that represent project ownership and transfers.\n  IProjects public immutable override projects;\n\n  // --- public stored properties --- //\n\n  /// @notice For each project ID, the juicebox terminal that the direct payment addresses are proxies for.\n  mapping(uint256 => ITerminal) public override terminalOf;\n\n  /// @notice For each address, the address that will be used as the beneficiary of direct payments made.\n  mapping(address => address) public override beneficiaryOf;\n\n  /// @notice For each address, the preference of whether ticket will be auto claimed as ERC20s when a payment is made.\n  mapping(address => bool) public override unstakedTicketsPreferenceOf;\n\n  // --- external views --- //\n\n  /** \n      @notice \n      A list of all direct payment addresses for the specified project ID.\n\n      @param _projectId The ID of the project to get direct payment addresses for.\n\n      @return A list of direct payment addresses for the specified project ID.\n    */\n  function addressesOf(uint256 _projectId)\n    external\n    view\n    override\n    returns (IDirectPaymentAddress[] memory)\n  {\n    return _addressesOf[_projectId];\n  }\n\n  // --- external transactions --- //\n\n  /** \n      @param _projects A Projects contract which mints ERC-721's that represent project ownership and transfers.\n      @param _operatorStore A contract storing operator assignments.\n    */\n  constructor(IProjects _projects, IOperatorStore _operatorStore) Operatable(_operatorStore) {\n    projects = _projects;\n  }\n\n  /** \n      @notice \n      Allows anyone to deploy a new direct payment address for a project.\n\n      @param _projectId The ID of the project to deploy a direct payment address for.\n      @param _memo The note to use for payments made through the new direct payment address.\n    */\n  function deployAddress(uint256 _projectId, string calldata _memo) external override {\n    require(_projectId > 0, 'TerminalDirectory::deployAddress: ZERO_PROJECT');\n\n    // Deploy the contract and push it to the list.\n    _addressesOf[_projectId].push(new DirectPaymentAddress(this, _projectId, _memo));\n\n    emit DeployAddress(_projectId, _memo, msg.sender);\n  }\n\n  /** \n      @notice \n      Update the juicebox terminal that payments to direct payment addresses will be forwarded for the specified project ID.\n\n      @param _projectId The ID of the project to set a new terminal for.\n      @param _terminal The new terminal to set.\n    */\n  function setTerminal(uint256 _projectId, ITerminal _terminal) external override {\n    // Get a reference to the current terminal being used.\n    ITerminal _currentTerminal = terminalOf[_projectId];\n\n    address _projectOwner = projects.ownerOf(_projectId);\n\n    // Either:\n    // - case 1: the current terminal hasn't been set yet and the msg sender is either the projects contract or the terminal being set.\n    // - case 2: the current terminal must not yet be set, or the current terminal is setting a new terminal.\n    // - case 3: the msg sender is the owner or operator and either the current terminal hasn't been set, or the current terminal allows migration to the terminal being set.\n    require(\n      // case 1.\n      (_currentTerminal == ITerminal(address(0)) &&\n        (msg.sender == address(projects) || msg.sender == address(_terminal))) ||\n        // case 2.\n        msg.sender == address(_currentTerminal) ||\n        // case 3.\n        ((msg.sender == _projectOwner ||\n          operatorStore.hasPermission(\n            msg.sender,\n            _projectOwner,\n            _projectId,\n            Operations.SetTerminal\n          )) &&\n          (_currentTerminal == ITerminal(address(0)) ||\n            _currentTerminal.migrationIsAllowed(_terminal))),\n      'TerminalDirectory::setTerminal: UNAUTHORIZED'\n    );\n\n    // The project must exist.\n    require(projects.exists(_projectId), 'TerminalDirectory::setTerminal: NOT_FOUND');\n\n    // Can't set the zero address.\n    require(_terminal != ITerminal(address(0)), 'TerminalDirectory::setTerminal: ZERO_ADDRESS');\n\n    // If the terminal is already set, nothing to do.\n    if (_currentTerminal == _terminal) return;\n\n    // Set the new terminal.\n    terminalOf[_projectId] = _terminal;\n\n    emit SetTerminal(_projectId, _terminal, msg.sender);\n  }\n\n  /** \n      @notice \n      Allows any address to pre set the beneficiary of their payments to any direct payment address,\n      and to pre set whether to prefer to unstake tickets into ERC20's when making a payment.\n\n      @param _beneficiary The beneficiary to set.\n      @param _preferUnstakedTickets The preference to set.\n    */\n  function setPayerPreferences(address _beneficiary, bool _preferUnstakedTickets)\n    external\n    override\n  {\n    beneficiaryOf[msg.sender] = _beneficiary;\n    unstakedTicketsPreferenceOf[msg.sender] = _preferUnstakedTickets;\n\n    emit SetPayerPreferences(msg.sender, _beneficiary, _preferUnstakedTickets);\n  }\n}\n"
    },
    "contracts/DirectPaymentAddress.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/IDirectPaymentAddress.sol\";\nimport \"./interfaces/ITerminalDirectory.sol\";\n\n/** \n  @notice\n  A contract that can receive funds directly and forward to a project's current terminal.\n*/\ncontract DirectPaymentAddress is IDirectPaymentAddress {\n    // --- public immutable stored properties --- //\n\n    /// @notice The directory to use when resolving which terminal to send the payment to.\n    ITerminalDirectory public immutable override terminalDirectory;\n\n    /// @notice The ID of the project to pay when this contract receives funds.\n    uint256 public immutable override projectId;\n\n    // --- public stored properties --- //\n\n    /// @notice The memo to use when this contract forwards a payment to a terminal.\n    string public override memo;\n\n    // --- external transactions --- //\n\n    /** \n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n      @param _projectId The ID of the project to pay when this contract receives funds.\n      @param _memo The memo to use when this contract forwards a payment to a terminal.\n    */\n    constructor(\n        ITerminalDirectory _terminalDirectory,\n        uint256 _projectId,\n        string memory _memo\n    ) {\n        terminalDirectory = _terminalDirectory;\n        projectId = _projectId;\n        memo = _memo;\n    }\n\n    // Receive funds and make a payment to the project's current terminal.\n    receive() external payable {\n        // Check to see if the sender has configured a beneficiary.\n        address _storedBeneficiary = terminalDirectory.beneficiaryOf(\n            msg.sender\n        );\n        // If no beneficiary is configured, use the sender's address.\n        address _beneficiary = _storedBeneficiary != address(0)\n            ? _storedBeneficiary\n            : msg.sender;\n\n        bool _preferUnstakedTickets = terminalDirectory\n        .unstakedTicketsPreferenceOf(msg.sender);\n\n        terminalDirectory.terminalOf(projectId).pay{value: msg.value}(\n            projectId,\n            _beneficiary,\n            memo,\n            _preferUnstakedTickets\n        );\n\n        emit Forward(\n            msg.sender,\n            projectId,\n            _beneficiary,\n            msg.value,\n            memo,\n            _preferUnstakedTickets\n        );\n    }\n}\n"
    },
    "contracts/ProxyPaymentAddressManager.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITicketBooth.sol\";\nimport \"./interfaces/ITerminalDirectory.sol\";\nimport \"./interfaces/IProxyPaymentAddress.sol\";\nimport \"./interfaces/IProxyPaymentAddressManager.sol\";\n\nimport \"./ProxyPaymentAddress.sol\";\n\n/** \n  @notice\n  Manages deploying proxy payment addresses for Juicebox projects.\n*/\ncontract ProxyPaymentAddressManager is IProxyPaymentAddressManager {\n    // --- private stored properties --- //\n\n    // A mapping from project id to proxy payment addresses.\n    mapping(uint256 => IProxyPaymentAddress[]) private _addressesOf;\n\n    // --- public immutable stored properties --- //\n\n    /// @notice The directory that will be injected into proxy payment addresses.\n    ITerminalDirectory public immutable override terminalDirectory;\n\n    /// @notice The ticket boot that will be injected into proxy payment addresses.\n    ITicketBooth public immutable override ticketBooth;\n\n    constructor(\n        ITerminalDirectory _terminalDirectory,\n        ITicketBooth _ticketBooth\n    ) {\n        terminalDirectory = _terminalDirectory;\n        ticketBooth = _ticketBooth;\n    }\n\n    /** \n      @notice \n      A list of all proxy payment addresses for the specified project ID.\n\n      @param _projectId The ID of the project to get proxy payment addresses for.\n\n      @return A list of proxy payment addresses for the specified project ID.\n    */\n    function addressesOf(uint256 _projectId)\n        external\n        view\n        override\n        returns (IProxyPaymentAddress[] memory)\n    {\n        return _addressesOf[_projectId];\n    }    \n\n    /** \n      @notice Deploys a proxy payment address.\n      @param _projectId ID of the project funds will be fowarded to.\n      @param _memo Memo that will be attached withdrawal transactions.\n    */\n    function deploy(uint256 _projectId, string memory _memo) external override returns(address) {\n        require(\n            _projectId > 0,\n            \"ProxyPaymentAddressManager::deploy: ZERO_PROJECT\"\n        );\n\n        // Create the proxy payment address contract.\n        ProxyPaymentAddress proxyPaymentAddress = new ProxyPaymentAddress(\n            terminalDirectory,\n            ticketBooth,\n            _projectId,\n            _memo\n        );\n\n        // Transfer ownership to the caller of this tx.\n        proxyPaymentAddress.transferOwnership(msg.sender);\n\n        // Push it to the list for the corresponding project.\n        _addressesOf[_projectId].push(proxyPaymentAddress);\n\n        emit Deploy(_projectId, _memo, msg.sender);\n\n        // Return the address of the proxy payment address.\n        return address(proxyPaymentAddress);\n    }\n\n}"
    },
    "contracts/interfaces/IProxyPaymentAddress.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./ITerminalDirectory.sol\";\nimport \"./ITicketBooth.sol\";\n\ninterface IProxyPaymentAddress {\n\n    event Receive(\n        address indexed caller,\n        uint256 value\n    );\n\n    event Tap(\n        address indexed caller,\n        uint256 value\n    );\n\n    event TransferTickets(\n        address indexed caller,\n        address indexed beneficiary,\n        uint256 indexed projectId,\n        uint256 amount\n    );\n\n    function terminalDirectory() external returns (ITerminalDirectory);\n\n    function ticketBooth() external returns (ITicketBooth);\n\n    function projectId() external returns (uint256);\n\n    function memo() external returns (string memory);\n\n    function tap() external;\n\n    function transferTickets(address _beneficiary, uint256 _amount) external;\n\n}"
    },
    "contracts/interfaces/IProxyPaymentAddressManager.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./ITerminalDirectory.sol\";\nimport \"./ITicketBooth.sol\";\nimport \"./IProxyPaymentAddress.sol\";\n\ninterface IProxyPaymentAddressManager {\n\n    event Deploy(\n        uint256 indexed projectId,\n        string memo,\n        address indexed caller\n    );       \n\n    function terminalDirectory() external returns (ITerminalDirectory);\n\n    function ticketBooth() external returns (ITicketBooth);\n\n    function addressesOf(uint256 _projectId)\n        external\n        view\n        returns (IProxyPaymentAddress[] memory);    \n\n    function deploy(uint256 _projectId, string memory _memo) external returns(address);\n\n}"
    },
    "contracts/ProxyPaymentAddress.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport \"./interfaces/IProxyPaymentAddress.sol\";\nimport \"./interfaces/ITerminalDirectory.sol\";\nimport \"./interfaces/ITicketBooth.sol\";\n\n/** \n  @notice\n  A contract that can receive and hold funds for a given project.\n  Once funds are tapped, tickets are printed and can be transferred out of the contract at a later date.\n\n  Particularly useful for routing funds from third-party platforms (e.g., Open Sea).\n*/\ncontract ProxyPaymentAddress is IProxyPaymentAddress, Ownable {\n    // --- public immutable stored properties --- //\n\n    /// @notice The directory to use when resolving which terminal to send the payment to.\n    ITerminalDirectory public immutable override terminalDirectory;\n\n    /// @notice The ticket booth to use when transferring tickets held by this contract to a beneficiary.\n    ITicketBooth public immutable override ticketBooth;\n\n    /// @notice The ID of the project tickets should be redeemed for.\n    uint256 public immutable override projectId;\n\n    /// @notice The memo to use when this contract forwards a payment to a terminal.\n    string public override memo;\n\n    constructor(\n        ITerminalDirectory _terminalDirectory,\n        ITicketBooth _ticketBooth,\n        uint256 _projectId,\n        string memory _memo\n    ) {\n        terminalDirectory = _terminalDirectory;\n        ticketBooth = _ticketBooth;\n        projectId = _projectId;\n        memo = _memo;\n    }\n\n    // Receive funds and hold them in the contract until they are ready to be transferred.\n    receive() external payable { \n        emit Receive(\n            msg.sender,\n            msg.value\n        );\n    }\n\n    // Transfers all funds held in the contract to the terminal of the corresponding project.\n    function tap() external override {\n        uint256 amount = address(this).balance;\n\n        terminalDirectory.terminalOf(projectId).pay{value: amount}(\n            projectId,\n            /*_beneficiary=*/address(this),\n            memo,\n            /*_preferUnstakedTickets=*/false\n        );\n\n        emit Tap(\n            msg.sender,\n            amount\n        ); \n    }\n\n    /** \n      @notice Transfers tickets held by this contract to a beneficiary.\n      @param _beneficiary Address of the beneficiary tickets will be transferred to.\n    */\n    function transferTickets(address _beneficiary, uint256 _amount) external override onlyOwner {\n        ticketBooth.transfer(\n            address(this),\n            projectId,\n            _amount,\n            _beneficiary\n        );\n\n        emit TransferTickets(\n            msg.sender,\n            _beneficiary,\n            projectId,\n            _amount\n        );            \n    }\n\n}"
    },
    "contracts/OperatorStore.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/IOperatorStore.sol\";\n\n/** \n  @notice\n  Addresses can give permissions to any other address to take specific actions \n  throughout the Juicebox ecosystem on their behalf. These addresses are called `operators`.\n  \n  @dev\n  Permissions are stored as a uint256, with each boolean bit representing whether or not\n  an oporator has the permission identified by that bit's index in the 256 bit uint256.\n  Indexes must be between 0 and 255.\n\n  The directory of permissions, along with how they uniquely mapp to indexes, are managed externally.\n  This contract doesn't know or care about specific permissions and their indexes.\n*/\ncontract OperatorStore is IOperatorStore {\n    // --- public stored properties --- //\n\n    /** \n      @notice\n      The permissions that an operator has to operate on a specific domain.\n      \n      @dev\n      An account can give an operator permissions that only pertain to a specific domain.\n      There is no domain with an ID of 0 -- accounts can use the 0 domain to give an operator\n      permissions to operator on their personal behalf.\n    */\n    mapping(address => mapping(address => mapping(uint256 => uint256)))\n        public\n        override permissionsOf;\n\n    // --- public views --- //\n\n    /** \n      @notice \n      Whether or not an operator has the permission to take a certain action pertaining to the specified domain.\n\n      @param _operator The operator to check.\n      @param _account The account that has given out permission to the operator.\n      @param _domain The domain that the operator has been given permissions to operate.\n      @param _permissionIndex the permission to check for.\n\n      @return Whether the operator has the specified permission.\n    */\n    function hasPermission(\n        address _operator,\n        address _account,\n        uint256 _domain,\n        uint256 _permissionIndex\n    ) external view override returns (bool) {\n        require(\n            _permissionIndex <= 255,\n            \"OperatorStore::hasPermission: INDEX_OUT_OF_BOUNDS\"\n        );\n        return\n            ((permissionsOf[_operator][_account][_domain] >> _permissionIndex) &\n                1) == 1;\n    }\n\n    /** \n      @notice \n      Whether or not an operator has the permission to take certain actions pertaining to the specified domain.\n\n      @param _operator The operator to check.\n      @param _account The account that has given out permissions to the operator.\n      @param _domain The domain that the operator has been given permissions to operate.\n      @param _permissionIndexes An array of permission indexes to check for.\n\n      @return Whether the operator has all specified permissions.\n    */\n    function hasPermissions(\n        address _operator,\n        address _account,\n        uint256 _domain,\n        uint256[] calldata _permissionIndexes\n    ) external view override returns (bool) {\n        for (uint256 _i = 0; _i < _permissionIndexes.length; _i++) {\n            uint256 _permissionIndex = _permissionIndexes[_i];\n\n            require(\n                _permissionIndex <= 255,\n                \"OperatorStore::hasPermissions: INDEX_OUT_OF_BOUNDS\"\n            );\n\n            if (\n                ((permissionsOf[_operator][_account][_domain] >>\n                    _permissionIndex) & 1) == 0\n            ) return false;\n        }\n        return true;\n    }\n\n    // --- external transactions --- //\n\n    /** \n      @notice \n      Sets permissions for an operator.\n\n      @param _operator The operator to give permission to.\n      @param _domain The domain that the operator is being given permissions to operate.\n      @param _permissionIndexes An array of indexes of permissions to set.\n    */\n    function setOperator(\n        address _operator,\n        uint256 _domain,\n        uint256[] calldata _permissionIndexes\n    ) external override {\n        // Pack the indexes into a uint256.\n        uint256 _packed = _packedPermissions(_permissionIndexes);\n\n        // Store the new value.\n        permissionsOf[_operator][msg.sender][_domain] = _packed;\n\n        emit SetOperator(\n            _operator,\n            msg.sender,\n            _domain,\n            _permissionIndexes,\n            _packed\n        );\n    }\n\n    /** \n      @notice \n      Sets permissions for many operators.\n\n      @param _operators The operators to give permission to.\n      @param _domains The domains that can be operated. Set to 0 to allow operation of account level actions.\n      @param _permissionIndexes The level of power each operator should have.\n    */\n    function setOperators(\n        address[] calldata _operators,\n        uint256[] calldata _domains,\n        uint256[][] calldata _permissionIndexes\n    ) external override {\n        // There should be a level for each operator provided.\n        require(\n            _operators.length == _permissionIndexes.length &&\n                _operators.length == _domains.length,\n            \"OperatorStore::setOperators: BAD_ARGS\"\n        );\n        for (uint256 _i = 0; _i < _operators.length; _i++) {\n            // Pack the indexes into a uint256.\n            uint256 _packed = _packedPermissions(_permissionIndexes[_i]);\n            // Store the new value.\n            permissionsOf[_operators[_i]][msg.sender][_domains[_i]] = _packed;\n            emit SetOperator(\n                _operators[_i],\n                msg.sender,\n                _domains[_i],\n                _permissionIndexes[_i],\n                _packed\n            );\n        }\n    }\n\n    // --- private helper functions --- //\n\n    /** \n      @notice \n      Converts an array of permission indexes to a packed int.\n\n      @param _indexes The indexes of the permissions to pack.\n\n      @return packed The packed result.\n    */\n    function _packedPermissions(uint256[] calldata _indexes)\n        private\n        pure\n        returns (uint256 packed)\n    {\n        for (uint256 _i = 0; _i < _indexes.length; _i++) {\n            uint256 _permissionIndex = _indexes[_i];\n            require(\n                _permissionIndex <= 255,\n                \"OperatorStore::_packedPermissions: INDEX_OUT_OF_BOUNDS\"\n            );\n            // Turn the bit at the index on.\n            packed |= 1 << _permissionIndex;\n        }\n    }\n}\n"
    },
    "contracts/ModStore.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/IModStore.sol\";\nimport \"./abstract/Operatable.sol\";\nimport \"./abstract/TerminalUtility.sol\";\n\nimport \"./libraries/Operations.sol\";\n\n/**\n  @notice\n  Stores mods for each project.\n\n  @dev\n  Mods can be used to distribute a percentage of payments or tickets to preconfigured beneficiaries.\n*/\ncontract ModStore is IModStore, Operatable, TerminalUtility {\n    // --- private stored properties --- //\n\n    // All payout mods for each project ID's configurations.\n    mapping(uint256 => mapping(uint256 => PayoutMod[])) private _payoutModsOf;\n\n    // All ticket mods for each project ID's configurations.\n    mapping(uint256 => mapping(uint256 => TicketMod[])) private _ticketModsOf;\n\n    // --- public immutable stored properties --- //\n\n    /// @notice The contract storing project information.\n    IProjects public immutable override projects;\n\n    // --- public views --- //\n\n    /**\n      @notice \n      Get all payout mods for the specified project ID.\n\n      @param _projectId The ID of the project to get mods for.\n      @param _configuration The configuration to get mods for.\n\n      @return An array of all mods for the project.\n     */\n    function payoutModsOf(uint256 _projectId, uint256 _configuration)\n        external\n        view\n        override\n        returns (PayoutMod[] memory)\n    {\n        return _payoutModsOf[_projectId][_configuration];\n    }\n\n    /**\n      @notice \n      Get all ticket mods for the specified project ID.\n\n      @param _projectId The ID of the project to get mods for.\n      @param _configuration The configuration to get mods for.\n\n      @return An array of all mods for the project.\n     */\n    function ticketModsOf(uint256 _projectId, uint256 _configuration)\n        external\n        view\n        override\n        returns (TicketMod[] memory)\n    {\n        return _ticketModsOf[_projectId][_configuration];\n    }\n\n    // --- external transactions --- //\n\n    /** \n      @param _projects The contract storing project information\n      @param _operatorStore A contract storing operator assignments.\n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n    constructor(\n        IProjects _projects,\n        IOperatorStore _operatorStore,\n        ITerminalDirectory _terminalDirectory\n    ) Operatable(_operatorStore) TerminalUtility(_terminalDirectory) {\n        projects = _projects;\n    }\n\n    /** \n      @notice \n      Adds a mod to the payout mods list.\n\n      @dev\n      Only the owner or operator of a project can make this call, or the current terminal of the project.\n\n      @param _projectId The project to add a mod to.\n      @param _configuration The configuration to set the mods to be active during.\n      @param _mods The payout mods to set.\n    */\n    function setPayoutMods(\n        uint256 _projectId,\n        uint256 _configuration,\n        PayoutMod[] memory _mods\n    )\n        external\n        override\n        requirePermissionAcceptingAlternateAddress(\n            projects.ownerOf(_projectId),\n            _projectId,\n            Operations.SetPayoutMods,\n            address(terminalDirectory.terminalOf(_projectId))\n        )\n    {\n        // There must be something to do.\n        require(_mods.length > 0, \"ModStore::setPayoutMods: NO_OP\");\n\n        // Get a reference to the project's payout mods.\n        PayoutMod[] memory _currentMods = _payoutModsOf[_projectId][\n            _configuration\n        ];\n\n        // Check to see if all locked Mods are included.\n        for (uint256 _i = 0; _i < _currentMods.length; _i++) {\n            if (block.timestamp < _currentMods[_i].lockedUntil) {\n                bool _includesLocked = false;\n                for (uint256 _j = 0; _j < _mods.length; _j++) {\n                    // Check for sameness. Let the note change.\n                    if (\n                        _mods[_j].percent == _currentMods[_i].percent &&\n                        _mods[_j].beneficiary == _currentMods[_i].beneficiary &&\n                        _mods[_j].allocator == _currentMods[_i].allocator &&\n                        _mods[_j].projectId == _currentMods[_i].projectId &&\n                        // Allow lock expention.\n                        _mods[_j].lockedUntil >= _currentMods[_i].lockedUntil\n                    ) _includesLocked = true;\n                }\n                require(\n                    _includesLocked,\n                    \"ModStore::setPayoutMods: SOME_LOCKED\"\n                );\n            }\n        }\n\n        // Delete from storage so mods can be repopulated.\n        delete _payoutModsOf[_projectId][_configuration];\n\n        // Add up all the percents to make sure they cumulative are under 100%.\n        uint256 _payoutModPercentTotal = 0;\n\n        for (uint256 _i = 0; _i < _mods.length; _i++) {\n            // The percent should be greater than 0.\n            require(\n                _mods[_i].percent > 0,\n                \"ModStore::setPayoutMods: BAD_MOD_PERCENT\"\n            );\n\n            // Add to the total percents.\n            _payoutModPercentTotal = _payoutModPercentTotal + _mods[_i].percent;\n\n            // The total percent should be less than 10000.\n            require(\n                _payoutModPercentTotal <= 10000,\n                \"ModStore::setPayoutMods: BAD_TOTAL_PERCENT\"\n            );\n\n            // The allocator and the beneficiary shouldn't both be the zero address.\n            require(\n                _mods[_i].allocator != IModAllocator(address(0)) ||\n                    _mods[_i].beneficiary != address(0),\n                \"ModStore::setPayoutMods: ZERO_ADDRESS\"\n            );\n\n            // Push the new mod into the project's list of mods.\n            _payoutModsOf[_projectId][_configuration].push(_mods[_i]);\n\n            emit SetPayoutMod(\n                _projectId,\n                _configuration,\n                _mods[_i],\n                msg.sender\n            );\n        }\n    }\n\n    /** \n      @notice \n      Adds a mod to the ticket mods list.\n\n      @dev\n      Only the owner or operator of a project can make this call, or the current terminal of the project.\n\n      @param _projectId The project to add a mod to.\n      @param _configuration The configuration to set the mods to be active during.\n      @param _mods The ticket mods to set.\n    */\n    function setTicketMods(\n        uint256 _projectId,\n        uint256 _configuration,\n        TicketMod[] memory _mods\n    )\n        external\n        override\n        requirePermissionAcceptingAlternateAddress(\n            projects.ownerOf(_projectId),\n            _projectId,\n            Operations.SetTicketMods,\n            address(terminalDirectory.terminalOf(_projectId))\n        )\n    {\n        // There must be something to do.\n        require(_mods.length > 0, \"ModStore::setTicketMods: NO_OP\");\n\n        // Get a reference to the project's ticket mods.\n        TicketMod[] memory _projectTicketMods = _ticketModsOf[_projectId][\n            _configuration\n        ];\n\n        // Check to see if all locked Mods are included.\n        for (uint256 _i = 0; _i < _projectTicketMods.length; _i++) {\n            if (block.timestamp < _projectTicketMods[_i].lockedUntil) {\n                bool _includesLocked = false;\n                for (uint256 _j = 0; _j < _mods.length; _j++) {\n                    // Check for the same values.\n                    if (\n                        _mods[_j].percent == _projectTicketMods[_i].percent &&\n                        _mods[_j].beneficiary ==\n                        _projectTicketMods[_i].beneficiary &&\n                        // Allow lock extensions.\n                        _mods[_j].lockedUntil >=\n                        _projectTicketMods[_i].lockedUntil\n                    ) _includesLocked = true;\n                }\n                require(\n                    _includesLocked,\n                    \"ModStore::setTicketMods: SOME_LOCKED\"\n                );\n            }\n        }\n        // Delete from storage so mods can be repopulated.\n        delete _ticketModsOf[_projectId][_configuration];\n\n        // Add up all the percents to make sure they cumulative are under 100%.\n        uint256 _ticketModPercentTotal = 0;\n\n        for (uint256 _i = 0; _i < _mods.length; _i++) {\n            // The percent should be greater than 0.\n            require(\n                _mods[_i].percent > 0,\n                \"ModStore::setTicketMods: BAD_MOD_PERCENT\"\n            );\n\n            // Add to the total percents.\n            _ticketModPercentTotal = _ticketModPercentTotal + _mods[_i].percent;\n            // The total percent should be less than 10000.\n            require(\n                _ticketModPercentTotal <= 10000,\n                \"ModStore::setTicketMods: BAD_TOTAL_PERCENT\"\n            );\n\n            // The beneficiary shouldn't be the zero address.\n            require(\n                _mods[_i].beneficiary != address(0),\n                \"ModStore::setTicketMods: ZERO_ADDRESS\"\n            );\n\n            // Push the new mod into the project's list of mods.\n            _ticketModsOf[_projectId][_configuration].push(_mods[_i]);\n\n            emit SetTicketMod(\n                _projectId,\n                _configuration,\n                _mods[_i],\n                msg.sender\n            );\n        }\n    }\n}\n"
    },
    "contracts/FundingCycles.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\nimport \"@paulrberg/contracts/math/PRBMath.sol\";\n\nimport \"./interfaces/IFundingCycles.sol\";\nimport \"./interfaces/IPrices.sol\";\nimport \"./abstract/TerminalUtility.sol\";\n\n/** \n  @notice Manage funding cycle configurations, accounting, and scheduling.\n*/\ncontract FundingCycles is TerminalUtility, IFundingCycles {\n    // --- private stored contants --- //\n\n    // The number of seconds in a day.\n    uint256 private constant SECONDS_IN_DAY = 86400;\n\n    // --- private stored properties --- //\n\n    // Stores the reconfiguration properties of each funding cycle, packed into one storage slot.\n    mapping(uint256 => uint256) private _packedConfigurationPropertiesOf;\n\n    // Stores the properties added by the mechanism to manage and schedule each funding cycle, packed into one storage slot.\n    mapping(uint256 => uint256) private _packedIntrinsicPropertiesOf;\n\n    // Stores the metadata for each funding cycle, packed into one storage slot.\n    mapping(uint256 => uint256) private _metadataOf;\n\n    // Stores the amount that each funding cycle can tap funding cycle.\n    mapping(uint256 => uint256) private _targetOf;\n\n    // Stores the amount that has been tapped within each funding cycle.\n    mapping(uint256 => uint256) private _tappedOf;\n\n    // --- public stored constants --- //\n\n    /// @notice The weight used for each project's first funding cycle.\n    uint256 public constant override BASE_WEIGHT = 1E24;\n\n    /// @notice The maximum value that a cycle limit can be set to.\n    uint256 public constant override MAX_CYCLE_LIMIT = 32;\n\n    // --- public stored properties --- //\n\n    /// @notice The ID of the latest funding cycle for each project.\n    mapping(uint256 => uint256) public override latestIdOf;\n\n    /// @notice The total number of funding cycles created, which is used for issuing funding cycle IDs.\n    /// @dev Funding cycles have IDs > 0.\n    uint256 public override count = 0;\n\n    // --- external views --- //\n\n    /**\n        @notice \n        Get the funding cycle with the given ID.\n\n        @param _fundingCycleId The ID of the funding cycle to get.\n\n        @return _fundingCycle The funding cycle.\n    */\n    function get(uint256 _fundingCycleId)\n        external\n        view\n        override\n        returns (FundingCycle memory)\n    {\n        // The funding cycle should exist.\n        require(\n            _fundingCycleId > 0 && _fundingCycleId <= count,\n            \"FundingCycle::get: NOT_FOUND\"\n        );\n\n        return _getStruct(_fundingCycleId);\n    }\n\n    /**\n        @notice \n        The funding cycle that's next up for a project, and therefor not currently accepting payments.\n\n        @dev \n        This runs roughly similar logic to `_configurable`.\n\n        @param _projectId The ID of the project being looked through.\n\n        @return _fundingCycle The queued funding cycle.\n    */\n    function queuedOf(uint256 _projectId)\n        external\n        view\n        override\n        returns (FundingCycle memory)\n    {\n        // The project must have funding cycles.\n        if (latestIdOf[_projectId] == 0) return _getStruct(0);\n\n        // Get a reference to the standby funding cycle.\n        uint256 _fundingCycleId = _standby(_projectId);\n\n        // If it exists, return it.\n        if (_fundingCycleId > 0) return _getStruct(_fundingCycleId);\n\n        // Get a reference to the eligible funding cycle.\n        _fundingCycleId = _eligible(_projectId);\n\n        // If an eligible funding cycle exists...\n        if (_fundingCycleId > 0) {\n            // Get the necessary properties for the standby funding cycle.\n            FundingCycle memory _fundingCycle = _getStruct(_fundingCycleId);\n\n            // There's no queued if the current has a duration of 0.\n            if (_fundingCycle.duration == 0) return _getStruct(0);\n\n            // Check to see if the correct ballot is approved for this funding cycle.\n            // If so, return a funding cycle based on it.\n            if (_isApproved(_fundingCycle))\n                return _mockFundingCycleBasedOn(_fundingCycle, false);\n\n            // If it hasn't been approved, set the ID to be its base funding cycle, which carries the last approved configuration.\n            _fundingCycleId = _fundingCycle.basedOn;\n        } else {\n            // No upcoming funding cycle found that is eligible to become active,\n            // so use the ID of the latest active funding cycle, which carries the last approved configuration.\n            _fundingCycleId = latestIdOf[_projectId];\n        }\n\n        // A funding cycle must exist.\n        if (_fundingCycleId == 0) return _getStruct(0);\n\n        // Return a mock of what its second next up funding cycle would be.\n        // Use second next because the next would be a mock of the current funding cycle.\n        return _mockFundingCycleBasedOn(_getStruct(_fundingCycleId), false);\n    }\n\n    /**\n        @notice \n        The funding cycle that is currently active for the specified project.\n\n        @dev \n        This runs very similar logic to `_tappable`.\n\n        @param _projectId The ID of the project being looked through.\n\n        @return fundingCycle The current funding cycle.\n    */\n    function currentOf(uint256 _projectId)\n        external\n        view\n        override\n        returns (FundingCycle memory fundingCycle)\n    {\n        // The project must have funding cycles.\n        if (latestIdOf[_projectId] == 0) return _getStruct(0);\n\n        // Check for an active funding cycle.\n        uint256 _fundingCycleId = _eligible(_projectId);\n\n        // If no active funding cycle is found, check if there is a standby funding cycle.\n        // If one exists, it will become active one it has been tapped.\n        if (_fundingCycleId == 0) _fundingCycleId = _standby(_projectId);\n\n        // Keep a reference to the eligible funding cycle.\n        FundingCycle memory _fundingCycle;\n\n        // If a standy funding cycle exists...\n        if (_fundingCycleId > 0) {\n            // Get the necessary properties for the standby funding cycle.\n            _fundingCycle = _getStruct(_fundingCycleId);\n\n            // Check to see if the correct ballot is approved for this funding cycle, and that it has started.\n            if (\n                _fundingCycle.start <= block.timestamp &&\n                _isApproved(_fundingCycle)\n            ) return _fundingCycle;\n\n            // If it hasn't been approved, set the ID to be the based funding cycle,\n            // which carries the last approved configuration.\n            _fundingCycleId = _fundingCycle.basedOn;\n        } else {\n            // No upcoming funding cycle found that is eligible to become active,\n            // so us the ID of the latest active funding cycle, which carries the last approved configuration.\n            _fundingCycleId = latestIdOf[_projectId];\n        }\n\n        // The funding cycle cant be 0.\n        if (_fundingCycleId == 0) return _getStruct(0);\n\n        // The funding cycle to base a current one on.\n        _fundingCycle = _getStruct(_fundingCycleId);\n\n        // Return a mock of what the next funding cycle would be like,\n        // which would become active one it has been tapped.\n        return _mockFundingCycleBasedOn(_fundingCycle, true);\n    }\n\n    /** \n      @notice \n      The currency ballot state of the project.\n\n      @param _projectId The ID of the project to check for a pending reconfiguration.\n\n      @return The current ballot's state.\n    */\n    function currentBallotStateOf(uint256 _projectId)\n        external\n        view\n        override\n        returns (BallotState)\n    {\n        // The project must have funding cycles.\n        require(\n            latestIdOf[_projectId] > 0,\n            \"FundingCycles::currentBallotStateOf: NOT_FOUND\"\n        );\n\n        // Get a reference to the latest funding cycle ID.\n        uint256 _fundingCycleId = latestIdOf[_projectId];\n\n        // Get the necessary properties for the latest funding cycle.\n        FundingCycle memory _fundingCycle = _getStruct(_fundingCycleId);\n\n        // If the latest funding cycle is the first, or if it has already started, it must be approved.\n        if (_fundingCycle.basedOn == 0) return BallotState.Standby;\n\n        return\n            _ballotState(\n                _fundingCycleId,\n                _fundingCycle.configured,\n                _fundingCycle.basedOn\n            );\n    }\n\n    // --- external transactions --- //\n\n    /** \n      @param _terminalDirectory A directory of a project's current Juicebox terminal to receive payments in.\n    */\n    constructor(ITerminalDirectory _terminalDirectory)\n        TerminalUtility(_terminalDirectory)\n    {}\n\n    /**\n        @notice \n        Configures the next eligible funding cycle for the specified project.\n\n        @dev\n        Only a project's current terminal can configure its funding cycles.\n\n        @param _projectId The ID of the project being reconfigured.\n        @param _properties The funding cycle configuration.\n          @dev _properties.target The amount that the project wants to receive in each funding cycle. 18 decimals.\n          @dev _properties.currency The currency of the `_target`. Send 0 for ETH or 1 for USD.\n          @dev _properties.duration The duration of the funding cycle for which the `_target` amount is needed. Measured in days. \n            Set to 0 for no expiry and to be able to reconfigure anytime.\n          @dev _cycleLimit The number of cycles that this configuration should last for before going back to the last permanent. This does nothing for a project's first funding cycle.\n          @dev _properties.discountRate A number from 0-200 indicating how valuable a contribution to this funding cycle is compared to previous funding cycles.\n            If it's 0, each funding cycle will have equal weight.\n            If the number is 100, a contribution to the next funding cycle will only give you 90% of tickets given to a contribution of the same amount during the current funding cycle.\n            If the number is 200, a contribution to the next funding cycle will only give you 80% of tickets given to a contribution of the same amoutn during the current funding cycle.\n            If the number is 201, an non-recurring funding cycle will get made.\n          @dev _ballot The new ballot that will be used to approve subsequent reconfigurations.\n        @param _metadata Data to associate with this funding cycle configuration.\n        @param _fee The fee that this configuration will incure when tapping.\n        @param _configureActiveFundingCycle If a funding cycle that has already started should be configurable.\n\n        @return fundingCycle The funding cycle that the configuration will take effect during.\n    */\n    function configure(\n        uint256 _projectId,\n        FundingCycleProperties calldata _properties,\n        uint256 _metadata,\n        uint256 _fee,\n        bool _configureActiveFundingCycle\n    )\n        external\n        override\n        onlyTerminal(_projectId)\n        returns (FundingCycle memory fundingCycle)\n    {\n        // Duration must fit in a uint16.\n        require(\n            _properties.duration <= type(uint16).max,\n            \"FundingCycles::configure: BAD_DURATION\"\n        );\n\n        // Currency must be less than the limit.\n        require(\n            _properties.cycleLimit <= MAX_CYCLE_LIMIT,\n            \"FundingCycles::configure: BAD_CYCLE_LIMIT\"\n        );\n\n        // Discount rate token must be less than or equal to 100%.\n        require(\n            _properties.discountRate <= 201,\n            \"FundingCycles::configure: BAD_DISCOUNT_RATE\"\n        );\n\n        // Currency must fit into a uint8.\n        require(\n            _properties.currency <= type(uint8).max,\n            \"FundingCycles::configure: BAD_CURRENCY\"\n        );\n\n        // Fee must be less than or equal to 100%.\n        require(_fee <= 200, \"FundingCycles::configure: BAD_FEE\");\n\n        // Set the configuration timestamp is now.\n        uint256 _configured = block.timestamp;\n\n        // Gets the ID of the funding cycle to reconfigure.\n        uint256 _fundingCycleId = _configurable(\n            _projectId,\n            _configured,\n            _configureActiveFundingCycle\n        );\n\n        // Store the configuration.\n        _packAndStoreConfigurationProperties(\n            _fundingCycleId,\n            _configured,\n            _properties.cycleLimit,\n            _properties.ballot,\n            _properties.duration,\n            _properties.currency,\n            _fee,\n            _properties.discountRate\n        );\n\n        // Set the target amount.\n        _targetOf[_fundingCycleId] = _properties.target;\n\n        // Set the metadata.\n        _metadataOf[_fundingCycleId] = _metadata;\n\n        emit Configure(\n            _fundingCycleId,\n            _projectId,\n            _configured,\n            _properties,\n            _metadata,\n            msg.sender\n        );\n\n        return _getStruct(_fundingCycleId);\n    }\n\n    /** \n      @notice \n      Tap funds from a project's currently tappable funding cycle.\n\n      @dev\n      Only a project's current terminal can tap funds for its funding cycles.\n\n      @param _projectId The ID of the project being tapped.\n      @param _amount The amount being tapped.\n\n      @return fundingCycle The tapped funding cycle.\n    */\n    function tap(uint256 _projectId, uint256 _amount)\n        external\n        override\n        onlyTerminal(_projectId)\n        returns (FundingCycle memory fundingCycle)\n    {\n        // Get a reference to the funding cycle being tapped.\n        uint256 fundingCycleId = _tappable(_projectId);\n\n        // Get a reference to how much has already been tapped from this funding cycle.\n        uint256 _tapped = _tappedOf[fundingCycleId];\n\n        // Amount must be within what is still tappable.\n        require(\n            _amount <= _targetOf[fundingCycleId] - _tapped,\n            \"FundingCycles::tap: INSUFFICIENT_FUNDS\"\n        );\n\n        // The new amount that has been tapped.\n        uint256 _newTappedAmount = _tapped + _amount;\n\n        // Store the new amount.\n        _tappedOf[fundingCycleId] = _newTappedAmount;\n\n        emit Tap(\n            fundingCycleId,\n            _projectId,\n            _amount,\n            _newTappedAmount,\n            msg.sender\n        );\n\n        return _getStruct(fundingCycleId);\n    }\n\n    // --- private helper functions --- //\n\n    /**\n        @notice \n        Returns the configurable funding cycle for this project if it exists, otherwise creates one.\n\n        @param _projectId The ID of the project to find a configurable funding cycle for.\n        @param _configured The time at which the configuration is occuring.\n        @param _configureActiveFundingCycle If the active funding cycle should be configurable. Otherwise the next funding cycle will be used.\n\n        @return fundingCycleId The ID of the configurable funding cycle.\n    */\n    function _configurable(\n        uint256 _projectId,\n        uint256 _configured,\n        bool _configureActiveFundingCycle\n    ) private returns (uint256 fundingCycleId) {\n        // If there's not yet a funding cycle for the project, return the ID of a newly created one.\n        if (latestIdOf[_projectId] == 0)\n            return _init(_projectId, _getStruct(0), block.timestamp, false);\n\n        // Get the standby funding cycle's ID.\n        fundingCycleId = _standby(_projectId);\n\n        // If it exists, make sure its updated, then return it.\n        if (fundingCycleId > 0) {\n            // Get the funding cycle that the specified one is based on.\n            FundingCycle memory _baseFundingCycle = _getStruct(\n                _getStruct(fundingCycleId).basedOn\n            );\n\n            // The base's ballot must have ended.\n            _updateFundingCycle(\n                fundingCycleId,\n                _baseFundingCycle,\n                _getTimeAfterBallot(_baseFundingCycle, _configured),\n                false\n            );\n            return fundingCycleId;\n        }\n\n        // Get the active funding cycle's ID.\n        fundingCycleId = _eligible(_projectId);\n\n        // If the ID of an eligible funding cycle exists, it's approved, and active funding cycles are configurable, return it.\n        if (fundingCycleId > 0) {\n            if (!_isIdApproved(fundingCycleId)) {\n                // If it hasn't been approved, set the ID to be the based funding cycle,\n                // which carries the last approved configuration.\n                fundingCycleId = _getStruct(fundingCycleId).basedOn;\n            } else if (_configureActiveFundingCycle) {\n                return fundingCycleId;\n            }\n        } else {\n            // Get the ID of the latest funding cycle which has the latest reconfiguration.\n            fundingCycleId = latestIdOf[_projectId];\n        }\n\n        // Determine if the configurable funding cycle can only take effect on or after a certain date.\n        uint256 _mustStartOnOrAfter;\n\n        // Base off of the active funding cycle if it exists.\n        FundingCycle memory _fundingCycle = _getStruct(fundingCycleId);\n\n        // Make sure the funding cycle is recurring.\n        require(\n            _fundingCycle.discountRate < 201,\n            \"FundingCycles::_configurable: NON_RECURRING\"\n        );\n\n        if (_configureActiveFundingCycle) {\n            // If the duration is zero, always go back to the original start.\n            if (_fundingCycle.duration == 0) {\n                _mustStartOnOrAfter = _fundingCycle.start;\n            } else {\n                // Set to the start time of the current active start time.\n                uint256 _timeFromStartMultiple = (block.timestamp -\n                    _fundingCycle.start) %\n                    (_fundingCycle.duration * SECONDS_IN_DAY);\n                _mustStartOnOrAfter = block.timestamp - _timeFromStartMultiple;\n            }\n        } else {\n            // The ballot must have ended.\n            _mustStartOnOrAfter = _getTimeAfterBallot(\n                _fundingCycle,\n                _configured\n            );\n        }\n\n        // Return the newly initialized configurable funding cycle.\n        fundingCycleId = _init(\n            _projectId,\n            _fundingCycle,\n            _mustStartOnOrAfter,\n            false\n        );\n    }\n\n    /**\n        @notice \n        Returns the funding cycle that can be tapped at the time of the call.\n\n        @param _projectId The ID of the project to find a configurable funding cycle for.\n\n        @return fundingCycleId The ID of the tappable funding cycle.\n    */\n    function _tappable(uint256 _projectId)\n        private\n        returns (uint256 fundingCycleId)\n    {\n        // Check for the ID of an eligible funding cycle.\n        fundingCycleId = _eligible(_projectId);\n\n        // No eligible funding cycle found, check for the ID of a standby funding cycle.\n        // If this one exists, it will become eligible one it has started.\n        if (fundingCycleId == 0) fundingCycleId = _standby(_projectId);\n\n        // Keep a reference to the funding cycle eligible for being tappable.\n        FundingCycle memory _fundingCycle;\n\n        // If the ID of an eligible funding cycle exists,\n        // check to see if it has been approved by the based funding cycle's ballot.\n        if (fundingCycleId > 0) {\n            // Get the necessary properties for the funding cycle.\n            _fundingCycle = _getStruct(fundingCycleId);\n\n            // Check to see if the cycle is approved. If so, return it.\n            if (\n                _fundingCycle.start <= block.timestamp &&\n                _isApproved(_fundingCycle)\n            ) return fundingCycleId;\n\n            // If it hasn't been approved, set the ID to be the base funding cycle,\n            // which carries the last approved configuration.\n            fundingCycleId = _fundingCycle.basedOn;\n        } else {\n            // No upcoming funding cycle found that is eligible to become active, clone the latest active funding cycle.\n            // which carries the last approved configuration.\n            fundingCycleId = latestIdOf[_projectId];\n        }\n\n        // The funding cycle cant be 0.\n        require(fundingCycleId > 0, \"FundingCycles::_tappable: NOT_FOUND\");\n\n        // Set the eligible funding cycle.\n        _fundingCycle = _getStruct(fundingCycleId);\n\n        // Funding cycles with a discount rate of 100% are non-recurring.\n        require(\n            _fundingCycle.discountRate < 201,\n            \"FundingCycles::_tappable: NON_RECURRING\"\n        );\n\n        // The time when the funding cycle immediately after the eligible funding cycle starts.\n        uint256 _nextImmediateStart = _fundingCycle.start +\n            (_fundingCycle.duration * SECONDS_IN_DAY);\n\n        // The distance from now until the nearest past multiple of the cycle duration from its start.\n        // A duration of zero means the reconfiguration can start right away.\n        uint256 _timeFromImmediateStartMultiple = _fundingCycle.duration == 0\n            ? 0\n            : (block.timestamp - _nextImmediateStart) %\n                (_fundingCycle.duration * SECONDS_IN_DAY);\n\n        // Return the tappable funding cycle.\n        fundingCycleId = _init(\n            _projectId,\n            _fundingCycle,\n            block.timestamp - _timeFromImmediateStartMultiple,\n            true\n        );\n    }\n\n    /**\n        @notice \n        Initializes a funding cycle with the appropriate properties.\n\n        @param _projectId The ID of the project to which the funding cycle being initialized belongs.\n        @param _baseFundingCycle The funding cycle to base the initialized one on.\n        @param _mustStartOnOrAfter The time before which the initialized funding cycle can't start.\n        @param _copy If non-intrinsic properties should be copied from the base funding cycle.\n\n        @return newFundingCycleId The ID of the initialized funding cycle.\n    */\n    function _init(\n        uint256 _projectId,\n        FundingCycle memory _baseFundingCycle,\n        uint256 _mustStartOnOrAfter,\n        bool _copy\n    ) private returns (uint256 newFundingCycleId) {\n        // Increment the count of funding cycles.\n        count++;\n\n        // Set the project's latest funding cycle ID to the new count.\n        latestIdOf[_projectId] = count;\n\n        // If there is no base, initialize a first cycle.\n        if (_baseFundingCycle.id == 0) {\n            // Set fresh intrinsic properties.\n            _packAndStoreIntrinsicProperties(\n                count,\n                _projectId,\n                BASE_WEIGHT,\n                1,\n                0,\n                block.timestamp\n            );\n        } else {\n            // Update the intrinsic properties of the funding cycle being initialized.\n            _updateFundingCycle(\n                count,\n                _baseFundingCycle,\n                _mustStartOnOrAfter,\n                _copy\n            );\n        }\n\n        // Get a reference to the funding cycle with updated intrinsic properties.\n        FundingCycle memory _fundingCycle = _getStruct(count);\n\n        emit Init(\n            count,\n            _fundingCycle.projectId,\n            _fundingCycle.number,\n            _fundingCycle.basedOn,\n            _fundingCycle.weight,\n            _fundingCycle.start\n        );\n\n        return _fundingCycle.id;\n    }\n\n    /**\n        @notice \n        The project's funding cycle that hasn't yet started, if one exists.\n\n        @param _projectId The ID of project to look through.\n\n        @return fundingCycleId The ID of the standby funding cycle.\n    */\n    function _standby(uint256 _projectId)\n        private\n        view\n        returns (uint256 fundingCycleId)\n    {\n        // Get a reference to the project's latest funding cycle.\n        fundingCycleId = latestIdOf[_projectId];\n\n        // If there isn't one, theres also no standy funding cycle.\n        if (fundingCycleId == 0) return 0;\n\n        // Get the necessary properties for the latest funding cycle.\n        FundingCycle memory _fundingCycle = _getStruct(fundingCycleId);\n\n        // There is no upcoming funding cycle if the latest funding cycle has already started.\n        if (block.timestamp >= _fundingCycle.start) return 0;\n    }\n\n    /**\n        @notice \n        The project's funding cycle that has started and hasn't yet expired.\n\n        @param _projectId The ID of the project to look through.\n\n        @return fundingCycleId The ID of the active funding cycle.\n    */\n    function _eligible(uint256 _projectId)\n        private\n        view\n        returns (uint256 fundingCycleId)\n    {\n        // Get a reference to the project's latest funding cycle.\n        fundingCycleId = latestIdOf[_projectId];\n\n        // If the latest funding cycle doesn't exist, return an undefined funding cycle.\n        if (fundingCycleId == 0) return 0;\n\n        // Get the necessary properties for the latest funding cycle.\n        FundingCycle memory _fundingCycle = _getStruct(fundingCycleId);\n\n        // If the latest is expired, return an undefined funding cycle.\n        // A duration of 0 can not be expired.\n        if (\n            _fundingCycle.duration > 0 &&\n            block.timestamp >=\n            _fundingCycle.start + (_fundingCycle.duration * SECONDS_IN_DAY)\n        ) return 0;\n\n        // The first funding cycle when running on local can be in the future for some reason.\n        // This will have no effect in production.\n        if (\n            _fundingCycle.basedOn == 0 || block.timestamp >= _fundingCycle.start\n        ) return fundingCycleId;\n\n        // The base cant be expired.\n        FundingCycle memory _baseFundingCycle = _getStruct(\n            _fundingCycle.basedOn\n        );\n\n        // If the current time is past the end of the base, return 0.\n        // A duration of 0 is always eligible.\n        if (\n            _baseFundingCycle.duration > 0 &&\n            block.timestamp >=\n            _baseFundingCycle.start +\n                (_baseFundingCycle.duration * SECONDS_IN_DAY)\n        ) return 0;\n\n        // Return the funding cycle immediately before the latest.\n        fundingCycleId = _fundingCycle.basedOn;\n    }\n\n    /** \n        @notice \n        A view of the funding cycle that would be created based on the provided one if the project doesn't make a reconfiguration.\n\n        @param _baseFundingCycle The funding cycle to make the calculation for.\n        @param _allowMidCycle Allow the mocked funding cycle to already be mid cycle.\n\n        @return The next funding cycle, with an ID set to 0.\n    */\n    function _mockFundingCycleBasedOn(\n        FundingCycle memory _baseFundingCycle,\n        bool _allowMidCycle\n    ) internal view returns (FundingCycle memory) {\n        // Can't mock a non recurring funding cycle.\n        if (_baseFundingCycle.discountRate == 201) return _getStruct(0);\n\n        // If the base has a limit, find the last permanent funding cycle, which is needed to make subsequent calculations.\n        // Otherwise, the base is already the latest permanent funding cycle.\n        FundingCycle memory _latestPermanentFundingCycle = _baseFundingCycle\n        .cycleLimit > 0\n            ? _latestPermanentCycleBefore(_baseFundingCycle)\n            : _baseFundingCycle;\n\n        // The distance of the current time to the start of the next possible funding cycle.\n        uint256 _timeFromImmediateStartMultiple;\n\n        if (_allowMidCycle && _baseFundingCycle.duration > 0) {\n            // Get the end time of the last cycle.\n            uint256 _cycleEnd = _baseFundingCycle.start +\n                (_baseFundingCycle.cycleLimit *\n                    _baseFundingCycle.duration *\n                    SECONDS_IN_DAY);\n\n            // If the cycle end time is in the past, the mock should start at a multiple of the last permanent cycle since the cycle ended.\n            if (\n                _baseFundingCycle.cycleLimit > 0 && _cycleEnd < block.timestamp\n            ) {\n                _timeFromImmediateStartMultiple = _latestPermanentFundingCycle\n                .duration == 0\n                    ? 0\n                    : ((block.timestamp - _cycleEnd) %\n                        (_latestPermanentFundingCycle.duration *\n                            SECONDS_IN_DAY));\n            } else {\n                _timeFromImmediateStartMultiple =\n                    _baseFundingCycle.duration *\n                    SECONDS_IN_DAY;\n            }\n        } else {\n            _timeFromImmediateStartMultiple = 0;\n        }\n\n        // Derive what the start time should be.\n        uint256 _start = _deriveStart(\n            _baseFundingCycle,\n            _latestPermanentFundingCycle,\n            block.timestamp - _timeFromImmediateStartMultiple\n        );\n\n        // Derive what the cycle limit should be.\n        uint256 _cycleLimit = _deriveCycleLimit(_baseFundingCycle, _start);\n\n        // Copy the last permanent funding cycle if the bases' limit is up.\n        FundingCycle memory _fundingCycleToCopy = _cycleLimit == 0\n            ? _latestPermanentFundingCycle\n            : _baseFundingCycle;\n\n        return\n            FundingCycle(\n                0,\n                _fundingCycleToCopy.projectId,\n                _deriveNumber(\n                    _baseFundingCycle,\n                    _latestPermanentFundingCycle,\n                    _start\n                ),\n                _fundingCycleToCopy.id,\n                _fundingCycleToCopy.configured,\n                _cycleLimit,\n                _deriveWeight(\n                    _baseFundingCycle,\n                    _latestPermanentFundingCycle,\n                    _start\n                ),\n                _fundingCycleToCopy.ballot,\n                _start,\n                _fundingCycleToCopy.duration,\n                _fundingCycleToCopy.target,\n                _fundingCycleToCopy.currency,\n                _fundingCycleToCopy.fee,\n                _fundingCycleToCopy.discountRate,\n                0,\n                _fundingCycleToCopy.metadata\n            );\n    }\n\n    /** \n      @notice\n      Updates intrinsic properties for a funding cycle given a base cycle.\n\n      @param _fundingCycleId The ID of the funding cycle to make sure is update.\n      @param _baseFundingCycle The cycle that the one being updated is based on.\n      @param _mustStartOnOrAfter The time before which the initialized funding cycle can't start.\n      @param _copy If non-intrinsic properties should be copied from the base funding cycle.\n    */\n    function _updateFundingCycle(\n        uint256 _fundingCycleId,\n        FundingCycle memory _baseFundingCycle,\n        uint256 _mustStartOnOrAfter,\n        bool _copy\n    ) private {\n        // Get the latest permanent funding cycle.\n        FundingCycle memory _latestPermanentFundingCycle = _baseFundingCycle\n        .cycleLimit > 0\n            ? _latestPermanentCycleBefore(_baseFundingCycle)\n            : _baseFundingCycle;\n\n        // Derive the correct next start time from the base.\n        uint256 _start = _deriveStart(\n            _baseFundingCycle,\n            _latestPermanentFundingCycle,\n            _mustStartOnOrAfter\n        );\n\n        // Derive the correct weight.\n        uint256 _weight = _deriveWeight(\n            _baseFundingCycle,\n            _latestPermanentFundingCycle,\n            _start\n        );\n\n        // Derive the correct number.\n        uint256 _number = _deriveNumber(\n            _baseFundingCycle,\n            _latestPermanentFundingCycle,\n            _start\n        );\n\n        // Copy if needed.\n        if (_copy) {\n            // Derive what the cycle limit should be.\n            uint256 _cycleLimit = _deriveCycleLimit(_baseFundingCycle, _start);\n\n            // Copy the last permanent funding cycle if the bases' limit is up.\n            FundingCycle memory _fundingCycleToCopy = _cycleLimit == 0\n                ? _latestPermanentFundingCycle\n                : _baseFundingCycle;\n\n            // Save the configuration efficiently.\n            _packAndStoreConfigurationProperties(\n                _fundingCycleId,\n                _fundingCycleToCopy.configured,\n                _cycleLimit,\n                _fundingCycleToCopy.ballot,\n                _fundingCycleToCopy.duration,\n                _fundingCycleToCopy.currency,\n                _fundingCycleToCopy.fee,\n                _fundingCycleToCopy.discountRate\n            );\n\n            _metadataOf[count] = _metadataOf[_fundingCycleToCopy.id];\n            _targetOf[count] = _targetOf[_fundingCycleToCopy.id];\n        }\n\n        // Update the intrinsic properties.\n        _packAndStoreIntrinsicProperties(\n            _fundingCycleId,\n            _baseFundingCycle.projectId,\n            _weight,\n            _number,\n            _baseFundingCycle.id,\n            _start\n        );\n    }\n\n    /**\n      @notice \n      Efficiently stores a funding cycle's provided intrinsic properties.\n\n      @param _fundingCycleId The ID of the funding cycle to pack and store.\n      @param _projectId The ID of the project to which the funding cycle belongs.\n      @param _weight The weight of the funding cycle.\n      @param _number The number of the funding cycle.\n      @param _basedOn The ID of the based funding cycle.\n      @param _start The start time of this funding cycle.\n\n     */\n    function _packAndStoreIntrinsicProperties(\n        uint256 _fundingCycleId,\n        uint256 _projectId,\n        uint256 _weight,\n        uint256 _number,\n        uint256 _basedOn,\n        uint256 _start\n    ) private {\n        // weight in bytes 0-79 bytes.\n        uint256 packed = _weight;\n        // projectId in bytes 80-135 bytes.\n        packed |= _projectId << 80;\n        // basedOn in bytes 136-183 bytes.\n        packed |= _basedOn << 136;\n        // start in bytes 184-231 bytes.\n        packed |= _start << 184;\n        // number in bytes 232-255 bytes.\n        packed |= _number << 232;\n\n        // Set in storage.\n        _packedIntrinsicPropertiesOf[_fundingCycleId] = packed;\n    }\n\n    /**\n      @notice \n      Efficiently stores a funding cycles provided configuration properties.\n\n      @param _fundingCycleId The ID of the funding cycle to pack and store.\n      @param _configured The timestamp of the configuration.\n      @param _cycleLimit The number of cycles that this configuration should last for before going back to the last permanent.\n      @param _ballot The ballot to use for future reconfiguration approvals. \n      @param _duration The duration of the funding cycle.\n      @param _currency The currency of the funding cycle.\n      @param _fee The fee of the funding cycle.\n      @param _discountRate The discount rate of the based funding cycle.\n     */\n    function _packAndStoreConfigurationProperties(\n        uint256 _fundingCycleId,\n        uint256 _configured,\n        uint256 _cycleLimit,\n        IFundingCycleBallot _ballot,\n        uint256 _duration,\n        uint256 _currency,\n        uint256 _fee,\n        uint256 _discountRate\n    ) private {\n        // ballot in bytes 0-159 bytes.\n        uint256 packed = uint160(address(_ballot));\n        // configured in bytes 160-207 bytes.\n        packed |= _configured << 160;\n        // duration in bytes 208-223 bytes.\n        packed |= _duration << 208;\n        // basedOn in bytes 224-231 bytes.\n        packed |= _currency << 224;\n        // fee in bytes 232-239 bytes.\n        packed |= _fee << 232;\n        // discountRate in bytes 240-247 bytes.\n        packed |= _discountRate << 240;\n        // cycleLimit in bytes 248-255 bytes.\n        packed |= _cycleLimit << 248;\n\n        // Set in storage.\n        _packedConfigurationPropertiesOf[_fundingCycleId] = packed;\n    }\n\n    /**\n        @notice \n        Unpack a funding cycle's packed stored values into an easy-to-work-with funding cycle struct.\n\n        @param _id The ID of the funding cycle to get a struct of.\n\n        @return _fundingCycle The funding cycle struct.\n    */\n    function _getStruct(uint256 _id)\n        private\n        view\n        returns (FundingCycle memory _fundingCycle)\n    {\n        // Return an empty funding cycle if the ID specified is 0.\n        if (_id == 0) return _fundingCycle;\n\n        _fundingCycle.id = _id;\n\n        uint256 _packedIntrinsicProperties = _packedIntrinsicPropertiesOf[_id];\n\n        _fundingCycle.weight = uint256(uint80(_packedIntrinsicProperties));\n        _fundingCycle.projectId = uint256(\n            uint56(_packedIntrinsicProperties >> 80)\n        );\n        _fundingCycle.basedOn = uint256(\n            uint48(_packedIntrinsicProperties >> 136)\n        );\n        _fundingCycle.start = uint256(\n            uint48(_packedIntrinsicProperties >> 184)\n        );\n        _fundingCycle.number = uint256(\n            uint24(_packedIntrinsicProperties >> 232)\n        );\n\n\n            uint256 _packedConfigurationProperties\n         = _packedConfigurationPropertiesOf[_id];\n        _fundingCycle.ballot = IFundingCycleBallot(\n            address(uint160(_packedConfigurationProperties))\n        );\n        _fundingCycle.configured = uint256(\n            uint48(_packedConfigurationProperties >> 160)\n        );\n        _fundingCycle.duration = uint256(\n            uint16(_packedConfigurationProperties >> 208)\n        );\n        _fundingCycle.currency = uint256(\n            uint8(_packedConfigurationProperties >> 224)\n        );\n        _fundingCycle.fee = uint256(\n            uint8(_packedConfigurationProperties >> 232)\n        );\n        _fundingCycle.discountRate = uint256(\n            uint8(_packedConfigurationProperties >> 240)\n        );\n        _fundingCycle.cycleLimit = uint256(\n            uint8(_packedConfigurationProperties >> 248)\n        );\n        _fundingCycle.target = _targetOf[_id];\n        _fundingCycle.tapped = _tappedOf[_id];\n        _fundingCycle.metadata = _metadataOf[_id];\n    }\n\n    /** \n        @notice \n        The date that is the nearest multiple of the specified funding cycle's duration from its end.\n\n        @param _baseFundingCycle The funding cycle to make the calculation for.\n        @param _latestPermanentFundingCycle The latest funding cycle in the same project as `_baseFundingCycle` to not have a limit.\n        @param _mustStartOnOrAfter A date that the derived start must be on or come after.\n\n        @return start The next start time.\n    */\n    function _deriveStart(\n        FundingCycle memory _baseFundingCycle,\n        FundingCycle memory _latestPermanentFundingCycle,\n        uint256 _mustStartOnOrAfter\n    ) internal pure returns (uint256 start) {\n        // A subsequent cycle to one with a duration of 0 should start as soon as possible.\n        if (_baseFundingCycle.duration == 0) return _mustStartOnOrAfter;\n\n        // Save a reference to the duration measured in seconds.\n        uint256 _durationInSeconds = _baseFundingCycle.duration *\n            SECONDS_IN_DAY;\n\n        // The time when the funding cycle immediately after the specified funding cycle starts.\n        uint256 _nextImmediateStart = _baseFundingCycle.start +\n            _durationInSeconds;\n\n        // If the next immediate start is now or in the future, return it.\n        if (_nextImmediateStart >= _mustStartOnOrAfter)\n            return _nextImmediateStart;\n\n        uint256 _cycleLimit = _baseFundingCycle.cycleLimit;\n\n        uint256 _timeFromImmediateStartMultiple;\n        // Only use base\n        if (\n            _mustStartOnOrAfter <=\n            _baseFundingCycle.start + _durationInSeconds * _cycleLimit\n        ) {\n            // Otherwise, use the closest multiple of the duration from the old end.\n            _timeFromImmediateStartMultiple =\n                (_mustStartOnOrAfter - _nextImmediateStart) %\n                _durationInSeconds;\n        } else {\n            // If the cycle has ended, make the calculation with the latest permanent funding cycle.\n            _timeFromImmediateStartMultiple = _latestPermanentFundingCycle\n            .duration == 0\n                ? 0\n                : ((_mustStartOnOrAfter -\n                    (_baseFundingCycle.start +\n                        (_durationInSeconds * _cycleLimit))) %\n                    (_latestPermanentFundingCycle.duration * SECONDS_IN_DAY));\n\n            // Use the duration of the permanent funding cycle from here on out.\n            _durationInSeconds =\n                _latestPermanentFundingCycle.duration *\n                SECONDS_IN_DAY;\n        }\n\n        // Otherwise use an increment of the duration from the most recent start.\n        start = _mustStartOnOrAfter - _timeFromImmediateStartMultiple;\n\n        // Add increments of duration as necessary to satisfy the threshold.\n        while (_mustStartOnOrAfter > start) start = start + _durationInSeconds;\n    }\n\n    /** \n        @notice \n        The accumulated weight change since the specified funding cycle.\n\n        @param _baseFundingCycle The funding cycle to make the calculation with.\n        @param _latestPermanentFundingCycle The latest funding cycle in the same project as `_fundingCycle` to not have a limit.\n        @param _start The start time to derive a weight for.\n\n        @return weight The next weight.\n    */\n    function _deriveWeight(\n        FundingCycle memory _baseFundingCycle,\n        FundingCycle memory _latestPermanentFundingCycle,\n        uint256 _start\n    ) internal pure returns (uint256 weight) {\n        // A subsequent cycle to one with a duration of 0 should have the next possible weight.\n        if (_baseFundingCycle.duration == 0)\n            return\n                PRBMath.mulDiv(\n                    _baseFundingCycle.weight,\n                    1000 - _baseFundingCycle.discountRate,\n                    1000\n                );\n\n        // The difference between the start of the base funding cycle and the proposed start.\n        uint256 _startDistance = _start - _baseFundingCycle.start;\n\n        // The number of seconds that the base funding cycle is limited to.\n        uint256 _limitLength = _baseFundingCycle.cycleLimit == 0 ||\n            _baseFundingCycle.basedOn == 0\n            ? 0\n            : _baseFundingCycle.cycleLimit *\n                (_baseFundingCycle.duration * SECONDS_IN_DAY);\n\n        // The weight should be based off the base funding cycle's weight.\n        weight = _baseFundingCycle.weight;\n\n        // If there's no limit or if the limit is greater than the start distance,\n        // apply the discount rate of the base.\n        if (_limitLength == 0 || _limitLength > _startDistance) {\n            // If the discount rate is 0, return the same weight.\n            if (_baseFundingCycle.discountRate == 0) return weight;\n\n            uint256 _discountMultiple = _startDistance /\n                (_baseFundingCycle.duration * SECONDS_IN_DAY);\n\n            for (uint256 i = 0; i < _discountMultiple; i++) {\n                // The number of times to apply the discount rate.\n                // Base the new weight on the specified funding cycle's weight.\n                weight = PRBMath.mulDiv(\n                    weight,\n                    1000 - _baseFundingCycle.discountRate,\n                    1000\n                );\n            }\n        } else {\n            // If the time between the base start at the given start is longer than\n            // the limit, the discount rate for the limited base has to be applied first,\n            // and then the discount rate for the last permanent should be applied to\n            // the remaining distance.\n\n            // Use up the limited discount rate up until the limit.\n            if (_baseFundingCycle.discountRate > 0) {\n                for (uint256 i = 0; i < _baseFundingCycle.cycleLimit; i++) {\n                    weight = PRBMath.mulDiv(\n                        weight,\n                        1000 - _baseFundingCycle.discountRate,\n                        1000\n                    );\n                }\n            }\n\n            if (_latestPermanentFundingCycle.discountRate > 0) {\n                // The number of times to apply the latest permanent discount rate.\n\n\n                    uint256 _permanentDiscountMultiple\n                 = _latestPermanentFundingCycle.duration == 0\n                    ? 0\n                    : (_startDistance - _limitLength) /\n                        (_latestPermanentFundingCycle.duration *\n                            SECONDS_IN_DAY);\n\n                for (uint256 i = 0; i < _permanentDiscountMultiple; i++) {\n                    // base the weight on the result of the previous calculation.\n                    weight = PRBMath.mulDiv(\n                        weight,\n                        1000 - _latestPermanentFundingCycle.discountRate,\n                        1000\n                    );\n                }\n            }\n        }\n    }\n\n    /** \n        @notice \n        The number of the next funding cycle given the specified funding cycle.\n\n        @param _baseFundingCycle The funding cycle to make the calculation with.\n        @param _latestPermanentFundingCycle The latest funding cycle in the same project as `_fundingCycle` to not have a limit.\n        @param _start The start time to derive a number for.\n\n        @return number The next number.\n    */\n    function _deriveNumber(\n        FundingCycle memory _baseFundingCycle,\n        FundingCycle memory _latestPermanentFundingCycle,\n        uint256 _start\n    ) internal pure returns (uint256 number) {\n        // A subsequent cycle to one with a duration of 0 should be the next number.\n        if (_baseFundingCycle.duration == 0)\n            return _baseFundingCycle.number + 1;\n\n        // The difference between the start of the base funding cycle and the proposed start.\n        uint256 _startDistance = _start - _baseFundingCycle.start;\n\n        // The number of seconds that the base funding cycle is limited to.\n        uint256 _limitLength = _baseFundingCycle.cycleLimit == 0\n            ? 0\n            : _baseFundingCycle.cycleLimit *\n                (_baseFundingCycle.duration * SECONDS_IN_DAY);\n\n        if (_limitLength == 0 || _limitLength > _startDistance) {\n            // If there's no limit or if the limit is greater than the start distance,\n            // get the result by finding the number of base cycles that fit in the start distance.\n            number =\n                _baseFundingCycle.number +\n                (_startDistance /\n                    (_baseFundingCycle.duration * SECONDS_IN_DAY));\n        } else {\n            // If the time between the base start at the given start is longer than\n            // the limit, first calculate the number of cycles that passed under the limit,\n            // and add any cycles that have passed of the latest permanent funding cycle afterwards.\n\n            number =\n                _baseFundingCycle.number +\n                (_limitLength / (_baseFundingCycle.duration * SECONDS_IN_DAY));\n\n            number =\n                number +\n                (\n                    _latestPermanentFundingCycle.duration == 0\n                        ? 0\n                        : ((_startDistance - _limitLength) /\n                            (_latestPermanentFundingCycle.duration *\n                                SECONDS_IN_DAY))\n                );\n        }\n    }\n\n    /** \n        @notice \n        The limited number of times a funding cycle configuration can be active given the specified funding cycle.\n\n        @param _fundingCycle The funding cycle to make the calculation with.\n        @param _start The start time to derive cycles remaining for.\n\n        @return start The inclusive nunmber of cycles remaining.\n    */\n    function _deriveCycleLimit(\n        FundingCycle memory _fundingCycle,\n        uint256 _start\n    ) internal pure returns (uint256) {\n        if (_fundingCycle.cycleLimit <= 1 || _fundingCycle.duration == 0)\n            return 0;\n        uint256 _cycles = ((_start - _fundingCycle.start) /\n            (_fundingCycle.duration * SECONDS_IN_DAY));\n\n        if (_cycles >= _fundingCycle.cycleLimit) return 0;\n        return _fundingCycle.cycleLimit - _cycles;\n    }\n\n    /** \n      @notice \n      Checks to see if the funding cycle of the provided ID is approved according to the correct ballot.\n\n      @param _fundingCycleId The ID of the funding cycle to get an approval flag for.\n\n      @return The approval flag.\n    */\n    function _isIdApproved(uint256 _fundingCycleId)\n        private\n        view\n        returns (bool)\n    {\n        FundingCycle memory _fundingCycle = _getStruct(_fundingCycleId);\n        return _isApproved(_fundingCycle);\n    }\n\n    /** \n      @notice \n      Checks to see if the provided funding cycle is approved according to the correct ballot.\n\n      @param _fundingCycle The ID of the funding cycle to get an approval flag for.\n\n      @return The approval flag.\n    */\n    function _isApproved(FundingCycle memory _fundingCycle)\n        private\n        view\n        returns (bool)\n    {\n        return\n            _ballotState(\n                _fundingCycle.id,\n                _fundingCycle.configured,\n                _fundingCycle.basedOn\n            ) == BallotState.Approved;\n    }\n\n    /**\n        @notice \n        A funding cycle configuration's currency status.\n\n        @param _id The ID of the funding cycle configuration to check the status of.\n        @param _configuration The timestamp of when the configuration took place.\n        @param _ballotFundingCycleId The ID of the funding cycle which is configured with the ballot that should be used.\n\n        @return The funding cycle's configuration status.\n    */\n    function _ballotState(\n        uint256 _id,\n        uint256 _configuration,\n        uint256 _ballotFundingCycleId\n    ) private view returns (BallotState) {\n        // If there is no ballot funding cycle, auto approve.\n        if (_ballotFundingCycleId == 0) return BallotState.Approved;\n\n        // Get the ballot funding cycle.\n        FundingCycle memory _ballotFundingCycle = _getStruct(\n            _ballotFundingCycleId\n        );\n\n        // If the configuration is the same as the ballot's funding cycle,\n        // the ballot isn't applicable. Auto approve since the ballot funding cycle is approved.\n        if (_ballotFundingCycle.configured == _configuration)\n            return BallotState.Approved;\n\n        // If there is no ballot, the ID is auto approved.\n        // Otherwise, return the ballot's state.\n        return\n            _ballotFundingCycle.ballot == IFundingCycleBallot(address(0))\n                ? BallotState.Approved\n                : _ballotFundingCycle.ballot.state(_id, _configuration);\n    }\n\n    /** \n      @notice \n      Finds the last funding cycle that was permanent in relation to the specified funding cycle.\n\n      @dev\n      Determined what the latest funding cycle with a `cycleLimit` of 0 is, or isn't based on any previous funding cycle.\n\n\n      @param _fundingCycle The funding cycle to find the most recent permanent cycle compared to.\n\n      @return fundingCycle The most recent permanent funding cycle.\n    */\n    function _latestPermanentCycleBefore(FundingCycle memory _fundingCycle)\n        private\n        view\n        returns (FundingCycle memory fundingCycle)\n    {\n        if (_fundingCycle.basedOn == 0) return _fundingCycle;\n        fundingCycle = _getStruct(_fundingCycle.basedOn);\n        if (fundingCycle.cycleLimit == 0) return fundingCycle;\n        return _latestPermanentCycleBefore(fundingCycle);\n    }\n\n    /** \n      @notice\n      The time after the ballot of the provided funding cycle has expired.\n\n      @dev\n      If the ballot ends in the past, the current block timestamp will be returned.\n\n      @param _fundingCycle The ID funding cycle to make the caluclation the ballot of.\n      @param _from The time from which the ballot duration should be calculated.\n\n      @return The time when the ballot duration ends.\n    */\n    function _getTimeAfterBallot(\n        FundingCycle memory _fundingCycle,\n        uint256 _from\n    ) private view returns (uint256) {\n        // The ballot must have ended.\n        uint256 _ballotExpiration = _fundingCycle.ballot !=\n            IFundingCycleBallot(address(0))\n            ? _from + _fundingCycle.ballot.duration()\n            : 0;\n\n        return\n            block.timestamp > _ballotExpiration\n                ? block.timestamp\n                : _ballotExpiration;\n    }\n}\n"
    },
    "contracts/Prices.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport \"./interfaces/IPrices.sol\";\n\n/** \n  @notice Manage and normalizes ETH price feeds.\n*/\ncontract Prices is IPrices, Ownable {\n    // --- public constant stored properties --- //\n\n    /// @notice The target number of decimals the price feed results have.\n    uint256 public constant override targetDecimals = 18;\n\n    // --- public stored properties --- //\n\n    /// @notice The number to multiply each price feed by to get to the target decimals.\n    mapping(uint256 => uint256) public override feedDecimalAdjuster;\n\n    /// @notice The available price feeds that can be used to get the price of ETH.\n    mapping(uint256 => AggregatorV3Interface) public override feedFor;\n\n    // --- external views --- //\n\n    /** \n      @notice \n      Gets the current price of ETH for the provided currency.\n      \n      @param _currency The currency to get a price for.\n      \n      @return price The price of ETH with 18 decimals.\n    */\n    function getETHPriceFor(uint256 _currency)\n        external\n        view\n        override\n        returns (uint256)\n    {\n        // The 0 currency is ETH itself.\n        if (_currency == 0) return 10**targetDecimals;\n\n        // Get a reference to the feed.\n        AggregatorV3Interface _feed = feedFor[_currency];\n\n        // Feed must exist.\n        require(\n            _feed != AggregatorV3Interface(address(0)),\n            \"Prices::getETHPrice: NOT_FOUND\"\n        );\n\n        // Get the lateset round information. Only need the price is needed.\n        (, int256 _price, , , ) = _feed.latestRoundData();\n\n        // Multiply the price by the decimal adjuster to get the normalized result.\n        return uint256(_price) * feedDecimalAdjuster[_currency];\n    }\n\n    // --- external transactions --- //\n\n    /** \n      @notice \n      Add a price feed for the price of ETH.\n\n      @dev\n      Current feeds can't be modified.\n\n      @param _feed The price feed being added.\n      @param _currency The currency that the price feed is for.\n    */\n    function addFeed(AggregatorV3Interface _feed, uint256 _currency)\n        external\n        override\n        onlyOwner\n    {\n        // The 0 currency is reserved for ETH.\n        require(_currency > 0, \"Prices::addFeed: RESERVED\");\n\n        // There can't already be a feed for the specified currency.\n        require(\n            feedFor[_currency] == AggregatorV3Interface(address(0)),\n            \"Prices::addFeed: ALREADY_EXISTS\"\n        );\n\n        // Get a reference to the number of decimals the feed uses.\n        uint256 _decimals = _feed.decimals();\n\n        // Decimals should be less than or equal to the target number of decimals.\n        require(_decimals <= targetDecimals, \"Prices::addFeed: BAD_DECIMALS\");\n\n        // Set the feed.\n        feedFor[_currency] = _feed;\n\n        // Set the decimal adjuster for the currency.\n        feedDecimalAdjuster[_currency] = 10**(targetDecimals - _decimals);\n\n        emit AddFeed(_currency, _feed);\n    }\n}\n"
    },
    "contracts/Governance.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITerminal.sol\";\nimport \"./interfaces/IPrices.sol\";\nimport \"./abstract/JuiceboxProject.sol\";\n\n/// Owner should eventually change to a multisig wallet contract.\ncontract Governance is JuiceboxProject {\n    // --- external transactions --- //\n\n    constructor(uint256 _projectId, ITerminalDirectory _terminalDirectory)\n        JuiceboxProject(_projectId, _terminalDirectory)\n    {}\n\n    /** \n      @notice Gives projects using one Terminal access to migrate to another Terminal.\n      @param _from The terminal to allow a new migration from.\n      @param _to The terminal to allow migration to.\n    */\n    function allowMigration(ITerminal _from, ITerminal _to) external onlyOwner {\n        _from.allowMigration(_to);\n    }\n\n    /**\n        @notice Adds a price feed.\n        @param _prices The prices contract to add a feed to.\n        @param _feed The price feed to add.\n        @param _currency The currency the price feed is for.\n    */\n    function addPriceFeed(\n        IPrices _prices,\n        AggregatorV3Interface _feed,\n        uint256 _currency\n    ) external onlyOwner {\n        _prices.addFeed(_feed, _currency);\n    }\n\n    /** \n      @notice Sets the fee of the TerminalV1.\n      @param _terminalV1 The terminalV1 to change the fee of.\n      @param _fee The new fee.\n    */\n    function setFee(ITerminalV1 _terminalV1, uint256 _fee) external onlyOwner {\n        _terminalV1.setFee(_fee);\n    }\n\n    /** \n      @notice Appoints a new governance for the specified terminalV1.\n      @param _terminalV1 The terminalV1 to change the governance of.\n      @param _newGovernance The address to appoint as governance.\n    */\n    function appointGovernance(\n        ITerminalV1 _terminalV1,\n        address payable _newGovernance\n    ) external onlyOwner {\n        _terminalV1.appointGovernance(_newGovernance);\n    }\n\n    /** \n      @notice Accepts the offer to be the governance of a new terminalV1.\n      @param _terminalV1 The terminalV1 to change the governance of.\n    */\n    function acceptGovernance(ITerminalV1 _terminalV1) external onlyOwner {\n        _terminalV1.acceptGovernance();\n    }\n}\n"
    },
    "contracts/Projects.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC721/ERC721.sol\";\n\nimport \"./abstract/Operatable.sol\";\nimport \"./interfaces/IProjects.sol\";\n\nimport \"./libraries/Operations.sol\";\n\n/** \n  @notice \n  Stores project ownership and identifying information.\n\n  @dev\n  Projects are represented as ERC-721's.\n*/\ncontract Projects is ERC721, IProjects, Operatable {\n    // --- private stored properties --- //\n\n    // The number of seconds in a day.\n    uint256 private constant SECONDS_IN_YEAR = 31536000;\n\n    // --- public stored properties --- //\n\n    /// @notice A running count of project IDs.\n    uint256 public override count = 0;\n\n    /// @notice Optional mapping for project URIs\n    mapping(uint256 => string) public override uriOf;\n\n    /// @notice Each project's handle.\n    mapping(uint256 => bytes32) public override handleOf;\n\n    /// @notice The project that each unique handle represents.\n    mapping(bytes32 => uint256) public override projectFor;\n\n    /// @notice Handles that have been transfered to the specified address.\n    mapping(bytes32 => address) public override transferAddressFor;\n\n    /// @notice The timestamps when each handle is claimable. A value of 0 means a handle isn't being challenged.\n    mapping(bytes32 => uint256) public override challengeExpiryOf;\n\n    // --- external views --- //\n\n    /** \n      @notice \n      Whether the specified project exists.\n\n      @param _projectId The project to check the existence of.\n\n      @return A flag indicating if the project exists.\n    */\n    function exists(uint256 _projectId) external view override returns (bool) {\n        return _exists(_projectId);\n    }\n\n    // --- external transactions --- //\n\n    /** \n      @param _operatorStore A contract storing operator assignments.\n    */\n    constructor(IOperatorStore _operatorStore)\n        ERC721(\"Juicebox project\", \"JUICEBOX PROJECT\")\n        Operatable(_operatorStore)\n    {}\n\n    /**\n        @notice \n        Create a new project.\n\n        @dev \n        Anyone can create a project on an owner's behalf.\n\n        @param _owner The owner of the project.\n        @param _handle A unique handle for the project.\n        @param _uri An ipfs CID to more info about the project.\n        @param _terminal The terminal to set for this project so that it can start receiving payments.\n\n        @return The new project's ID.\n    */\n    function create(\n        address _owner,\n        bytes32 _handle,\n        string calldata _uri,\n        ITerminal _terminal\n    ) external override returns (uint256) {\n        // Handle must exist.\n        require(_handle != bytes32(0), \"Projects::create: EMPTY_HANDLE\");\n\n        // Handle must be unique.\n        require(\n            projectFor[_handle] == 0 &&\n                transferAddressFor[_handle] == address(0),\n            \"Projects::create: HANDLE_TAKEN\"\n        );\n\n        // Increment the count, which will be used as the ID.\n        count++;\n\n        // Mint the project.\n        _safeMint(_owner, count);\n\n        // Set the handle stored values.\n        handleOf[count] = _handle;\n        projectFor[_handle] = count;\n\n        // Set the URI if one was provided.\n        if (bytes(_uri).length > 0) uriOf[count] = _uri;\n\n        // Set the project's terminal if needed.\n        if (_terminal != ITerminal(address(0)))\n            _terminal.terminalDirectory().setTerminal(count, _terminal);\n\n        emit Create(count, _owner, _handle, _uri, _terminal, msg.sender);\n\n        return count;\n    }\n\n    /**\n      @notice \n      Allows a project owner to set the project's handle.\n\n      @dev \n      Only a project's owner or operator can set its handle.\n\n      @param _projectId The ID of the project.\n      @param _handle The new unique handle for the project.\n    */\n    function setHandle(uint256 _projectId, bytes32 _handle)\n        external\n        override\n        requirePermission(ownerOf(_projectId), _projectId, Operations.SetHandle)\n    {\n        // Handle must exist.\n        require(_handle != bytes32(0), \"Projects::setHandle: EMPTY_HANDLE\");\n\n        // Handle must be unique.\n        require(\n            projectFor[_handle] == 0 &&\n                transferAddressFor[_handle] == address(0),\n            \"Projects::setHandle: HANDLE_TAKEN\"\n        );\n\n        // Register the change in the resolver.\n        projectFor[handleOf[_projectId]] = 0;\n\n        projectFor[_handle] = _projectId;\n        handleOf[_projectId] = _handle;\n\n        emit SetHandle(_projectId, _handle, msg.sender);\n    }\n\n    /**\n      @notice \n      Allows a project owner to set the project's uri.\n\n      @dev \n      Only a project's owner or operator can set its uri.\n\n      @param _projectId The ID of the project.\n      @param _uri An ipfs CDN to more info about the project. Don't include the leading ipfs://\n    */\n    function setUri(uint256 _projectId, string calldata _uri)\n        external\n        override\n        requirePermission(ownerOf(_projectId), _projectId, Operations.SetUri)\n    {\n        // Set the new uri.\n        uriOf[_projectId] = _uri;\n\n        emit SetUri(_projectId, _uri, msg.sender);\n    }\n\n    /**\n      @notice \n      Allows a project owner to transfer its handle to another address.\n\n      @dev \n      Only a project's owner or operator can transfer its handle.\n\n      @param _projectId The ID of the project to transfer the handle from.\n      @param _to The address that can now reallocate the handle.\n      @param _newHandle The new unique handle for the project that will replace the transfered one.\n    */\n    function transferHandle(\n        uint256 _projectId,\n        address _to,\n        bytes32 _newHandle\n    )\n        external\n        override\n        requirePermission(ownerOf(_projectId), _projectId, Operations.SetHandle)\n        returns (bytes32 _handle)\n    {\n        require(\n            _newHandle != bytes32(0),\n            \"Projects::transferHandle: EMPTY_HANDLE\"\n        );\n\n        require(\n            projectFor[_newHandle] == 0 &&\n                transferAddressFor[_handle] == address(0),\n            \"Projects::transferHandle: HANDLE_TAKEN\"\n        );\n\n        // Get a reference to the project's currency handle.\n        _handle = handleOf[_projectId];\n\n        // Remove the resolver for the transfered handle.\n        projectFor[_handle] = 0;\n\n        // If the handle is changing, register the change in the resolver.\n        projectFor[_newHandle] = _projectId;\n        handleOf[_projectId] = _newHandle;\n\n        // Transfer the current handle.\n        transferAddressFor[_handle] = _to;\n\n        emit TransferHandle(_projectId, _to, _handle, _newHandle, msg.sender);\n    }\n\n    /**\n      @notice \n      Allows an address to claim and handle that has been transfered to them and apply it to a project of theirs.\n\n      @dev \n      Only a project's owner or operator can claim a handle onto it.\n\n      @param _handle The handle being claimed.\n      @param _for The address that the handle has been transfered to.\n      @param _projectId The ID of the project to use the claimed handle.\n    */\n    function claimHandle(\n        bytes32 _handle,\n        address _for,\n        uint256 _projectId\n    )\n        external\n        override\n        requirePermissionAllowingWildcardDomain(\n            _for,\n            _projectId,\n            Operations.ClaimHandle\n        )\n        requirePermission(\n            ownerOf(_projectId),\n            _projectId,\n            Operations.ClaimHandle\n        )\n    {\n        // The handle must have been transfered to the specified address,\n        // or the handle challange must have expired before being renewed.\n        require(\n            transferAddressFor[_handle] == _for ||\n                (challengeExpiryOf[_handle] > 0 &&\n                    block.timestamp > challengeExpiryOf[_handle]),\n            \"Projects::claimHandle: UNAUTHORIZED\"\n        );\n\n        // Register the change in the resolver.\n        projectFor[handleOf[_projectId]] = 0;\n\n        // Register the change in the resolver.\n        projectFor[_handle] = _projectId;\n\n        // Set the new handle.\n        handleOf[_projectId] = _handle;\n\n        // Set the handle as not being transfered.\n        transferAddressFor[_handle] = address(0);\n\n        // Reset the challenge to 0.\n        challengeExpiryOf[_handle] = 0;\n\n        emit ClaimHandle(_for, _projectId, _handle, msg.sender);\n    }\n\n    /** \n      @notice\n      Allows anyone to challenge a project's handle. After one year, the handle can be claimed by the public if the challenge isn't answered by the handle's project.\n      This can be used to make sure a handle belonging to an unattended to project isn't lost forever.\n\n      @param _handle The handle to challenge.\n    */\n    function challengeHandle(bytes32 _handle) external {\n        // No need to challenge a handle that's not taken.\n        require(\n            projectFor[_handle] > 0,\n            \"Projects::challenge: HANDLE_NOT_TAKEN\"\n        );\n\n        // No need to challenge again if a handle is already being challenged.\n        require(\n            challengeExpiryOf[_handle] == 0,\n            \"Projects::challenge: HANDLE_ALREADY_BEING_CHALLENGED\"\n        );\n\n        // The challenge will expire in a year, at which point the handle can be claimed if the challenge hasn't been answered.\n        uint256 _challengeExpiry = block.timestamp + SECONDS_IN_YEAR;\n\n        challengeExpiryOf[_handle] = _challengeExpiry;\n\n        emit ChallengeHandle(_handle, _challengeExpiry, msg.sender);\n    }\n\n    /** \n      @notice\n      Allows a project to renew its handle so it can't be claimed until a year after its challenged again.\n\n      @dev \n      Only a project's owner or operator can renew its handle.\n\n      @param _projectId The ID of the project that current has the handle being renewed.\n    */\n    function renewHandle(uint256 _projectId)\n        external\n        requirePermission(\n            ownerOf(_projectId),\n            _projectId,\n            Operations.RenewHandle\n        )\n    {\n        // Get the handle of the project.\n        bytes32 _handle = handleOf[_projectId];\n\n        // Reset the challenge to 0.\n        challengeExpiryOf[_handle] = 0;\n\n        emit RenewHandle(_handle, _projectId, msg.sender);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/ERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n    using Address for address;\n    using Strings for uint256;\n\n    // Token name\n    string private _name;\n\n    // Token symbol\n    string private _symbol;\n\n    // Mapping from token ID to owner address\n    mapping(uint256 => address) private _owners;\n\n    // Mapping owner address to token count\n    mapping(address => uint256) private _balances;\n\n    // Mapping from token ID to approved address\n    mapping(uint256 => address) private _tokenApprovals;\n\n    // Mapping from owner to operator approvals\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n        return\n            interfaceId == type(IERC721).interfaceId ||\n            interfaceId == type(IERC721Metadata).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function balanceOf(address owner) public view virtual override returns (uint256) {\n        require(owner != address(0), \"ERC721: balance query for the zero address\");\n        return _balances[owner];\n    }\n\n    /**\n     * @dev See {IERC721-ownerOf}.\n     */\n    function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n        address owner = _owners[tokenId];\n        require(owner != address(0), \"ERC721: owner query for nonexistent token\");\n        return owner;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-name}.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-symbol}.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-tokenURI}.\n     */\n    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n        require(_exists(tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, can be overriden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return \"\";\n    }\n\n    /**\n     * @dev See {IERC721-approve}.\n     */\n    function approve(address to, uint256 tokenId) public virtual override {\n        address owner = ERC721.ownerOf(tokenId);\n        require(to != owner, \"ERC721: approval to current owner\");\n\n        require(\n            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n            \"ERC721: approve caller is not owner nor approved for all\"\n        );\n\n        _approve(to, tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-getApproved}.\n     */\n    function getApproved(uint256 tokenId) public view virtual override returns (address) {\n        require(_exists(tokenId), \"ERC721: approved query for nonexistent token\");\n\n        return _tokenApprovals[tokenId];\n    }\n\n    /**\n     * @dev See {IERC721-setApprovalForAll}.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual override {\n        require(operator != _msgSender(), \"ERC721: approve to caller\");\n\n        _operatorApprovals[_msgSender()][operator] = approved;\n        emit ApprovalForAll(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @dev See {IERC721-isApprovedForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n        return _operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev See {IERC721-transferFrom}.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual override {\n        //solhint-disable-next-line max-line-length\n        require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n\n        _transfer(from, to, tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual override {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) public virtual override {\n        require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: transfer caller is not owner nor approved\");\n        _safeTransfer(from, to, tokenId, _data);\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * `_data` is additional data, it has no specified format and it is sent in call to `to`.\n     *\n     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n     * implement alternative mechanisms to perform token transfer, such as signature-based.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeTransfer(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) internal virtual {\n        _transfer(from, to, tokenId);\n        require(_checkOnERC721Received(from, to, tokenId, _data), \"ERC721: transfer to non ERC721Receiver implementer\");\n    }\n\n    /**\n     * @dev Returns whether `tokenId` exists.\n     *\n     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n     *\n     * Tokens start existing when they are minted (`_mint`),\n     * and stop existing when they are burned (`_burn`).\n     */\n    function _exists(uint256 tokenId) internal view virtual returns (bool) {\n        return _owners[tokenId] != address(0);\n    }\n\n    /**\n     * @dev Returns whether `spender` is allowed to manage `tokenId`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n        require(_exists(tokenId), \"ERC721: operator query for nonexistent token\");\n        address owner = ERC721.ownerOf(tokenId);\n        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));\n    }\n\n    /**\n     * @dev Safely mints `tokenId` and transfers it to `to`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeMint(address to, uint256 tokenId) internal virtual {\n        _safeMint(to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeMint(\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) internal virtual {\n        _mint(to, tokenId);\n        require(\n            _checkOnERC721Received(address(0), to, tokenId, _data),\n            \"ERC721: transfer to non ERC721Receiver implementer\"\n        );\n    }\n\n    /**\n     * @dev Mints `tokenId` and transfers it to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - `to` cannot be the zero address.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _mint(address to, uint256 tokenId) internal virtual {\n        require(to != address(0), \"ERC721: mint to the zero address\");\n        require(!_exists(tokenId), \"ERC721: token already minted\");\n\n        _beforeTokenTransfer(address(0), to, tokenId);\n\n        _balances[to] += 1;\n        _owners[tokenId] = to;\n\n        emit Transfer(address(0), to, tokenId);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId) internal virtual {\n        address owner = ERC721.ownerOf(tokenId);\n\n        _beforeTokenTransfer(owner, address(0), tokenId);\n\n        // Clear approvals\n        _approve(address(0), tokenId);\n\n        _balances[owner] -= 1;\n        delete _owners[tokenId];\n\n        emit Transfer(owner, address(0), tokenId);\n    }\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {\n        require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer of token that is not own\");\n        require(to != address(0), \"ERC721: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, tokenId);\n\n        // Clear approvals from the previous owner\n        _approve(address(0), tokenId);\n\n        _balances[from] -= 1;\n        _balances[to] += 1;\n        _owners[tokenId] = to;\n\n        emit Transfer(from, to, tokenId);\n    }\n\n    /**\n     * @dev Approve `to` to operate on `tokenId`\n     *\n     * Emits a {Approval} event.\n     */\n    function _approve(address to, uint256 tokenId) internal virtual {\n        _tokenApprovals[tokenId] = to;\n        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n    }\n\n    /**\n     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n     * The call is not executed if the target address is not a contract.\n     *\n     * @param from address representing the previous owner of the given token ID\n     * @param to target address that will receive the tokens\n     * @param tokenId uint256 ID of the token to be transferred\n     * @param _data bytes optional data to send along with the call\n     * @return bool whether the call correctly returned the expected magic value\n     */\n    function _checkOnERC721Received(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) private returns (bool) {\n        if (to.isContract()) {\n            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {\n                return retval == IERC721Receiver(to).onERC721Received.selector;\n            } catch (bytes memory reason) {\n                if (reason.length == 0) {\n                    revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n                } else {\n                    assembly {\n                        revert(add(32, reason), mload(reason))\n                    }\n                }\n            }\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any token transfer. This includes minting\n     * and burning.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` will be minted for `to`.\n     * - When `to` is zero, ``from``'s `tokenId` will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
    },
    "@openzeppelin/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\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        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\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        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp >>= 8;\n        }\n        return toHexString(value, length);\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] = _HEX_SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "contracts/ExampleFailingFundingCycleBallot.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITerminalV1.sol\";\nimport \"./interfaces/IFundingCycleBallot.sol\";\n\ncontract ExampleFailingFundingCycleBallot is IFundingCycleBallot {\n    uint256 public constant reconfigurationDelay = 1209600;\n\n    function duration() external pure override returns (uint256) {\n        return reconfigurationDelay;\n    }\n\n    function state(uint256, uint256 _configured)\n        external\n        view\n        override\n        returns (BallotState)\n    {\n        return\n            // Fails halfway through\n            block.timestamp > _configured + (reconfigurationDelay / 2)\n                ? BallotState.Failed\n                : BallotState.Active;\n    }\n}\n"
    },
    "contracts/Active7DaysFundingCycleBallot.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITerminalV1.sol\";\nimport \"./interfaces/IFundingCycleBallot.sol\";\n\n/** \n   @notice Manages votes towards approving funding cycle reconfigurations.\n */\ncontract Active7DaysFundingCycleBallot is IFundingCycleBallot {\n    // --- public stored properties --- //\n\n    /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become active.\n    uint256 public constant reconfigurationDelay = 604800; // 7 days\n\n    // --- external views --- //\n\n    /** \n      @notice The time that this ballot is active for.\n      @dev A ballot should not be considered final until the duration has passed.\n      @return The durection in seconds.\n    */\n    function duration() external pure override returns (uint256) {\n        return reconfigurationDelay;\n    }\n\n    /**\n      @notice The approval state of a particular funding cycle.\n      @param _configured The configuration of the funding cycle to check the state of.\n      @return The state of the provided ballot.\n   */\n    function state(uint256, uint256 _configured)\n        external\n        view\n        override\n        returns (BallotState)\n    {\n        return\n            block.timestamp > _configured + reconfigurationDelay\n                ? BallotState.Approved\n                : BallotState.Active;\n    }\n}\n"
    },
    "contracts/Active3DaysFundingCycleBallot.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITerminalV1.sol\";\nimport \"./interfaces/IFundingCycleBallot.sol\";\n\n/** \n   @notice Manages votes towards approving funding cycle reconfigurations.\n */\ncontract Active3DaysFundingCycleBallot is IFundingCycleBallot {\n    // --- public stored properties --- //\n\n    /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become active.\n    uint256 public constant reconfigurationDelay = 259200; // 3 days\n\n    // --- external views --- //\n\n    /** \n      @notice The time that this ballot is active for.\n      @dev A ballot should not be considered final until the duration has passed.\n      @return The durection in seconds.\n    */\n    function duration() external pure override returns (uint256) {\n        return reconfigurationDelay;\n    }\n\n    /**\n      @notice The approval state of a particular funding cycle.\n      @param _configured The configuration of the funding cycle to check the state of.\n      @return The state of the provided ballot.\n   */\n    function state(uint256, uint256 _configured)\n        external\n        view\n        override\n        returns (BallotState)\n    {\n        return\n            block.timestamp > _configured + reconfigurationDelay\n                ? BallotState.Approved\n                : BallotState.Active;\n    }\n}\n"
    },
    "contracts/Active14DaysFundingCycleBallot.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/ITerminalV1.sol\";\nimport \"./interfaces/IFundingCycleBallot.sol\";\n\n/** \n   @notice Manages votes towards approving funding cycle reconfigurations.\n */\ncontract Active14DaysFundingCycleBallot is IFundingCycleBallot {\n    // --- public stored properties --- //\n\n    /// @notice The number of seconds that must pass for a funding cycle reconfiguration to become active.\n    uint256 public constant reconfigurationDelay = 1209600; // 14 days\n\n    // --- external views --- //\n\n    /** \n      @notice The time that this ballot is active for.\n      @dev A ballot should not be considered final until the duration has passed.\n      @return The durection in seconds.\n    */\n    function duration() external pure override returns (uint256) {\n        return reconfigurationDelay;\n    }\n\n    /**\n      @notice The approval state of a particular funding cycle.\n      @param _configured The configuration of the funding cycle to check the state of.\n      @return The state of the provided ballot.\n   */\n    function state(uint256, uint256 _configured)\n        external\n        view\n        override\n        returns (BallotState)\n    {\n        return\n            block.timestamp > _configured + reconfigurationDelay\n                ? BallotState.Approved\n                : BallotState.Active;\n    }\n}\n"
    },
    "contracts/ExampleYielder.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/IYielder.sol\";\n\n/// @dev For testing purposes.\ncontract ExampleYielder is IYielder {\n    function deposited() external pure override returns (uint256) {\n        return 0;\n    }\n\n    function getCurrentBalance() external pure override returns (uint256) {\n        return 0;\n    }\n\n    function deposit() external payable override {}\n\n    function withdraw(uint256 _amount, address payable _beneficiary)\n        external\n        override\n    {}\n\n    function withdrawAll(address payable _beneficiary)\n        external\n        override\n        returns (uint256)\n    {}\n}\n"
    },
    "contracts/ExampleETHUSDPriceFeed.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol\";\n\n// A static price feed contract to use locally.\ncontract ExampleETHUSDPriceFeed is AggregatorV3Interface {\n    function decimals() external pure override returns (uint8) {\n        return 18;\n    }\n\n    function description() external pure override returns (string memory) {\n        return \"Static ETH/USD price feed. Do not use in production.\";\n    }\n\n    function version() external pure override returns (uint256) {\n        return 0;\n    }\n\n    function getRoundData(uint80)\n        external\n        pure\n        override\n        returns (\n            uint80 roundId,\n            int256 answer,\n            uint256 startedAt,\n            uint256 updatedAt,\n            uint80 answeredInRound\n        )\n    {\n        return (0, 2000E18, 0, 0, 0);\n    }\n\n    function latestRoundData()\n        external\n        pure\n        override\n        returns (\n            uint80 roundId,\n            int256 answer,\n            uint256 startedAt,\n            uint256 updatedAt,\n            uint80 answeredInRound\n        )\n    {\n        return (0, 2000E18, 0, 0, 0);\n    }\n}\n"
    },
    "contracts/examples/Shwotime.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@paulrberg/contracts/math/PRBMath.sol\";\n\nimport \"../abstract/JuiceboxProject.sol\";\n\n/** \n  @dev \n  Shwotime allows friends to commit to buying tickets to events together.\n  They can commit to buying a ticket if a specified list of addresses also commit to buy the ticket.\n\n  Not reliable for situations where networks dont entirely overlap.\n*/\ncontract Shwotime is JuiceboxProject {\n    using SafeERC20 for IERC20;\n\n    struct Tix {\n        address owner;\n        uint256 max;\n        uint256 sold;\n        uint256 price;\n        uint256 expiry;\n        mapping(address => bool) committed;\n        mapping(address => bool) paid;\n        mapping(address => address[]) dependencies;\n    }\n\n    mapping(uint256 => Tix) public tickets;\n\n    uint256 public ticketsCount = 0;\n\n    IERC20 public dai;\n\n    uint256 public fee;\n\n    constructor(\n        uint256 _projectId,\n        ITerminalDirectory _terminalDirectory,\n        IERC20 _dai,\n        uint256 _fee\n    ) JuiceboxProject(_projectId, _terminalDirectory) {\n        dai = _dai;\n        fee = _fee;\n    }\n\n    // Create tickets to sell.\n    function createTickets(\n        uint256 _price,\n        uint256 _max,\n        uint256 _expiry\n    ) external {\n        //Store the new ticket.\n        ticketsCount++;\n        Tix storage _tickets = tickets[ticketsCount];\n        _tickets.price = _price;\n        _tickets.max = _max;\n        _tickets.sold = 0;\n        _tickets.expiry = _expiry;\n        _tickets.owner = msg.sender;\n    }\n\n    // commits to buying a ticket if the specified addresses also buy.\n    function buyTicket(uint256 id, address[] calldata addresses) external {\n        require(\n            id > 0 && id <= ticketsCount,\n            \"Shwotime::buyTickets: NOT_FOUND\"\n        );\n\n        //Mark the msg.sender as committed to buying.\n        Tix storage _tickets = tickets[id];\n\n        require(\n            _tickets.expiry > block.timestamp,\n            \"Shwotime::buyTickets: EXPIRED\"\n        );\n        require(\n            _tickets.max >= _tickets.sold,\n            \"Shwotime::buyTickets: SOLD_OUT\"\n        );\n\n        bool _transferFundsFromMsgSender = true;\n        for (uint256 _i = 0; _i < addresses.length; _i++) {\n            address _address = addresses[_i];\n            if (!_tickets.committed[_address])\n                _transferFundsFromMsgSender = false;\n            if (_tickets.paid[_address]) continue;\n            // Nest once.\n            bool _transferFundsFromDependency = true;\n            for (\n                uint256 _j = 0;\n                _j < _tickets.dependencies[_address].length;\n                _j++\n            ) {\n                address _subAddress = _tickets.dependencies[_address][_j];\n                if (\n                    _subAddress != msg.sender &&\n                    !_tickets.committed[_subAddress]\n                ) _transferFundsFromDependency = false;\n            }\n            if (_transferFundsFromDependency) {\n                // Transfer money from the committed buyer to this contract.\n                dai.safeTransferFrom(_address, address(this), _tickets.price);\n                _tickets.paid[_address] = true;\n                _tickets.sold++;\n            }\n        }\n        if (_transferFundsFromMsgSender) {\n            // Transfer money from the msg sender to this contract.\n            dai.safeTransferFrom(msg.sender, address(this), _tickets.price);\n            //save the fact that msg.sender owes\n            _tickets.paid[msg.sender] = true;\n            _tickets.sold++;\n        }\n\n        // Check to see if its sold out once everyone has been given tickets.\n        require(\n            _tickets.max >= _tickets.sold,\n            \"Shwotime::buyTickets: SOLD_OUT\"\n        );\n\n        _tickets.committed[msg.sender] = true;\n    }\n\n    //Allow a ticket owner to collect funds once the tickets expire.\n    function collect(uint256 _id, string calldata _memo) external {\n        require(_id > 0 && _id <= ticketsCount, \"Shwotime::collect: NOT_FOUND\");\n\n        Tix storage _tickets = tickets[_id];\n\n        require(\n            msg.sender == _tickets.owner,\n            \"Shwotime::collect: UNAUTHORIZED\"\n        );\n\n        require(\n            _tickets.expiry <= block.timestamp,\n            \"Shwotime::collect: TOO_SOON\"\n        );\n\n        uint256 _total = _tickets.price * _tickets.sold;\n        uint256 _collectable = PRBMath.mulDiv(_total, 200 - fee, 200);\n        dai.safeTransfer(msg.sender, _collectable);\n        //Take your fee into Juicebox.\n        _takeFee(_total - _collectable, msg.sender, _memo, false);\n    }\n}\n"
    },
    "contracts/ExampleModAllocator.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./interfaces/IModAllocator.sol\";\n\n// A static mod allocator contract to use locally.\ncontract ExampleModAllocator is IModAllocator {\n    function allocate(\n        uint256 _projectId,\n        uint256 _forProjectId,\n        address _beneficiary\n    ) external payable override {}\n}\n"
    },
    "contracts/examples/YourContract.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"../abstract/JuiceboxProject.sol\";\n\n/// @dev This contract is an example of how you can use Juicebox to fund your own project.\ncontract YourContract is JuiceboxProject {\n    constructor(uint256 _projectId, ITerminalDirectory _directory)\n        JuiceboxProject(_projectId, _directory)\n    {}\n}\n"
    },
    "contracts/ExampleJuiceboxProject.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.6;\n\nimport \"./abstract/JuiceboxProject.sol\";\n\n/// @dev For testing purposes.\ncontract ExampleJuiceboxProject is JuiceboxProject {\n    constructor(uint256 _projectId, ITerminalDirectory _terminalDirectory)\n        JuiceboxProject(_projectId, _terminalDirectory)\n    {}\n\n    function takeFee(\n        uint256 _amount,\n        address _beneficiary,\n        string calldata _memo,\n        bool _preferUnstakedTickets\n    ) external {\n        _takeFee(_amount, _beneficiary, _memo, _preferUnstakedTickets);\n    }\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 10000
    },
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates"
        ],
        "": [
          "ast"
        ]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}