// File: contracts/RebaseHelper.sol



// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;

import "./OperatorManager.sol";

interface IUFragmentsPolicy {
    function rebase() external;
}

interface IUniswapV2Pair {
    function sync() external;
}

/**
 * @title RebaseHelper
 *
 * @notice Rebase helper will run policy.rebase and sync all pools in one tx
 */
contract RebaseHelper is OperatorManager {
    IUFragmentsPolicy public policy;

    IUniswapV2Pair[] public pairs;

    uint256 public lastRebaseCalledTimestamp;

    function getPairs() external view returns (IUniswapV2Pair[] memory) {
        return pairs;
    }

    function setPolicy(IUFragmentsPolicy _policy) external onlyOwner {
        policy = _policy;
    }

    function setPairs(IUniswapV2Pair[] calldata _pairs) external onlyOwner {
        for (uint256 index = 0; index < pairs.length; index += 1) {
            pairs.pop();
        }

        for (uint256 index = 0; index < _pairs.length; index += 1) {
            pairs.push(_pairs[index]);
        }
    }

    function rebase() external onlyOperator {
        policy.rebase();
        for (uint256 index = 0; index < pairs.length; index++) {
            pairs[index].sync();
        }
        lastRebaseCalledTimestamp = block.timestamp;
    }
}

// File: contracts/OperatorManager.sol



// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;

import "./_external/Ownable.sol";

contract OperatorManager is Ownable {
    mapping(address => bool) private operators;

    modifier onlyOperator() {
        require(operators[msg.sender], "Only operators can execute this function.");
        _;
    }

    constructor() {
        initialize(msg.sender);
    }

    function setOperators(address[] calldata _operators, bool _isOperator) external onlyOwner {
        for (uint256 index = 0; index < _operators.length; index++) {
            operators[_operators[index]] = _isOperator;
        }
    }

    function addOperator(address _operator) external onlyOwner {
        operators[_operator] = true;
    }

    function removeOperator(address _operator) external onlyOwner {
        operators[_operator] = false;
    }

    function isOperator(address _operator) external view returns (bool) {
        return operators[_operator];
    }
}

// File: contracts/_external/Ownable.sol



pragma solidity 0.8.4;

import "./Initializable.sol";

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable is Initializable {
    address private _owner;

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

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    function initialize(address sender) public virtual initializer {
        _owner = sender;
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner());
        _;
    }

    /**
     * @return true if `msg.sender` is the owner of the contract.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    /**
     * @dev Allows the current owner to relinquish control of the contract.
     * @notice Renouncing to ownership will leave the contract without an owner.
     * It will not be possible to call the functions with the `onlyOwner`
     * modifier anymore.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipRenounced(_owner);
        _owner = address(0);
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }

    uint256[50] private ______gap;
}

// File: contracts/_external/Initializable.sol



pragma solidity 0.8.4;

/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private initializing;

    /**
     * @dev Modifier to use in the initializer function of a contract.
     */
    modifier initializer() {
        require(
            initializing || isConstructor() || !initialized,
            "Contract instance has already been initialized"
        );

        bool wasInitializing = initializing;
        initializing = true;
        initialized = true;

        _;

        initializing = wasInitializing;
    }

    /// @dev Returns true if and only if the function is running in the constructor
    function isConstructor() private view returns (bool) {
        // extcodesize checks the size of the code stored in an address, and
        // address returns the current address. Since the code is still not
        // deployed when running a constructor, any checks on its code size will
        // yield zero, making it an effective way to detect if a contract is
        // under construction or not.

        // MINOR CHANGE HERE:

        // previous code
        // uint256 cs;
        // assembly { cs := extcodesize(address) }
        // return cs == 0;

        // current code
        address _self = address(this);
        uint256 cs;
        assembly {
            cs := extcodesize(_self)
        }
        return cs == 0;
    }

    // Reserved storage space to allow for layout changes in the future.
    uint256[50] private ______gap;
}