// File: /Users/akshaycm/Documents/relay3r.network/contracts/interfaces/IGetBackETHHelperV2.sol



// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;
interface IGetBackETHHelperV2 {
  function BASE (  ) external view returns ( uint256 );
  function FEE (  ) external view returns ( uint256 );
  function FeeDiscountRatio (  ) external view returns ( uint256 );
  function FeeDiscountToken (  ) external view returns ( address );
  function FeeTokenBalanceNeeded (  ) external view returns ( uint256 );
  function IsEligibleForFeeDiscount ( address user ) external view returns ( bool );
  function QueueDelay (  ) external view returns ( uint256 );
  function UniRouter (  ) external view returns ( address );
  function Unifactory (  ) external view returns ( address );
  function WETH (  ) external view returns ( address );
  function addWhitelisted ( address addx ) external;
  function addr (  ) external view returns ( address );
  function addrSwapStats ( address ) external view returns ( uint256 );
  function checkPerm ( address sender, uint256 timex, address token ) external view returns ( bool );
  function clearQueueFromOwner (  ) external;
  function feeGetter (  ) external view returns ( address );
  function getSendAfterFee ( uint256 amount, address user, uint256 fee ) external view returns ( uint256 amt );
  function getTimeLeftToTimeout (  ) external view returns ( uint256 );
  function getTokens (  ) external view returns ( address[] memory);
  function getUsers (  ) external view returns ( address[] memory);
  function getWETHBalance (  ) external view returns ( uint256 );
  function isAwaitingSwap (  ) external view returns ( bool );
  function isQueueEmpty (  ) external view returns ( bool );
  function owner (  ) external view returns ( address );
  function queue ( address tokentoQueue ) external;
  function recoverTokens ( address token ) external;
  function renounceOwnership (  ) external;
  function revokeWhitelisted ( address addx ) external;
  function setFeeDiscountRatio ( uint256 ratio ) external;
  function setFeeDiscountToken ( address token ) external;
  function setFeeGetter ( address newFeeGetter ) external;
  function setQueueDelay ( uint256 newDelay ) external;
  function setServicefee ( uint256 fee ) external;
  function setTokensForFeeDiscount ( uint256 tokenAmt ) external;
  function shouldClearQueue (  ) external view returns ( bool );
  function swapQueuedToken (  ) external returns ( uint256[] memory amounts );
  function swapToETH ( address tokenx ) external returns ( uint256[] memory  amounts );
  function time (  ) external view returns ( uint256 );
  function tokenHasBurn ( address ) external view returns ( bool );
  function tokenQueued (  ) external view returns ( address );
  function tokenSwappedSuccess ( address ) external view returns ( bool );
  function tokenTried ( address ) external view returns ( bool );
  function totalETHFees (  ) external view returns ( uint256 );
  function totalETHSwapped (  ) external view returns ( uint256 );
  function totalTries (  ) external view returns ( uint256 );
  function transferOwnership ( address newOwner ) external;
  function whitelistedExecutors ( address ) external view returns ( bool );
}

// File: /Users/akshaycm/Documents/relay3r.network/contracts/interfaces/Keep3r/IKeep3rV1Mini.sol



//SPDX-License-Identifier: MIT

pragma solidity ^0.6.12;
interface IKeep3rV1Mini {
    function isKeeper(address) external returns (bool);
    function worked(address keeper) external;
    function totalBonded() external view returns (uint);
    function bonds(address keeper, address credit) external view returns (uint);
    function votes(address keeper) external view returns (uint);
    function isMinKeeper(address keeper, uint minBond, uint earned, uint age) external returns (bool);
    function addCreditETH(address job) external payable;
    function workedETH(address keeper) external;
    function credits(address job, address credit) external view returns (uint);
    function receipt(address credit, address keeper, uint amount) external;
    function ETH() external view returns (address);
    function receiptETH(address keeper, uint amount) external;
}
// File: /Users/akshaycm/Documents/relay3r.network/contracts/jobs/GBETHRelayer.sol



// SPDX-License-Identifier: MIT
pragma solidity >=0.6.12;
import '@openzeppelin/contracts/access/Ownable.sol';
//Import job interfaces and helper interfaces
import '../interfaces/IGetBackETHHelperV2.sol';
import '../interfaces/Keep3r/IKeep3rV1Mini.sol';


contract GetBackETHRelayer is Ownable {
    IKeep3rV1Mini public RLR;
    IGetBackETHHelperV2 public iGBETH;

    modifier upkeep() {
        require(RLR.isKeeper(msg.sender), "::isKeeper: relayer is not registered");
        _;
        RLR.worked(msg.sender);
    }

    //Init interfaces with addresses
    constructor (address token,address gbethelper) public {
        RLR = IKeep3rV1Mini(token);
        iGBETH = IGetBackETHHelperV2(gbethelper);
    }

    //Use this to depricate this job to move rlr to another job later
    function destructJob() public onlyOwner {
     //Get the credits for this job first
     uint256 currRLRCreds = RLR.credits(address(this),address(RLR));
     uint256 currETHCreds = RLR.credits(address(this),RLR.ETH());
     //Send out RLR Credits if any
     if(currRLRCreds > 0) {
        //Invoke receipt to send all the credits of job to owner
        RLR.receipt(address(RLR),owner(),currRLRCreds);
     }
     //Send out ETH credits if any
     if (currETHCreds > 0) {
        RLR.receiptETH(owner(),currETHCreds);
     }
     //Finally self destruct the contract after sending the credits
     selfdestruct(payable(owner()));
    }

    function workableQueue() public view returns (bool) {
        return iGBETH.shouldClearQueue();
    }

    function workableSwap() public view returns (bool) {
        return iGBETH.isAwaitingSwap();
    }

    function clearQueue() public upkeep {
        require(workableQueue(),"!workable");
        iGBETH.clearQueueFromOwner();
    }

    function executeSwap() public upkeep {
        require(workableSwap(),"!workable");
        iGBETH.swapQueuedToken();
    }

}
// File: @openzeppelin/contracts/GSN/Context.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}