// Vulnerability label: DC1
{"AbstractSweeper.sol":{"content":"//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"./Controller.sol\";\nimport \"./Token.sol\";\n\nabstract contract AbstractSweeper {\n  Controller internal controller;\n\n  constructor(Controller _controller) {\n    controller = _controller;\n  }\n\n  modifier canSweep() {\n    require(\n      msg.sender == controller.authorizedCaller()\n      || msg.sender == controller.owner()\n      || msg.sender == controller.dev(),\n      \"not authorized\"\n    );\n    require(controller.halted() == false, \"controller is halted\");\n    _;\n  }\n\n  function sweep(address token, uint amount) public virtual returns (bool);\n\n  fallback () payable external { revert(); }\n  receive () payable external { revert(); }\n}\n\ncontract DefaultSweeper is AbstractSweeper {\n  constructor(Controller _controller) AbstractSweeper(_controller) {}\n\n  function sweep(address _token, uint _amount) override public canSweep returns (bool) {\n    bool success = false;\n    address payable destination = controller.destination();\n\n    if (_token != address(0)) {\n      Token token = Token(_token);\n      uint amount = _amount;\n      if (amount \u003e token.balanceOf(address(this))) {\n          return false;\n      }\n      success = token.transfer(destination, amount);\n    }\n    else {\n      uint amountInWei = _amount;\n      if (amountInWei \u003e address(this).balance) {\n          return false;\n      }\n\n      success = destination.send(amountInWei);\n    }\n\n    if (success) {\n      controller.logSweep(this, destination, _token, _amount);\n    }\n    return success;\n  }\n}"},"AbstractSweeperList.sol":{"content":"//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"./AbstractSweeper.sol\";\n\nabstract contract AbstractSweeperList {\n  function sweeperOf(address _token) public virtual returns (address);\n}"},"Controller.sol":{"content":"//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"./AbstractSweeper.sol\";\nimport \"./AbstractSweeperList.sol\";\nimport \"./UserWallet.sol\";\n\ncontract Controller is AbstractSweeperList {\n  address public owner;\n  address public authorizedCaller;\n  address public dev;\n  address payable public destination;\n\n  bool public halted;\n\n  address public defaultSweeper = address(new DefaultSweeper(this));\n  mapping (address =\u003e address) sweepers;\n\n  event LogNewWallet(address receiver);\n  event LogSweep(address indexed from, address indexed to, address indexed token, uint amount);\n  \n  modifier onlyOwner() {\n    require(msg.sender == owner, \"not owner\");\n    _;\n  }\n\n  modifier onlyAdmins() {\n    require(msg.sender == authorizedCaller || msg.sender == owner || msg.sender == dev, \"not admin\");\n    _;\n  }\n\n  constructor() {\n    owner = msg.sender;\n    destination = payable(msg.sender);\n    authorizedCaller = msg.sender;\n    dev = msg.sender;\n  }\n\n  function changeAuthorizedCaller(address _newCaller) public onlyOwner {\n    authorizedCaller = _newCaller;\n  }\n\n  function changeDestination(address payable _dest) public onlyOwner {\n    destination = _dest;\n  }\n\n  function changeOwner(address _owner) public onlyOwner {\n    owner = _owner;\n  }\n\n  function changeDev(address _dev) public onlyOwner {\n    dev = _dev;\n  }\n\n  function makeWallet() public onlyAdmins returns (address wallet)  {\n    wallet = address(new UserWallet(this));\n    emit LogNewWallet(wallet);\n  }\n\n  function halt() public onlyAdmins {\n    halted = true;\n  }\n\n  function start() public onlyOwner {\n    halted = false;\n  }\n\n  function addSweeper(address _token, address _sweeper) public onlyOwner {\n    sweepers[_token] = _sweeper;\n  }\n\n  function sweeperOf(address _token) override public view returns (address) {\n    address sweeper = sweepers[_token];\n    if (sweeper == address(0)) sweeper = defaultSweeper;\n    return sweeper;\n  }\n\n  function logSweep(AbstractSweeper from, address to, address token, uint amount) public {\n    emit LogSweep(address(from), to, token, amount);\n  }\n}"},"Token.sol":{"content":"//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nabstract contract Token {\n  function balanceOf(address) public virtual returns (uint);\n  function transfer(address, uint) public virtual returns (bool);\n}"},"UserWallet.sol":{"content":"//SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.0;\n\nimport \"./AbstractSweeperList.sol\";\n\ncontract UserWallet {\n  AbstractSweeperList sweeperList;\n  constructor(AbstractSweeperList _sweeperlist) {\n    sweeperList = _sweeperlist;\n  }\n\n  fallback () payable external { }\n  receive () payable external { }\n\n  function tokenFallback(address _from, uint _value, bytes memory _data) public pure {}\n\n  function sweep(address _token, uint) public returns (bool) {\n    (bool success, ) = sweeperList.sweeperOf(_token).delegatecall(msg.data);\n    return success;\n  }\n}"}}