contract RebaseOracle is Ownable {
    using SafeMath for uint256;
    
    IUniswapV2Pair public pool = IUniswapV2Pair(0x6c35c40447E8011a63aB05f088fa7cD914d66904); // Address of the IUniswapV2Pair for Weth / Token
    
    IRebaseableERC20 public token = IRebaseableERC20(0xf911a7ec46a2c6fa49193212fe4a2a9B95851c27);
    uint256 public tokenDecimals = 9;
    
    IExchangeRates rates = IExchangeRates(0x3eAfb425e22beCFAB10754Ef8BDE68B2AB640384);
    
    uint256 public lastRebase;
    uint256 public timeBetweenRebases = 1 minutes;
    uint256 public lastExchangeRate = 0;
    
    bool public guarded = true;
    
    event RebaseSuccess(uint256 oldPrice, uint256 newPrice, uint256 delta);
    event RebaseFail(uint256 oldPrice, uint256 newPrice);
    
    constructor() public {
        lastRebase = now;
        lastExchangeRate = currentExchangeRate();
    }
    
    // Enforces only owner if the guarded 
    modifier onlyOwnerIfGuarded {
        canOperateRebase(msg.sender);
        _;
    }
    
    // Public function to return if address can operate rebase or not
    function canOperateRebase(address _a) public view returns(bool) {
        return ((guarded == false) || (_a == _owner));
    }
    
    // Size of next rebase
    function nextSupplyDelta() public view returns(uint256) {
        uint256 currentSupply = token.totalSupply();
        if (currentSupply < 100) {
            return 0;
        }
        return currentSupply.div(100);
    }
    
    // Public shouldRebase
    function shouldRebase(uint256 exchangeRate) public view returns(bool) {
        if (exchangeRate < lastExchangeRate) {
            return true;
        }
        return false;
    }
    
    // Public exchange rate variable
    function currentExchangeRate() public view returns(uint256) {
        return rates.calculateUsdForToken({
            token: address(token),
            pool: address(pool),
            tokenDecimals: tokenDecimals,
            precision: 4
        });
    }
    
    // Fully open rebasing
    function rebase() public onlyOwnerIfGuarded {
        require(now > lastRebase.add(timeBetweenRebases));
        
        uint256 exchangeRate = currentExchangeRate();
        
        if (shouldRebase(exchangeRate)) {
            uint256 supplyDelta = nextSupplyDelta();
            token.rebase(0, supplyDelta);
            pool.sync();
            emit RebaseSuccess(lastExchangeRate, exchangeRate, supplyDelta);
        }
        else {
            emit RebaseFail(lastExchangeRate, exchangeRate);
        }
        
        lastRebase = now;
        lastExchangeRate = exchangeRate;
    }
    
    // Only owner operated manual rebasing
    function _rebase() public onlyOwner {
        uint256 exchangeRate = currentExchangeRate();
        
        uint256 supplyDelta = nextSupplyDelta();
        token.rebase(0, supplyDelta);
        pool.sync();
        emit RebaseSuccess(lastExchangeRate, exchangeRate, supplyDelta);
        
        lastRebase = now;
        lastExchangeRate = exchangeRate;
    }
    
    // Allows anyone to call the rebase function
    function unguard() public onlyOwner {
        guarded = false;
    }
    
    // Change token to test rebase
    function changeToken(address _token) public onlyOwner {
        token = IRebaseableERC20(_token);
    }
    
    // Change pool to test
    function changePool(address _pool) public onlyOwner {
        pool = IUniswapV2Pair(_pool);
    }
    
    // Modifies the period between rebases
    function changePeriod(uint256 _t) public onlyOwner {
        timeBetweenRebases = _t;
    }
    
    // Transfers the rebase token to a new owner
    function transferTokenOwnership(address newOwner) public onlyOwner {
        token.transferOwnership(newOwner);
    }
    
    // Syncs the exchange rate and rebase to the current transaction state
    function refresh() public onlyOwner {
        lastExchangeRate = currentExchangeRate();
        lastRebase = now;
    }
}
function refresh() public onlyOwner {
    lastExchangeRate = currentExchangeRate();
    lastRebase = now;
}

// Syncs the exchange rate and rebase to the current transaction state