{
  "language": "Solidity",
  "sources": {
    "contracts/universal/AssetReceiver.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n    /**\n     * Emitted when ETH is received by this address.\n     */\n    event ReceivedETH(address indexed from, uint256 amount);\n\n    /**\n     * Emitted when ETH is withdrawn from this address.\n     */\n    event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n    /**\n     * Emitted when ERC20 tokens are withdrawn from this address.\n     */\n    event WithdrewERC20(\n        address indexed withdrawer,\n        address indexed recipient,\n        address indexed asset,\n        uint256 amount\n    );\n\n    /**\n     * Emitted when ERC721 tokens are withdrawn from this address.\n     */\n    event WithdrewERC721(\n        address indexed withdrawer,\n        address indexed recipient,\n        address indexed asset,\n        uint256 id\n    );\n\n    /**\n     * @param _owner Initial contract owner.\n     */\n    constructor(address _owner) Transactor(_owner) {}\n\n    /**\n     * Make sure we can receive ETH.\n     */\n    receive() external payable {\n        emit ReceivedETH(msg.sender, msg.value);\n    }\n\n    /**\n     * Withdraws full ETH balance to the recipient.\n     *\n     * @param _to Address to receive the ETH balance.\n     */\n    function withdrawETH(address payable _to) external onlyOwner {\n        withdrawETH(_to, address(this).balance);\n    }\n\n    /**\n     * Withdraws partial ETH balance to the recipient.\n     *\n     * @param _to Address to receive the ETH balance.\n     * @param _amount Amount of ETH to withdraw.\n     */\n    function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n        // slither-disable-next-line reentrancy-unlimited-gas\n        _to.transfer(_amount);\n        emit WithdrewETH(msg.sender, _to, _amount);\n    }\n\n    /**\n     * Withdraws full ERC20 balance to the recipient.\n     *\n     * @param _asset ERC20 token to withdraw.\n     * @param _to Address to receive the ERC20 balance.\n     */\n    function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n        withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n    }\n\n    /**\n     * Withdraws partial ERC20 balance to the recipient.\n     *\n     * @param _asset ERC20 token to withdraw.\n     * @param _to Address to receive the ERC20 balance.\n     * @param _amount Amount of ERC20 to withdraw.\n     */\n    function withdrawERC20(\n        ERC20 _asset,\n        address _to,\n        uint256 _amount\n    ) public onlyOwner {\n        // slither-disable-next-line unchecked-transfer\n        _asset.transfer(_to, _amount);\n        // slither-disable-next-line reentrancy-events\n        emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n    }\n\n    /**\n     * Withdraws ERC721 token to the recipient.\n     *\n     * @param _asset ERC721 token to withdraw.\n     * @param _to Address to receive the ERC721 token.\n     * @param _id Token ID of the ERC721 token to withdraw.\n     */\n    function withdrawERC721(\n        ERC721 _asset,\n        address _to,\n        uint256 _id\n    ) external onlyOwner {\n        _asset.transferFrom(address(this), _to, _id);\n        // slither-disable-next-line reentrancy-events\n        emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n    }\n}\n"
    },
    "@rari-capital/solmate/src/tokens/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Transfer(address indexed from, address indexed to, uint256 amount);\n\n    event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n    /*//////////////////////////////////////////////////////////////\n                            METADATA STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    string public name;\n\n    string public symbol;\n\n    uint8 public immutable decimals;\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC20 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 public totalSupply;\n\n    mapping(address => uint256) public balanceOf;\n\n    mapping(address => mapping(address => uint256)) public allowance;\n\n    /*//////////////////////////////////////////////////////////////\n                            EIP-2612 STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal immutable INITIAL_CHAIN_ID;\n\n    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n    mapping(address => uint256) public nonces;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\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        INITIAL_CHAIN_ID = block.chainid;\n        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               ERC20 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function approve(address spender, uint256 amount) public virtual returns (bool) {\n        allowance[msg.sender][spender] = amount;\n\n        emit Approval(msg.sender, spender, amount);\n\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) public virtual returns (bool) {\n        balanceOf[msg.sender] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(msg.sender, to, amount);\n\n        return true;\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual returns (bool) {\n        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n        balanceOf[from] -= amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        return true;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                             EIP-2612 LOGIC\n    //////////////////////////////////////////////////////////////*/\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 {\n        require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n        // Unchecked because the only math done is incrementing\n        // the owner's nonce which cannot realistically overflow.\n        unchecked {\n            address recoveredAddress = ecrecover(\n                keccak256(\n                    abi.encodePacked(\n                        \"\\x19\\x01\",\n                        DOMAIN_SEPARATOR(),\n                        keccak256(\n                            abi.encode(\n                                keccak256(\n                                    \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n                                ),\n                                owner,\n                                spender,\n                                value,\n                                nonces[owner]++,\n                                deadline\n                            )\n                        )\n                    )\n                ),\n                v,\n                r,\n                s\n            );\n\n            require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n            allowance[recoveredAddress][spender] = value;\n        }\n\n        emit Approval(owner, spender, value);\n    }\n\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n    }\n\n    function computeDomainSeparator() internal view virtual returns (bytes32) {\n        return\n            keccak256(\n                abi.encode(\n                    keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n                    keccak256(bytes(name)),\n                    keccak256(\"1\"),\n                    block.chainid,\n                    address(this)\n                )\n            );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL MINT/BURN LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _mint(address to, uint256 amount) internal virtual {\n        totalSupply += amount;\n\n        // Cannot overflow because the sum of all user\n        // balances can't exceed the max uint256 value.\n        unchecked {\n            balanceOf[to] += amount;\n        }\n\n        emit Transfer(address(0), to, amount);\n    }\n\n    function _burn(address from, uint256 amount) internal virtual {\n        balanceOf[from] -= amount;\n\n        // Cannot underflow because a user's balance\n        // will never be larger than the total supply.\n        unchecked {\n            totalSupply -= amount;\n        }\n\n        emit Transfer(from, address(0), amount);\n    }\n}\n"
    },
    "@rari-capital/solmate/src/tokens/ERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n    event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /*//////////////////////////////////////////////////////////////\n                         METADATA STORAGE/LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    string public name;\n\n    string public symbol;\n\n    function tokenURI(uint256 id) public view virtual returns (string memory);\n\n    /*//////////////////////////////////////////////////////////////\n                      ERC721 BALANCE/OWNER STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    mapping(uint256 => address) internal _ownerOf;\n\n    mapping(address => uint256) internal _balanceOf;\n\n    function ownerOf(uint256 id) public view virtual returns (address owner) {\n        require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n    }\n\n    function balanceOf(address owner) public view virtual returns (uint256) {\n        require(owner != address(0), \"ZERO_ADDRESS\");\n\n        return _balanceOf[owner];\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                         ERC721 APPROVAL STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    mapping(uint256 => address) public getApproved;\n\n    mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(string memory _name, string memory _symbol) {\n        name = _name;\n        symbol = _symbol;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC721 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function approve(address spender, uint256 id) public virtual {\n        address owner = _ownerOf[id];\n\n        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n        getApproved[id] = spender;\n\n        emit Approval(owner, spender, id);\n    }\n\n    function setApprovalForAll(address operator, bool approved) public virtual {\n        isApprovedForAll[msg.sender][operator] = approved;\n\n        emit ApprovalForAll(msg.sender, operator, approved);\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 id\n    ) public virtual {\n        require(from == _ownerOf[id], \"WRONG_FROM\");\n\n        require(to != address(0), \"INVALID_RECIPIENT\");\n\n        require(\n            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n            \"NOT_AUTHORIZED\"\n        );\n\n        // Underflow of the sender's balance is impossible because we check for\n        // ownership above and the recipient's balance can't realistically overflow.\n        unchecked {\n            _balanceOf[from]--;\n\n            _balanceOf[to]++;\n        }\n\n        _ownerOf[id] = to;\n\n        delete getApproved[id];\n\n        emit Transfer(from, to, id);\n    }\n\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 id\n    ) public virtual {\n        transferFrom(from, to, id);\n\n        if (to.code.length != 0)\n            require(\n                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n                    ERC721TokenReceiver.onERC721Received.selector,\n                \"UNSAFE_RECIPIENT\"\n            );\n    }\n\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 id,\n        bytes calldata data\n    ) public virtual {\n        transferFrom(from, to, id);\n\n        if (to.code.length != 0)\n            require(\n                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n                    ERC721TokenReceiver.onERC721Received.selector,\n                \"UNSAFE_RECIPIENT\"\n            );\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                              ERC165 LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return\n            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL MINT/BURN LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _mint(address to, uint256 id) internal virtual {\n        require(to != address(0), \"INVALID_RECIPIENT\");\n\n        require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n        // Counter overflow is incredibly unrealistic.\n        unchecked {\n            _balanceOf[to]++;\n        }\n\n        _ownerOf[id] = to;\n\n        emit Transfer(address(0), to, id);\n    }\n\n    function _burn(uint256 id) internal virtual {\n        address owner = _ownerOf[id];\n\n        require(owner != address(0), \"NOT_MINTED\");\n\n        // Ownership check above ensures no underflow.\n        unchecked {\n            _balanceOf[owner]--;\n        }\n\n        delete _ownerOf[id];\n\n        delete getApproved[id];\n\n        emit Transfer(owner, address(0), id);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                        INTERNAL SAFE MINT LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function _safeMint(address to, uint256 id) internal virtual {\n        _mint(to, id);\n\n        if (to.code.length != 0)\n            require(\n                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n                    ERC721TokenReceiver.onERC721Received.selector,\n                \"UNSAFE_RECIPIENT\"\n            );\n    }\n\n    function _safeMint(\n        address to,\n        uint256 id,\n        bytes memory data\n    ) internal virtual {\n        _mint(to, id);\n\n        if (to.code.length != 0)\n            require(\n                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n                    ERC721TokenReceiver.onERC721Received.selector,\n                \"UNSAFE_RECIPIENT\"\n            );\n    }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n    function onERC721Received(\n        address,\n        address,\n        uint256,\n        bytes calldata\n    ) external virtual returns (bytes4) {\n        return ERC721TokenReceiver.onERC721Received.selector;\n    }\n}\n"
    },
    "contracts/universal/Transactor.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n    /**\n     * @param _owner Initial contract owner.\n     */\n    constructor(address _owner) Owned(_owner) {}\n\n    /**\n     * Sends a CALL to a target address.\n     *\n     * @param _target Address to call.\n     * @param _data Data to send with the call.\n     * @param _gas Amount of gas to send with the call.\n     * @param _value ETH value to send with the call.\n     * @return Boolean success value.\n     * @return Bytes data returned by the call.\n     */\n    function CALL(\n        address _target,\n        bytes memory _data,\n        uint256 _gas,\n        uint256 _value\n    ) external payable onlyOwner returns (bool, bytes memory) {\n        return _target.call{ gas: _gas, value: _value }(_data);\n    }\n\n    /**\n     * Sends a DELEGATECALL to a target address.\n     *\n     * @param _target Address to call.\n     * @param _data Data to send with the call.\n     * @param _gas Amount of gas to send with the call.\n     * @return Boolean success value.\n     * @return Bytes data returned by the call.\n     */\n    function DELEGATECALL(\n        address _target,\n        bytes memory _data,\n        uint256 _gas\n    ) external payable onlyOwner returns (bool, bytes memory) {\n        // slither-disable-next-line controlled-delegatecall\n        return _target.delegatecall{ gas: _gas }(_data);\n    }\n}\n"
    },
    "@rari-capital/solmate/src/auth/Owned.sol": {
      "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n    /*//////////////////////////////////////////////////////////////\n                                 EVENTS\n    //////////////////////////////////////////////////////////////*/\n\n    event OwnerUpdated(address indexed user, address indexed newOwner);\n\n    /*//////////////////////////////////////////////////////////////\n                            OWNERSHIP STORAGE\n    //////////////////////////////////////////////////////////////*/\n\n    address public owner;\n\n    modifier onlyOwner() virtual {\n        require(msg.sender == owner, \"UNAUTHORIZED\");\n\n        _;\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                               CONSTRUCTOR\n    //////////////////////////////////////////////////////////////*/\n\n    constructor(address _owner) {\n        owner = _owner;\n\n        emit OwnerUpdated(address(0), _owner);\n    }\n\n    /*//////////////////////////////////////////////////////////////\n                             OWNERSHIP LOGIC\n    //////////////////////////////////////////////////////////////*/\n\n    function setOwner(address newOwner) public virtual onlyOwner {\n        owner = newOwner;\n\n        emit OwnerUpdated(msg.sender, newOwner);\n    }\n}\n"
    },
    "contracts/universal/drippie/Drippie.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n    /**\n     * Enum representing different status options for a given drip.\n     */\n    enum DripStatus {\n        NONE,\n        ACTIVE,\n        PAUSED,\n        ARCHIVED\n    }\n\n    /**\n     * Represents a drip action.\n     */\n    struct DripAction {\n        address payable target;\n        bytes data;\n        uint256 value;\n    }\n\n    /**\n     * Represents the configuration for a given drip.\n     */\n    struct DripConfig {\n        uint256 interval;\n        IDripCheck dripcheck;\n        bytes checkparams;\n        DripAction[] actions;\n    }\n\n    /**\n     * Represents the state of an active drip.\n     */\n    struct DripState {\n        DripStatus status;\n        DripConfig config;\n        uint256 last;\n    }\n\n    /**\n     * Emitted when a new drip is created.\n     */\n    event DripCreated(string indexed name, DripConfig config);\n\n    /**\n     * Emitted when a drip status is updated.\n     */\n    event DripStatusUpdated(string indexed name, DripStatus status);\n\n    /**\n     * Emitted when a drip is executed.\n     */\n    event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n    /**\n     * Maps from drip names to drip states.\n     */\n    mapping(string => DripState) public drips;\n\n    /**\n     * @param _owner Initial contract owner.\n     */\n    constructor(address _owner) AssetReceiver(_owner) {}\n\n    /**\n     * Creates a new drip with the given name and configuration. Once created, drips cannot be\n     * modified in any way (this is a security measure). If you want to update a drip, simply pause\n     * (and potentially archive) the existing drip and create a new one.\n     *\n     * @param _name Name of the drip.\n     * @param _config Configuration for the drip.\n     */\n    function create(string memory _name, DripConfig memory _config) external onlyOwner {\n        // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n        // will ever set the status of a drip back to NONE after it's been created. This is why\n        // archival is a separate status.\n        require(\n            drips[_name].status == DripStatus.NONE,\n            \"Drippie: drip with that name already exists\"\n        );\n\n        // We initialize this way because Solidity won't let us copy arrays into storage yet.\n        DripState storage state = drips[_name];\n        state.status = DripStatus.PAUSED;\n        state.config.interval = _config.interval;\n        state.config.dripcheck = _config.dripcheck;\n        state.config.checkparams = _config.checkparams;\n\n        // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n        for (uint256 i = 0; i < _config.actions.length; i++) {\n            state.config.actions.push(_config.actions[i]);\n        }\n\n        // Tell the world!\n        emit DripCreated(_name, _config);\n    }\n\n    /**\n     * Sets the status for a given drip. The behavior of this function depends on the status that\n     * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n     * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n     *\n     * @param _name Name of the drip to update.\n     * @param _status New drip status.\n     */\n    function status(string memory _name, DripStatus _status) external onlyOwner {\n        // Make sure we can never set drip status back to NONE. A simple security measure to\n        // prevent accidental overwrites if this code is ever updated down the line.\n        require(\n            _status != DripStatus.NONE,\n            \"Drippie: drip status can never be set back to NONE after creation\"\n        );\n\n        // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n        // seem to be any clear reason why you would want to do this, and it may save some gas in\n        // the case of a front-end bug.\n        require(\n            drips[_name].status != DripStatus.NONE,\n            \"Drippie: drip with that name does not exist\"\n        );\n\n        // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n        // point of archiving a drip.\n        require(\n            drips[_name].status != DripStatus.ARCHIVED,\n            \"Drippie: drip with that name has been archived\"\n        );\n\n        // Although not strictly necessary, we make sure that the status here is actually changing.\n        // This may save the client some gas if there's a front-end bug and the user accidentally\n        // tries to \"change\" the status to the same value as before.\n        require(\n            drips[_name].status != _status,\n            \"Drippie: cannot set drip status to same status as before\"\n        );\n\n        // If the user is trying to archive this drip, make sure the drip has been paused. We do\n        // not allow users to archive active drips so that the effects of this action are more\n        // abundantly clear.\n        if (_status == DripStatus.ARCHIVED) {\n            require(\n                drips[_name].status == DripStatus.PAUSED,\n                \"Drippie: drip must be paused to be archived\"\n            );\n        }\n\n        // If we made it here then we can safely update the status.\n        drips[_name].status = _status;\n        emit DripStatusUpdated(_name, drips[_name].status);\n    }\n\n    /**\n     * Triggers a drip. This function is deliberately left as a public function because the\n     * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n     * the drip should be executable according to the drip parameters, drip check, and drip\n     * interval. Note that drip parameters are read entirely from the state and are not supplied as\n     * user input, so there should not be any way for a non-authorized user to influence the\n     * behavior of the drip.\n     *\n     * @param _name Name of the drip to trigger.\n     */\n    function drip(string memory _name) external {\n        DripState storage state = drips[_name];\n\n        // Only allow active drips to be executed, an obvious security measure.\n        require(\n            state.status == DripStatus.ACTIVE,\n            \"Drippie: selected drip does not exist or is not currently active\"\n        );\n\n        // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n        // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n        // their funds and repeatedly requesting new drips. Limits the potential impact of a\n        // compromised recipient to just a single drip interval, after which the drip can be paused\n        // by the owner address.\n        require(\n            state.last + state.config.interval <= block.timestamp,\n            \"Drippie: drip interval has not elapsed since last drip\"\n        );\n\n        // Make sure we're allowed to execute this drip.\n        require(\n            state.config.dripcheck.check(state.config.checkparams),\n            \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n        );\n\n        // Update the last execution time for this drip before the call. Note that it's entirely\n        // possible for a drip to be executed multiple times per block or even multiple times\n        // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n        // should set a drip interval of 1 if they'd like the drip to be executed only once per\n        // block (since this will then prevent re-entrancy).\n        state.last = block.timestamp;\n\n        // Execute each action in the drip. We allow drips to have multiple actions because there\n        // are scenarios in which a contract must do multiple things atomically. For example, the\n        // contract may need to withdraw ETH from one account and then deposit that ETH into\n        // another account within the same transaction.\n        uint256 len = state.config.actions.length;\n        for (uint256 i = 0; i < len; i++) {\n            // Must be marked as \"storage\" because copying structs into memory is not yet supported\n            // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n            // read what the rest of this section is doing.\n            DripAction storage action = state.config.actions[i];\n\n            // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n            // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n            // will ever happen in practice). Could save a marginal amount of gas to ignore the\n            // returndata.\n            // slither-disable-next-line calls-loop\n            (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n            // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n            // the wrong data to the target contract), the recipient is not payable, or\n            // insufficient gas was supplied to this transaction. We revert so the drip can be\n            // fixed and triggered again later. Means we cannot emit an event to alert of the\n            // failure, but can reasonably be detected by off-chain services even without an event.\n            // Note that this forces the drip executor to supply sufficient gas to the call\n            // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n            // not execute).\n            require(\n                success,\n                \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n            );\n        }\n\n        emit DripExecuted(_name, msg.sender, block.timestamp);\n    }\n}\n"
    },
    "contracts/universal/drippie/IDripCheck.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n    // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n    // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n    // possible to easily encode parameters on the client side. Solidity does not support generics\n    // so it's not possible to do this with explicit typing.\n\n    function check(bytes memory _params) external view returns (bool);\n}\n"
    },
    "contracts/universal/drippie/dripchecks/CheckTrue.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n    function check(bytes memory) external pure returns (bool) {\n        return true;\n    }\n}\n"
    },
    "contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n    function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n    event _EventToExposeStructInABI__Params(Params params);\n    struct Params {\n        address treasury;\n        uint256 threshold;\n        address recipient;\n    }\n\n    function check(bytes memory _params) external view returns (bool) {\n        Params memory params = abi.decode(_params, (Params));\n\n        // Check GelatoTreasury ETH balance is below threshold.\n        return\n            IGelatoTreasury(params.treasury).userTokenBalance(\n                params.recipient,\n                // Gelato represents ETH as 0xeeeee....eeeee\n                0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n            ) < params.threshold;\n    }\n}\n"
    },
    "contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n    event _EventToExposeStructInABI__Params(Params params);\n    struct Params {\n        address target;\n        uint256 threshold;\n    }\n\n    function check(bytes memory _params) external view returns (bool) {\n        Params memory params = abi.decode(_params, (Params));\n\n        // Check target ETH balance is below threshold.\n        return params.target.balance < params.threshold;\n    }\n}\n"
    },
    "contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n    event _EventToExposeStructInABI__Params(Params params);\n    struct Params {\n        address target;\n        uint256 threshold;\n    }\n\n    function check(bytes memory _params) external view returns (bool) {\n        Params memory params = abi.decode(_params, (Params));\n\n        // Check target balance is above threshold.\n        return params.target.balance > params.threshold;\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
    }
  }
}