// Contract: QUAI_Staking
// Target function: function deposit(uint256 amountTokens) external
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.7.5;

//MATH OPERATIONS -- designed to avoid possibility of errors with built-in math functions
library SafeMath {
    //@dev Multiplies two numbers, throws on overflow.
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        assert(c / a == b);
        return c;
    }
    //@dev Integer division of two numbers, truncating the quotient (i.e. rounds down).
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); Solidity automatically throws when dividing by 0
        uint256 c = a / b;
        return c;
    }
    //@dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        uint256 c = a - b;
        return c;
    }
    //@dev Adds two numbers, throws on overflow.
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        assert(c >= a);
        return c;
    }
//end library
}

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

abstract contract Ownable {
    address internal _owner;
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    constructor () {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }
    function owner() public view returns (address) {
        return _owner;
    }
    modifier onlyOwner() {
        require(_owner == msg.sender, "Ownable: caller is not the owner");
        _;
    }
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

contract QUAI_Staking is Ownable {
	using SafeMath for uint256;

	address public constant quaiToken = 0x40821CD074dfeCb1524286923bC69315075b5c89; //token to stake

	//STAKING PARAMETERS
	uint256 public constant stakingPeriod = 30 days; //period over which tokens are locked after staking
	uint256 public stakingEnd; //point after which staking rewards cease to accumulate
	uint256 public rewardRate = 14; //14% linear return per staking period
	uint256 public totalStaked; //sum of all user stakes
	uint256 public maxTotalStaked = 58e23; //5.8 million tokens
	uint256 public minStaked = 1e21; //1000 tokens. min staked per user

	//STAKING MAPPINGS
	mapping (address => uint256) public stakedTokens; //amount of tokens that address has staked
	mapping (address => uint256) public lastStaked; //last time at which address staked, deposited, or "rolled over" their position by calling updateStake directly
	mapping (address => uint256) public totalEarnedTokens; //total tokens earned through staking by each user
	
	constructor(){
		stakingEnd = (block.timestamp + 180 days);
	}