// File: /Users/mrbitkoin/Projects/LindaCEOJonah/Repositories/Sparkle-Developers/XETH/xeth-v2-token/contracts/ChainlinkAggregatorV3Interface.sol



// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.12;

interface AggregatorV3Interface
{

  function decimals() external view returns (uint8);
  function description() external view returns (string memory);
  function version() external view returns (uint256);

  // getRoundData and latestRoundData should both raise "No data present"
  // if they do not have data to report, instead of returning unset values
  // which could be misinterpreted as actual reported values.
  function getRoundData(uint80 _roundId)
  external
  view
  returns (
    uint80 roundId,
    int256 answer,
    uint256 startedAt,
    uint256 updatedAt,
    uint80 answeredInRound
  );

  function latestRoundData()
  external
  view
  returns (
    uint80 roundId,
    int256 answer,
    uint256 startedAt,
    uint256 updatedAt,
    uint80 answeredInRound
  );

}

// File: /Users/mrbitkoin/Projects/LindaCEOJonah/Repositories/Sparkle-Developers/XETH/xeth-v2-token/contracts/XplosiveEthereum.sol



// SPDX-License-Identifier: UNLICENSED
/**
 *
 * ██╗  ██╗███████╗████████╗██╗  ██╗
 * ╚██╗██╔╝██╔════╝╚══██╔══╝██║  ██║
 *  ╚███╔╝ █████╗     ██║   ███████║
 *  ██╔██╗ ██╔══╝     ██║   ██╔══██║
 * ██╔╝ ██╗███████╗   ██║   ██║  ██║
 * ╚═╝  ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝
 *
 *    An Ethereum pegged
 * base-down, burn-up currency.
 *
 *  https://xEth.finance
 *
 *
**/


/// SWC-103:  Floating Pragma
pragma solidity 0.6.12;

import "./XplosiveSafeMath.sol";
import "@openzeppelin/contracts/utils/SafeCast.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import '@openzeppelin/contracts/utils/Pausable.sol';
import './XplosiveRebaser.sol';
import "./ChainlinkAggregatorV3Interface.sol";

contract XplosiveEthereum is Ownable, Pausable, Rebasable
{
    using XplosiveSafeMath for uint256;
    using SafeCast for int256;
    using SafeCast for uint8;

    event Transfer(address indexed from, address indexed to, uint amount);
    event Approval(address indexed owner, address indexed spender, uint amount);

    event Rebase(uint256 indexed epoch, uint256 scalingFactor);
    event NewRebaser(address oldRebaser, address newRebaser);

    event WhitelistFrom(address _addr, bool _whitelisted);
    event WhitelistTo(address _addr, bool _whitelisted);
    event WhitelistRebase(address _addr, bool _whitelisted);

    string public name     = "Xplosive EthereumG";
    string public symbol   = "xETHG";
    uint8  public decimals = 18;

    AggregatorV3Interface internal priceFeed;

    // address public rebaser;
    address public rewardAddress;

    /**
     * @notice Internal decimals used to handle scaling factor
     */
    uint256 public constant internalDecimals = 10**24;

    /**
     * @notice Used for percentage maths
     */
    uint256 public constant BASE = 10**18;

    /**
     * @notice Scaling factor that adjusts everyone's balances
     */
    uint256 public xETHScalingFactor  = BASE;

    mapping (address => uint256) internal _xETHBalances;
    mapping (address => mapping (address => uint256)) internal _allowedFragments;

    mapping(address => bool) public whitelistFrom;
    mapping(address => bool) public whitelistTo;
    mapping(address => bool) public whitelistRebase;

    address public noRebaseAddress;

    uint256 initSupply = 0;
    uint256 _totalSupply = 0;
    uint16 public SELL_FEE = 33;
    uint16 public TX_FEE = 50;

    constructor( uint256 initialSupply, address initialSupplyAddr )
    public
    Ownable()
    Pausable()
    Rebasable()
    {
        priceFeed = AggregatorV3Interface(address(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419));
        _mint(initialSupplyAddr,initialSupply);
    }

    function totalSupply()
    public
    view
    returns (uint256)
    {
        return _totalSupply;
    }

    function getSellBurn(uint256 value)
    public
    view
    whenNotPaused
    returns (uint256)
    {
        uint256 nPercent = value.divRound(SELL_FEE);
        return nPercent;
    }

    function getTxBurn(uint256 value)
    public
    view
    whenNotPaused
    returns (uint256)
    {
        uint256 nPercent = value.divRound(TX_FEE);
        return nPercent;
    }

    function _isWhitelisted(address _from, address _to)
    internal
    view
    returns (bool)
    {
        return whitelistFrom[_from]||whitelistTo[_to];
    }
    function _isRebaseWhitelisted(address _addr)
    internal
    view
    returns (bool)
    {
        return whitelistRebase[_addr];
    }

    function setWhitelistedTo(address _addr, bool _whitelisted)
    external
    onlyOwner
    {
        emit WhitelistTo(_addr, _whitelisted);
        whitelistTo[_addr] = _whitelisted;
    }

    function setTxFee(uint16 fee)
    external
    onlyRebaser
    whenNotPaused
    {
        TX_FEE = fee;
    }

    function setSellFee(uint16 fee)
    external
    onlyRebaser
    whenNotPaused
    {
        SELL_FEE = fee;
    }

    function setWhitelistedFrom(address _addr, bool _whitelisted)
    external
    onlyOwner
    {
        emit WhitelistFrom(_addr, _whitelisted);
        whitelistFrom[_addr] = _whitelisted;
    }

    function setWhitelistedRebase(address _addr, bool _whitelisted)
    external
    onlyOwner
    {
        emit WhitelistRebase(_addr, _whitelisted);
        whitelistRebase[_addr] = _whitelisted;
    }

    function setNoRebaseAddress(address _addr)
    external
    onlyOwner
    {
        noRebaseAddress = _addr;
    }

    /**
    * @notice Computes the current max scaling factor
    */
    function maxScalingFactor()
    external
    view
    whenNotPaused
    returns (uint256)
    {
        return _maxScalingFactor();
    }

    function _maxScalingFactor()
    internal
    view
    returns (uint256)
    {
        // scaling factor can only go up to 2**256-1 = initSupply * xETHScalingFactor
        // this is used to check if xETHScalingFactor will be too high to compute balances when rebasing.
        return uint256(-1) / initSupply;
    }

    function _mint(address to, uint256 amount)
    internal
    {
      // increase totalSupply
      _totalSupply = _totalSupply.add(amount);

      // get underlying value
      uint256 xETHValue = amount.mul(internalDecimals).div(xETHScalingFactor);

      // increase initSupply
      initSupply = initSupply.add(xETHValue);

      // make sure the mint didnt push maxScalingFactor too low
      require(xETHScalingFactor <= _maxScalingFactor(), "max scaling factor too low");

      // add balance
      _xETHBalances[to] = _xETHBalances[to].add(xETHValue);

      emit Transfer(address(0),to,amount);
    }

    /* - ERC20 functionality - */

    /**
    * @dev Transfer tokens to a specified address.
    * @param to The address to transfer to.
    * @param value The amount to be transferred.
    * @return True on success, false otherwise.
    */
    function transfer(address to, uint256 value)
    external
    whenNotPaused
    returns (bool)
    {
        // underlying balance is stored in xETH, so divide by current scaling factor

        // note, this means as scaling factor grows, dust will be untransferrable.
        // minimum transfer value == xETHScalingFactor / 1e24;

        // get amount in underlying
        //from noRebaseWallet
        if(_isRebaseWhitelisted(msg.sender))
        {
            uint256 noReValue = value.mul(internalDecimals).div(BASE);
            uint256 noReNextValue = noReValue.mul(BASE).div(xETHScalingFactor);
            _xETHBalances[msg.sender] = _xETHBalances[msg.sender].sub(noReValue); //value==underlying
            _xETHBalances[to] = _xETHBalances[to].add(noReNextValue);
            emit Transfer(msg.sender, to, value);
        }
        else if(_isRebaseWhitelisted(to))
        {
            uint256 fee = getSellBurn(value);
            uint256 tokensToBurn = fee/2;
            uint256 tokensForRewards = fee-tokensToBurn;
            uint256 tokensToTransfer = value-fee;

            uint256 xETHValue = value.mul(internalDecimals).div(xETHScalingFactor);
            uint256 xETHValueKeep = tokensToTransfer.mul(internalDecimals).div(xETHScalingFactor);
            uint256 xETHValueReward = tokensForRewards.mul(internalDecimals).div(xETHScalingFactor);


            uint256 xETHNextValue = xETHValueKeep.mul(xETHScalingFactor).div(BASE);

            _totalSupply = _totalSupply-fee;
            _xETHBalances[address(0)] = _xETHBalances[address(0)].add(fee/2);
            _xETHBalances[msg.sender] = _xETHBalances[msg.sender].sub(xETHValue);
            _xETHBalances[to] = _xETHBalances[to].add(xETHNextValue);
            _xETHBalances[rewardAddress] = _xETHBalances[rewardAddress].add(xETHValueReward);
            emit Transfer(msg.sender, to, tokensToTransfer);
            emit Transfer(msg.sender, address(0), tokensToBurn);
            emit Transfer(msg.sender, rewardAddress, tokensForRewards);
        }
        else
        {
            if(!_isWhitelisted(msg.sender, to))
            {
                uint256 fee = getTxBurn(value);
                uint256 tokensToBurn = fee/2;
                uint256 tokensForRewards = fee-tokensToBurn;
                uint256 tokensToTransfer = value-fee;

                uint256 xETHValue = value.mul(internalDecimals).div(xETHScalingFactor);
                uint256 xETHValueKeep = tokensToTransfer.mul(internalDecimals).div(xETHScalingFactor);
                uint256 xETHValueReward = tokensForRewards.mul(internalDecimals).div(xETHScalingFactor);

                _totalSupply = _totalSupply-fee;
                _xETHBalances[address(0)] = _xETHBalances[address(0)].add(fee/2);
                _xETHBalances[msg.sender] = _xETHBalances[msg.sender].sub(xETHValue);
                _xETHBalances[to] = _xETHBalances[to].add(xETHValueKeep);
                _xETHBalances[rewardAddress] = _xETHBalances[rewardAddress].add(xETHValueReward);
                emit Transfer(msg.sender, to, tokensToTransfer);
                emit Transfer(msg.sender, address(0), tokensToBurn);
                emit Transfer(msg.sender, rewardAddress, tokensForRewards);
            }
            else
            {
                uint256 xETHValue = value.mul(internalDecimals).div(xETHScalingFactor);

                _xETHBalances[msg.sender] = _xETHBalances[msg.sender].sub(xETHValue);
                _xETHBalances[to] = _xETHBalances[to].add(xETHValue);
                emit Transfer(msg.sender, to, xETHValue);
             }
        }
        return true;
    }

    /**
    * @dev Transfer tokens from one address to another.
    * @param from The address you want to send tokens from.
    * @param to The address you want to transfer to.
    * @param value The amount of tokens to be transferred.
    */
    function transferFrom(address from, address to, uint256 value)
    external
    whenNotPaused
    returns (bool)
    {
        // decrease allowance
        _allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(value);

        if(_isRebaseWhitelisted(from))
        {
            uint256 noReValue = value.mul(internalDecimals).div(BASE);
            uint256 noReNextValue = noReValue.mul(BASE).div(xETHScalingFactor);
            _xETHBalances[from] = _xETHBalances[from].sub(noReValue); //value==underlying
            _xETHBalances[to] = _xETHBalances[to].add(noReNextValue);
            emit Transfer(from, to, value);
        }
        else if(_isRebaseWhitelisted(to))
        {
            uint256 fee = getSellBurn(value);
            uint256 tokensForRewards = fee-(fee/2);
            uint256 tokensToTransfer = value-fee;

            uint256 xETHValue = value.mul(internalDecimals).div(xETHScalingFactor);
            uint256 xETHValueKeep = tokensToTransfer.mul(internalDecimals).div(xETHScalingFactor);
            uint256 xETHValueReward = tokensForRewards.mul(internalDecimals).div(xETHScalingFactor);
            uint256 xETHNextValue = xETHValueKeep.mul(xETHScalingFactor).div(BASE);

            _totalSupply = _totalSupply-fee;

            _xETHBalances[from] = _xETHBalances[from].sub(xETHValue);
            _xETHBalances[to] = _xETHBalances[to].add(xETHNextValue);
            _xETHBalances[rewardAddress] = _xETHBalances[rewardAddress].add(xETHValueReward);
            _xETHBalances[address(0)] = _xETHBalances[address(0)].add(fee/2);
            emit Transfer(from, to, tokensToTransfer);
            emit Transfer(from, address(0), fee/2);
            emit Transfer(from, rewardAddress, tokensForRewards);
        }
        else
        {
            if(!_isWhitelisted(from, to))
            {
                uint256 fee = getTxBurn(value);
                uint256 tokensToBurn = fee/2;
                uint256 tokensForRewards = fee-tokensToBurn;
                uint256 tokensToTransfer = value-fee;

                uint256 xETHValue = value.mul(internalDecimals).div(xETHScalingFactor);
                uint256 xETHValueKeep = tokensToTransfer.mul(internalDecimals).div(xETHScalingFactor);
                uint256 xETHValueReward = tokensForRewards.mul(internalDecimals).div(xETHScalingFactor);

                _totalSupply = _totalSupply-fee;
                _xETHBalances[address(0)] = _xETHBalances[address(0)].add(fee/2);
                _xETHBalances[from] = _xETHBalances[from].sub(xETHValue);
                _xETHBalances[to] = _xETHBalances[to].add(xETHValueKeep);
                _xETHBalances[rewardAddress] = _xETHBalances[rewardAddress].add(xETHValueReward);
                emit Transfer(from, to, tokensToTransfer);
                emit Transfer(from, address(0), tokensToBurn);
                emit Transfer(from, rewardAddress, tokensForRewards);
            }
            else
            {
                uint256 xETHValue = value.mul(internalDecimals).div(xETHScalingFactor);

                _xETHBalances[from] = _xETHBalances[from].sub(xETHValue);
                _xETHBalances[to] = _xETHBalances[to].add(xETHValue);
                emit Transfer(from, to, xETHValue);
             }
        }
        return true;
    }

    /**
    * @param who The address to query.
    * @return The balance of the specified address.
    */
    function balanceOf(address who)
    external
    view
    returns (uint256)
    {
        if(_isRebaseWhitelisted(who))
        {
            return _xETHBalances[who].mul(BASE).div(internalDecimals);
        }
        else
        {
            return _xETHBalances[who].mul(xETHScalingFactor).div(internalDecimals);
        }
    }

    /** @notice Currently returns the internal storage amount
    * @param who The address to query.
    * @return The underlying balance of the specified address.
    */
    function balanceOfUnderlying(address who)
    external
    view
    returns (uint256)
    {
        return _xETHBalances[who];
    }

    /**
     * @dev Function to check the amount of tokens that an owner has allowed to a spender.
     * @param owner_ The address which owns the funds.
     * @param spender The address which will spend the funds.
     * @return The number of tokens still available for the spender.
     */
    function allowance(address owner_, address spender)
    external
    view
    whenNotPaused
    returns (uint256)
    {
        return _allowedFragments[owner_][spender];
    }

    /**
     * @dev Approve the passed address to spend the specified amount of tokens on behalf of
     * msg.sender. This method is included for ERC20 compatibility.
     * increaseAllowance and decreaseAllowance should be used instead.
     * Changing an allowance with this method brings the risk that someone may transfer both
     * the old and the new allowance - if they are both greater than zero - if a transfer
     * transaction is mined before the later approve() call is mined.
     *
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     */
    function approve(address spender, uint256 value)
    external
    whenNotPaused
    returns (bool)
    {
        _allowedFragments[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev Increase the amount of tokens that an owner has allowed to a spender.
     * This method should be used instead of approve() to avoid the double approval vulnerability
     * described above.
     * @param spender The address which will spend the funds.
     * @param addedValue The amount of tokens to increase the allowance by.
     */
    function increaseAllowance(address spender, uint256 addedValue)
    external
    whenNotPaused
    returns (bool)
    {
        _allowedFragments[msg.sender][spender] = _allowedFragments[msg.sender][spender].add(addedValue);
        emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
        return true;
    }

    /**
     * @dev Decrease the amount of tokens that an owner has allowed to a spender.
     *
     * @param spender The address which will spend the funds.
     * @param subtractedValue The amount of tokens to decrease the allowance by.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue)
    external
    whenNotPaused
    returns (bool)
    {
        uint256 oldValue = _allowedFragments[msg.sender][spender];
        if (subtractedValue >= oldValue)
        {
            _allowedFragments[msg.sender][spender] = 0;
        }
        else
        {
            _allowedFragments[msg.sender][spender] = oldValue.sub(subtractedValue);
        }

        emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
        return true;
    }

    function _setRewardAddress(address rewards_)
    external
    onlyOwner
    {
        rewardAddress = rewards_;
    }

    function clRebase()
    external
    onlyRebaser
    whenNotPaused
    returns (uint256)
    {
        uint256 clEthValue = this.getChainlinkEthDollarValue();
        return this.rebase(now, clEthValue, true);
    }

    function clRebaseWtihMultiplier(uint256 _multiplier)
    external
    onlyRebaser
    whenNotPaused
    returns (uint256)
    {
        uint256 clEthValue = this.getChainlinkEthDollarValue();
        return this.rebase(now, clEthValue.mul(_multiplier), true);
    }

    function getChainlinkEthDollarValue()
    external
    view
    returns (uint256)
    {
        ( uint80 roundId, int price, uint startedAt, uint timeStamp, uint80 answeredInRound ) = priceFeed.latestRoundData();
        return uint256(10e18).divRound(price.toUint256()).mul(10e6);
    }

    function getChainlinkEthDollarValueWithMultiplier(uint256 _multiplier)
    external
    view
    returns (uint256)
    {
        uint256 clEthValue = this.getChainlinkEthDollarValue();
        return clEthValue.mul(_multiplier);
    }

    /**
    * @notice Initiates a new rebase operation, provided the minimum time period has elapsed.
    *
    * @dev The supply adjustment equals (totalSupply * DeviationFromTargetRate) / rebaseLag
    *      Where DeviationFromTargetRate is (MarketOracleRate - targetRate) / targetRate
    *      and targetRate is CpiOracleRate / baseCpi
    */
    function rebase(uint256 epoch, uint256 indexDelta, bool positive)
    external
    onlyRebaser
    whenNotPaused
    returns (uint256)
    {
        if (indexDelta == 0 || !positive)
        {
            emit Rebase(epoch, xETHScalingFactor);
            return _totalSupply;
        }

        uint256 newScalingFactor = xETHScalingFactor.mul(BASE.add(indexDelta)).div(BASE);
        if (newScalingFactor < _maxScalingFactor())
        {
            xETHScalingFactor = newScalingFactor;
        }
        else
        {
            xETHScalingFactor = _maxScalingFactor();
        }

        _totalSupply = ((initSupply.sub(_xETHBalances[address(0)]).sub(_xETHBalances[noRebaseAddress]))
            .mul(xETHScalingFactor).div(internalDecimals))
            .add(_xETHBalances[noRebaseAddress].mul(BASE).div(internalDecimals));

        emit Rebase(epoch, xETHScalingFactor);
        return _totalSupply;
    }
}

// File: /Users/mrbitkoin/Projects/LindaCEOJonah/Repositories/Sparkle-Developers/XETH/xeth-v2-token/contracts/XplosiveRebaser.sol



// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.6.12;

import "@openzeppelin/contracts/access/Ownable.sol";

contract Rebasable is Ownable {
  address private _rebaser;

  event TransferredRebasership(address indexed previousRebaser, address indexed newRebaser);

  constructor() internal {
    address msgSender = _msgSender();
    _rebaser = msgSender;
    emit TransferredRebasership(address(0), msgSender);
  }

  function Rebaser() public view returns(address) {
    return _rebaser;
  }

  modifier onlyRebaser() {
    require(_rebaser == _msgSender(), "caller is not rebaser");
    _;
  }

  function transferRebasership(address newRebaser) public virtual onlyOwner {
    require(newRebaser != address(0), "new rebaser is address zero");
    emit TransferredRebasership(_rebaser, newRebaser);
    _rebaser = newRebaser;
  }
}

// File: /Users/mrbitkoin/Projects/LindaCEOJonah/Repositories/Sparkle-Developers/XETH/xeth-v2-token/contracts/XplosiveSafeMath.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library XplosiveSafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }

    function ceil(uint256 a, uint256 m) internal pure returns (uint256)
    {
        uint256 c = add(a,m);
        uint256 d = sub(c,1);
        return mul(div(d,m),m);
    }

    function divRound(uint256 x, uint256 y) internal pure returns (uint256) {
        require(y != 0, "Div by zero");
        uint256 r = x / y;
        if (x % y != 0) {
            r = r + 1;
        }

        return r;
    }
}

// File: @openzeppelin/contracts/GSN/Context.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File: @openzeppelin/contracts/utils/Pausable.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "../GSN/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor () internal {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!_paused, "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(_paused, "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

// File: @openzeppelin/contracts/utils/SafeCast.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}