// 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;
}
// File: /Users/akshaycm/Documents/relay3r.network/contracts/interfaces/Sushiswap/ISushiswapV2Factory.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

interface ISushiswapV2Factory {
    function allPairsLength() external view returns (uint);
    function allPairs(uint) external view returns (address pair);
}

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



// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface ISushiswapV2Maker {
    function convert(address token0, address token1) external;
}
// File: /Users/akshaycm/Documents/relay3r.network/contracts/interfaces/Sushiswap/ISushiswapV2Pair.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
interface ISushiswapV2Pair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function balanceOf(address account) external view returns (uint);
}
// File: /Users/akshaycm/Documents/relay3r.network/contracts/jobs/SushiswapV2Keep3r.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

import '../interfaces/Keep3r/IKeep3rV1Mini.sol';
import '../interfaces/Sushiswap/ISushiswapV2Factory.sol';
import '../interfaces/Sushiswap/ISushiswapV2Maker.sol';
import '../interfaces/Sushiswap/ISushiswapV2Pair.sol';

contract SushiswapV2Keep3r {

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

    IKeep3rV1Mini public KP3R;
    ISushiswapV2Factory public constant SV2F = ISushiswapV2Factory(0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac);
    ISushiswapV2Maker public constant SV2M = ISushiswapV2Maker(0x6684977bBED67e101BB80Fc07fCcfba655c0a64F);

    constructor(address keepertoken) public {
        KP3R = IKeep3rV1Mini(keepertoken);
    }

    function count() public view returns (uint) {
        uint _count = 0;
        for (uint i = 0; i < SV2F.allPairsLength(); i++) {
            if (haveBalance(SV2F.allPairs(i))) {
                _count++;
            }
        }
        return _count;
    }

    function workable() public view returns (bool) {
        return count() > 0;
    }

    function workableAll(uint _count) external view returns (address[] memory) {
        return (workable(_count, 0, SV2F.allPairsLength()));
    }

    function workable(uint _count, uint start, uint end) public view returns (address[] memory) {
        address[] memory _workable = new address[](_count);
        uint index = 0;
        for (uint i = start; i < end; i++) {
            if (haveBalance(SV2F.allPairs(i))) {
                _workable[index] = SV2F.allPairs(i);
                index++;
            }
        }
        return _workable;
    }

    function haveBalance(address pair) public view returns (bool) {
        return ISushiswapV2Pair(pair).balanceOf(address(SV2M)) > 0;
    }

    function batch(ISushiswapV2Pair[] calldata pair) external {
        bool _worked = true;
        for (uint i = 0; i < pair.length; i++) {
            if (haveBalance(address(pair[i]))) {
                (bool success, bytes memory message) = address(SV2M).delegatecall(abi.encodeWithSignature("convert(address,address)", pair[i].token0(), pair[i].token1()));
                require(success, string(abi.encodePacked("SushiswapV2Keep3r::convert: failed [", message, "]")));
            } else {
                _worked = false;
            }
        }
        require(_worked, "SushiswapV2Keep3r::batch: job(s) failed");
    }

    function work() external upkeep{
        require(workable(),"No pairs to convert");
        // iterate and add convert all pairs with balance
        for (uint i = 0; i < SV2F.allPairsLength(); i++) {
            if (haveBalance(SV2F.allPairs(i))) {
                //Do work
                (bool success, bytes memory message) = address(SV2M).delegatecall(abi.encodeWithSignature("convert(address,address)", ISushiswapV2Pair(SV2F.allPairs(i)).token0(), ISushiswapV2Pair(SV2F.allPairs(i)).token1()));
                require(success,  string(abi.encodePacked("SushiswapV2Keep3r::convert: failed [", message, "]")));
            }
        }
    }
}