contract QueryScript {
    using SafeMath for uint256;

    constructor() public {}

    // assumes a Uniswap XYZ_ETH pair, where XYZ is reserve0
    function getData(
        StakingRewards _rewards,
        IUniswap _pricePair,
        address _staker
    )
        public
        view
        returns (
            uint _availableBalance,
            uint _stakedBalance,
            uint _allowedBalance,
            uint _earned,
            uint _totalStakedValue,
            uint _APY,
            uint _rewardRate,
            uint _timestamp // rewards per second
        )
    {
        _availableBalance = _rewards.stakingToken().balanceOf(_staker);
        _stakedBalance = _rewards.balanceOf(_staker);
        _allowedBalance = _rewards
            .stakingToken()
            .allowance(_staker,address(_rewards));
        _earned = _rewards.earned(_staker);
        _rewardRate = _rewards.rewardRate();
        _timestamp = now;
            
        _totalStakedValue = getStakedValue(_rewards, _pricePair);

        _APY = _totalStakedValue == 0 ? 
            0 :
            _rewardRate
                .mul(365 days)
                .mul(10**18)
                .div(_totalStakedValue); /* */

        _rewardRate = _rewards.totalSupply() == 0 ?
            0 :
            _rewardRate
                .mul(_stakedBalance)
                .div(_rewards.totalSupply());
    }
    
    function getStakedValue(StakingRewards _rewards, IUniswap _pricePair)
        public
        view
        returns (uint _totalStakedValue)
    {
        IUniswap stakingToken = IUniswap(address(_rewards.stakingToken()));
        
        uint fryPrice = getTokenPairPrice(_pricePair)
            .mul(10**18)
            .div(getTokenPairPrice(stakingToken));
            
        _totalStakedValue = fryPrice
            .mul(getBiggerReserve(stakingToken))
            .mul(10**18) // add precision before dividing
            .div(_rewards.stakingToken().totalSupply())
            .mul(_rewards.totalSupply())
            .div(10**18) // remove precision after dividing
            .div(10**18) // remove prevision from fryPrive 
            .mul(2); // mul by two to get the value of both sides of the pair
    }
    
    function getBiggerReserve(IUniswap _tokenPair)
        public
        view
        returns (uint _reserve)
    {
        (uint reserve0, uint reserve1, ) = _tokenPair.getReserves();
        _reserve = Math.max(reserve0, reserve1);
    }

    function getTokenPairPrice(IUniswap _tokenPair)
        public
        view
        returns (uint _price)
    {
        (uint reserve0, uint reserve1, ) = _tokenPair.getReserves();
        _price = reserve0 > reserve1 ?
            reserve0.mul(10**18).div(reserve1) :
            reserve1.mul(10**18).div(reserve0);
    }
}
function getData(
    StakingRewards _rewards,
    IUniswap _pricePair,
    address _staker
)
    public
    view
    returns (
        uint _availableBalance,
        uint _stakedBalance,
        uint _allowedBalance,
        uint _earned,
        uint _totalStakedValue,
        uint _APY,
        uint _rewardRate,
        uint _timestamp // rewards per second
    )
{
    _availableBalance = _rewards.stakingToken().balanceOf(_staker);
    _stakedBalance = _rewards.balanceOf(_staker);
    _allowedBalance = _rewards
        .stakingToken()
        .allowance(_staker,address(_rewards));
    _earned = _rewards.earned(_staker);
    _rewardRate = _rewards.rewardRate();
    _timestamp = now;
            
    _totalStakedValue = getStakedValue(_rewards, _pricePair);

    _APY = _totalStakedValue == 0 ? 
        0 :
        _rewardRate
            .mul(365 days)
            .mul(10**18)
            .div(_totalStakedValue); /* */

    _rewardRate = _rewards.totalSupply() == 0 ?
        0 :
        _rewardRate
            .mul(_stakedBalance)
            .div(_rewards.totalSupply());
}

// assumes a Uniswap XYZ_ETH pair, where XYZ is reserve0