Cubic Finance Token & Staking - Smart Contract Audit Report

Summary




NOTE: The Cubic Finance team has stolen the 661 of the 698 ETH raised in presale funds and sent them into tornado cash. We strongly advise not engaging with the project; they are still actively marketing it as of January 30th, 2021.








QRX Lottery Audit Report Cubic Finance is a new token that utilizes a low total supply and burn mechanism. Users will also be given the chance to stake Cubic(the platforms native token).


There are currently 3 different staking tiers allowing users to choose from different staking periods. Users staking for the max of 150 days will be earning 84% APY of their investment, it is important to note the minimum stake amount is 5 Cubic. Early withdrawals will not receive rewards and users who claim tokens before the specified date will receive a 5% deduction that will be burned from the total supply. Users who decided to leave their staking rewards locked will gain an extra 10%to their set APY.

Timelock Details:

Notes on the Contracts:
  • The burn rate is fixed and cannot be altered by any outside functions. Token burning of all kinds will be disallowed once the supply of tokens has reached 100,000.
  • The token contract includes a 2% burn-on-transfer fee which increases when the circulating supply drops to 250,000, the token fee then increases to 4% for each transaction. All transactions will be charged with the new fee until the supply drops to 100,000.
  • Users can stake Cubic for different durations. Depending on the duration staked users will incur different fees when they unstake their tokens. No rewards will be given to early withdrawals.
  • The owner has the ability to add and withdraw reward tokens from the rewards pool.
  • The owner can whitelist any address; thereby exempting that address from incurring burn-on-transfer fees.
Audit Findings Summary:
  • No security issues from outside attackers were identified.
  • Date: December 22nd, 2020.


Date: December 22nd, 2020
Vulnerability CategoryNotesResult
Arbitrary Storage WriteN/APASS
Arbitrary JumpN/APASS
Delegate Call to Untrusted ContractN/APASS
Dependence on Predictable VariablesN/APASS
Deprecated OpcodesN/APASS
Ether ThiefN/APASS
ExceptionsN/APASS
External CallsN/APASS
Integer Over/UnderflowN/APASS
Multiple SendsN/APASS
SuicideN/APASS
State Change External CallsN/APass
Unchecked RetvalN/APASS
User Supplied AssertionN/APASS
Critical Solidity CompilerN/APASS
Overall Contract Safety PASS

Token Contract


Smart Contract Graph

Contract Inheritance



                                                            
	($) = payable function
	 # = non-constant function	+  Context 
		- [Int] _msgSender
		- [Int] _msgData

	 + [Int] IERC20 
		- [Ext] totalSupply
		- [Ext] balanceOf
		- [Ext] transfer #
		- [Ext] allowance
		- [Ext] approve #
		- [Ext] transferFrom #

	 + [Lib] SafeMath 
		- [Int] add
		- [Int] sub
		- [Int] sub
		- [Int] mul
		- [Int] div
		- [Int] div
		- [Int] mod
		- [Int] mod

	 + [Lib] Address 
		- [Int] isContract
		- [Int] sendValue #
		- [Int] functionCall #
		- [Int] functionCall #
		- [Int] functionCallWithValue #
		- [Int] functionCallWithValue #
		- [Prv] _functionCallWithValue #

	 + [Lib] SafeERC20 
		- [Int] safeTransfer #
		- [Int] safeTransferFrom #
		- [Int] safeApprove #
		- [Int] safeIncreaseAllowance #
		- [Int] safeDecreaseAllowance #
		- [Prv] _callOptionalReturn #

	 +  Ownable (Context)
		- [Int]  #
		- [Pub] owner
		- [Pub] renounceOwnership #
		   - modifiers: onlyOwner
		- [Pub] transferOwnership #
		   - modifiers: onlyOwner

	 +  Whitelist (Ownable)
		- [Pub] addToWhitelist #
		   - modifiers: onlyOwner
		- [Pub] removeFromWhitelist #
		   - modifiers: onlyOwner
		- [Pub] isWhitelisted

	 +  ERC20 (IERC20, Whitelist)
		- [Pub] name
		- [Pub] symbol
		- [Pub] decimals
		- [Pub] totalSupply
		- [Pub] balanceOf
		- [Pub] transfer #
		- [Pub] allowance
		- [Pub] approve #
		- [Pub] transferFrom #
		- [Pub] increaseAllowance #
		- [Pub] decreaseAllowance #
		- [Int] _transfer #
		- [Int] _approve #
		- [Pub] burn #
		- [Int] _burn #
		- [Int] _setupDecimals #
		- [Int] _beforeTokenTransfer #

	 +  Cubic (ERC20)
		- [Pub]  #

							

Click here to download the source code as a .sol file.


	/**
	*Submitted for verification at Etherscan.io on 2020-12-18
   */

   pragma solidity ^0.6.12;

   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;
	   }
   }

   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);
   }   library SafeMath {

	   function add(uint256 a, uint256 b) internal pure returns (uint256) {
		   uint256 c = a + b;
		   require(c >= a, "SafeMath: addition overflow");

		   return c;
	   }

	   function sub(uint256 a, uint256 b) internal pure returns (uint256) {
		   return sub(a, b, "SafeMath: subtraction overflow");
	   }

	   function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		   require(b <= a, errorMessage);
		   uint256 c = a - b;

		   return c;
	   }

	   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;
	   }

	   function div(uint256 a, uint256 b) internal pure returns (uint256) {
		   return div(a, b, "SafeMath: division by 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;
	   }

	   function mod(uint256 a, uint256 b) internal pure returns (uint256) {
		   return mod(a, b, "SafeMath: modulo by zero");
	   }

	   function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		   require(b != 0, errorMessage);
		   return a % b;
	   }
   }

   library Address {

	   function isContract(address account) internal view returns (bool) {
		   // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
		   // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
		   // for accounts without code, i.e. `keccak256('')`
		   bytes32 codehash;
		   bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
		   // solhint-disable-next-line no-inline-assembly
		   assembly { codehash := extcodehash(account) }
		   return (codehash != accountHash && codehash != 0x0);
	   }

	   function sendValue(address payable recipient, uint256 amount) internal {
		   require(address(this).balance >= amount, "Address: insufficient balance");

		   // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
		   (bool success, ) = recipient.call{ value: amount }("");
		   require(success, "Address: unable to send value, recipient may have reverted");
	   }

	   function functionCall(address target, bytes memory data) internal returns (bytes memory) {
		 return functionCall(target, data, "Address: low-level call failed");
	   }

	   function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
		   return _functionCallWithValue(target, data, 0, errorMessage);
	   }

	   function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
		   return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
	   }

	   function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
		   require(address(this).balance >= value, "Address: insufficient balance for call");
		   return _functionCallWithValue(target, data, value, errorMessage);
	   }

	   function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
		   require(isContract(target), "Address: call to non-contract");

		   // solhint-disable-next-line avoid-low-level-calls
		   (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
		   if (success) {
			   return returndata;
		   } else {
			   // Look for revert reason and bubble it up if present
			   if (returndata.length > 0) {
				   // The easiest way to bubble the revert reason is using memory via assembly

				   // solhint-disable-next-line no-inline-assembly
				   assembly {
					   let returndata_size := mload(returndata)
					   revert(add(32, returndata), returndata_size)
				   }
			   } else {
				   revert(errorMessage);
			   }
		   }
	   }
   }   library SafeERC20 {
	   using SafeMath for uint256;
	   using Address for address;

	   function safeTransfer(IERC20 token, address to, uint256 value) internal {
		   _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
	   }

	   function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
		   _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
	   }

	   function safeApprove(IERC20 token, address spender, uint256 value) internal {
		   require((value == 0) || (token.allowance(address(this), spender) == 0),
			   "SafeERC20: approve from non-zero to non-zero allowance"
		   );
		   _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
	   }

	   function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
		   uint256 newAllowance = token.allowance(address(this), spender).add(value);
		   _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
	   }

	   function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
		   uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
		   _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
	   }

	   function _callOptionalReturn(IERC20 token, bytes memory data) private {
		   bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
		   if (returndata.length > 0) { // Return data is optional
			   // solhint-disable-next-line max-line-length
			   require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
		   }
	   }
   }

   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;
	   }
   }

   contract Whitelist is Ownable {
	   mapping(address => bool) whitelist;
	   event AddedToWhitelist(address indexed account);
	   event RemovedFromWhitelist(address indexed account);

	   modifier onlyWhitelisted() {
		   require(isWhitelisted(msg.sender));
		   _;
	   }

	   function addToWhitelist(address _address) public onlyOwner {
		   whitelist[_address] = true;
		   emit AddedToWhitelist(_address);
	   }

	   function removeFromWhitelist(address _address) public onlyOwner {
		   whitelist[_address] = false;
		   emit RemovedFromWhitelist(_address);
	   }

	   function isWhitelisted(address _address) public view returns(bool) {
		   return whitelist[_address];
	   }
   }   contract ERC20 is IERC20, Whitelist {
	   using SafeMath for uint256;
	   using Address for address;

	   mapping (address => uint256) _balances;

	   mapping (address => mapping (address => uint256)) _allowances;

	   event Burn(address indexed burner, uint256 value);

	   uint256 INITIAL_SUPPLY = 300000e18; //available supply
	   uint256 BURN_RATE = 2; //burn every per txn
	   uint256 MAX_SUPPLY_FLOOR = 100000e18; // floor supply after burned
	   uint256 DEFLATION_START_TIME = block.timestamp + 28 days;

	   string  _name;
	   string  _symbol;
	   uint8 _decimals;
	   uint256 _totalSupply;

	   function name() public view returns (string memory) {
		   return _name;
	   }

	   function symbol() public view returns (string memory) {
		   return _symbol;
	   }	   function decimals() public view returns (uint8) {
		   return _decimals;
	   }	   function totalSupply() public view override returns (uint256) {
		   return _totalSupply;
	   }	   function balanceOf(address account) public view override returns (uint256) {
		   return _balances[account];
	   }	   function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
		   _transfer(_msgSender(), recipient, amount);
		   return true;
	   }

	   function allowance(address owner, address spender) public view virtual override returns (uint256) {
		   return _allowances[owner][spender];
	   }

	   function approve(address spender, uint256 amount) public virtual override returns (bool) {
		   _approve(_msgSender(), spender, amount);
		   return true;
	   }	   function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
		   _transfer(sender, recipient, amount);
		   _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
		   return true;
	   }	   function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
		   _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
		   return true;
	   }	   function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
		   _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
		   return true;
	   }

	   function _transfer(address sender, address recipient, uint256 amount) internal virtual {
		   require(sender != address(0), "ERC20: transfer from the zero address");
		   require(recipient != address(0), "ERC20: transfer to the zero address");

		   _beforeTokenTransfer(sender, recipient, amount);

		   _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");

		   if(block.timestamp >= DEFLATION_START_TIME){
			   uint256 _burnedAmount = amount.mul(BURN_RATE).div(100);

			   if(_totalSupply.sub(_burnedAmount) < MAX_SUPPLY_FLOOR || isWhitelisted(sender)){
				   _burnedAmount = 0;
			   } else if (_totalSupply.sub(_burnedAmount) < 250000e18 && _totalSupply.sub(_burnedAmount) > MAX_SUPPLY_FLOOR) {
				   _burnedAmount = _burnedAmount.mul(2); //4%
			   }

			   if (_burnedAmount > 0) {
				   _totalSupply = _totalSupply.sub(_burnedAmount);
				   emit Burn(sender, _burnedAmount);
			   }
			   amount = amount.sub(_burnedAmount);
		   }

		   _balances[recipient] = _balances[recipient].add(amount);

		   emit Transfer(sender, recipient, amount);
	   }	   function _approve(address owner, address spender, uint256 amount) internal virtual {
		   require(owner != address(0), "ERC20: approve from the zero address");
		   require(spender != address(0), "ERC20: approve to the zero address");

		   _allowances[owner][spender] = amount;
		   emit Approval(owner, spender, amount);
	   }

	   function burn(uint256 _value) public {

		   if(_totalSupply.sub(_value) >= MAX_SUPPLY_FLOOR ){
			   _burn(msg.sender, _value);
		   }

	   }

	   function _burn(address account, uint256 amount) internal virtual {
		   require(account != address(0), "ERC20: burn from the zero address");

		   _beforeTokenTransfer(account, address(0), amount);

		   _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
		   _totalSupply = _totalSupply.sub(amount);

		   emit Burn(account, amount);
		   emit Transfer(account, address(0), amount);
	   }	   function _setupDecimals(uint8 decimals_) internal {
		   _decimals = decimals_;
	   }	   function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
   }   contract Cubic is ERC20{

	   constructor (string memory name, string memory symbol) public {
		   _name = "Cubic Finance";
		   _symbol = "CUBIC";
		   _decimals = 18;
		   _totalSupply = INITIAL_SUPPLY;
		   _balances[msg.sender] = _balances[msg.sender].add(INITIAL_SUPPLY);
	   }
}


Staking Contract


Smart Contract Graph

Contract Inheritance



                                                            
($) = payable function
 # = non-constant function +  Context 
	- [Int] _msgSender
	- [Int] _msgData

 + [Int] IERC20 
	- [Ext] totalSupply
	- [Ext] balanceOf
	- [Ext] transfer #
	- [Ext] allowance
	- [Ext] approve #
	- [Ext] transferFrom #

 + [Lib] SafeMath 
	- [Int] add
	- [Int] sub
	- [Int] sub
	- [Int] mul
	- [Int] div
	- [Int] div
	- [Int] mod
	- [Int] mod

 + [Lib] Address 
	- [Int] isContract
	- [Int] sendValue #
	- [Int] functionCall #
	- [Int] functionCall #
	- [Int] functionCallWithValue #
	- [Int] functionCallWithValue #
	- [Prv] _functionCallWithValue #

 + [Lib] SafeERC20 
	- [Int] safeTransfer #
	- [Int] safeTransferFrom #
	- [Int] safeApprove #
	- [Int] safeIncreaseAllowance #
	- [Int] safeDecreaseAllowance #
	- [Prv] _callOptionalReturn #

 +  Ownable (Context)
	- [Int]  #
	- [Pub] owner
	- [Pub] renounceOwnership #
	   - modifiers: onlyOwner
	- [Pub] transferOwnership #
	   - modifiers: onlyOwner

 +  Whitelist (Ownable)
	- [Pub] addToWhitelist #
	   - modifiers: onlyOwner
	- [Pub] removeFromWhitelist #
	   - modifiers: onlyOwner
	- [Pub] isWhitelisted

 +  ERC20 (IERC20, Whitelist)
	- [Pub] name
	- [Pub] symbol
	- [Pub] decimals
	- [Pub] totalSupply
	- [Pub] balanceOf
	- [Pub] transfer #
	- [Pub] allowance
	- [Pub] approve #
	- [Pub] transferFrom #
	- [Pub] increaseAllowance #
	- [Pub] decreaseAllowance #
	- [Int] _transfer #
	- [Int] _approve #
	- [Pub] burn #
	- [Int] _burn #
	- [Int] _setupDecimals #
	- [Int] _beforeTokenTransfer #

 +  Token (ERC20)
	- [Pub]  #

 +  Staking (Ownable)
	- [Pub]  #
	- [Pub] stake #
	   - modifiers: shouldStarted
	- [Pub] withdraw #
	   - modifiers: shouldStarted
	- [Pub] claim #
	   - modifiers: shouldStarted
	- [Pub] getRewardsAmountPerSeconds
	- [Pub] balanceOf
	- [Pub] getTotalRewardsAmount
	- [Pub] addPoolAmount #
	   - modifiers: onlyOwner
	- [Pub] updatePoolAmount #
	   - modifiers: onlyOwner
	- [Pub] withdrawPoolAmount #
	   - modifiers: onlyOwner
	- [Int] updateRewards #
	- [Ext] startStaking #
	   - modifiers: onlyOwner

							

Click here to download the source code as a .sol file.


	/**
	*Submitted for verification at Etherscan.io on 2020-12-18
	*/

	pragma solidity ^0.6.12;

	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;
	   }
	}

	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);
	}	library SafeMath {

	   function add(uint256 a, uint256 b) internal pure returns (uint256) {
		   uint256 c = a + b;
		   require(c >= a, "SafeMath: addition overflow");

		   return c;
	   }

	   function sub(uint256 a, uint256 b) internal pure returns (uint256) {
		   return sub(a, b, "SafeMath: subtraction overflow");
	   }

	   function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		   require(b <= a, errorMessage);
		   uint256 c = a - b;

		   return c;
	   }

	   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;
	   }

	   function div(uint256 a, uint256 b) internal pure returns (uint256) {
		   return div(a, b, "SafeMath: division by 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;
	   }

	   function mod(uint256 a, uint256 b) internal pure returns (uint256) {
		   return mod(a, b, "SafeMath: modulo by zero");
	   }

	   function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
		   require(b != 0, errorMessage);
		   return a % b;
	   }
	}

	library Address {

	   function isContract(address account) internal view returns (bool) {
		   // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
		   // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
		   // for accounts without code, i.e. `keccak256('')`
		   bytes32 codehash;
		   bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
		   // solhint-disable-next-line no-inline-assembly
		   assembly { codehash := extcodehash(account) }
		   return (codehash != accountHash && codehash != 0x0);
	   }

	   function sendValue(address payable recipient, uint256 amount) internal {
		   require(address(this).balance >= amount, "Address: insufficient balance");

		   // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
		   (bool success, ) = recipient.call{ value: amount }("");
		   require(success, "Address: unable to send value, recipient may have reverted");
	   }

	   function functionCall(address target, bytes memory data) internal returns (bytes memory) {
		 return functionCall(target, data, "Address: low-level call failed");
	   }

	   function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
		   return _functionCallWithValue(target, data, 0, errorMessage);
	   }

	   function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
		   return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
	   }

	   function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
		   require(address(this).balance >= value, "Address: insufficient balance for call");
		   return _functionCallWithValue(target, data, value, errorMessage);
	   }

	   function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
		   require(isContract(target), "Address: call to non-contract");

		   // solhint-disable-next-line avoid-low-level-calls
		   (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
		   if (success) {
			   return returndata;
		   } else {
			   // Look for revert reason and bubble it up if present
			   if (returndata.length > 0) {
				   // The easiest way to bubble the revert reason is using memory via assembly

				   // solhint-disable-next-line no-inline-assembly
				   assembly {
					   let returndata_size := mload(returndata)
					   revert(add(32, returndata), returndata_size)
				   }
			   } else {
				   revert(errorMessage);
			   }
		   }
	   }
	}	library SafeERC20 {
	   using SafeMath for uint256;
	   using Address for address;

	   function safeTransfer(IERC20 token, address to, uint256 value) internal {
		   _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
	   }

	   function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
		   _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
	   }

	   function safeApprove(IERC20 token, address spender, uint256 value) internal {
		   require((value == 0) || (token.allowance(address(this), spender) == 0),
			   "SafeERC20: approve from non-zero to non-zero allowance"
		   );
		   _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
	   }

	   function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
		   uint256 newAllowance = token.allowance(address(this), spender).add(value);
		   _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
	   }

	   function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
		   uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
		   _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
	   }

	   function _callOptionalReturn(IERC20 token, bytes memory data) private {
		   bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
		   if (returndata.length > 0) { // Return data is optional
			   // solhint-disable-next-line max-line-length
			   require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
		   }
	   }
	}

	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;
	   }
	}

	contract Whitelist is Ownable {
	   mapping(address => bool) whitelist;
	   event AddedToWhitelist(address indexed account);
	   event RemovedFromWhitelist(address indexed account);

	   modifier onlyWhitelisted() {
		   require(isWhitelisted(msg.sender));
		   _;
	   }

	   function addToWhitelist(address _address) public onlyOwner {
		   whitelist[_address] = true;
		   emit AddedToWhitelist(_address);
	   }

	   function removeFromWhitelist(address _address) public onlyOwner {
		   whitelist[_address] = false;
		   emit RemovedFromWhitelist(_address);
	   }

	   function isWhitelisted(address _address) public view returns(bool) {
		   return whitelist[_address];
	   }
	}	contract ERC20 is IERC20, Whitelist {
	   using SafeMath for uint256;
	   using Address for address;

	   mapping (address => uint256) _balances;

	   mapping (address => mapping (address => uint256)) _allowances;

	   event Burn(address indexed burner, uint256 value);

	   uint256 INITIAL_SUPPLY = 300000e18; //available supply
	   uint256 BURN_RATE = 2; //burn every per txn
	   uint256 MAX_SUPPLY_FLOOR = 100000e18; // floor supply after burned
	   uint256 DEFLATION_START_TIME = block.timestamp + 30 days;

	   string  _name;
	   string  _symbol;
	   uint8 _decimals;
	   uint256 _totalSupply;

	   function name() public view returns (string memory) {
		   return _name;
	   }

	   function symbol() public view returns (string memory) {
		   return _symbol;
	   }	   function decimals() public view returns (uint8) {
		   return _decimals;
	   }	   function totalSupply() public view override returns (uint256) {
		   return _totalSupply;
	   }	   function balanceOf(address account) public view override returns (uint256) {
		   return _balances[account];
	   }	   function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
		   _transfer(_msgSender(), recipient, amount);
		   return true;
	   }

	   function allowance(address owner, address spender) public view virtual override returns (uint256) {
		   return _allowances[owner][spender];
	   }

	   function approve(address spender, uint256 amount) public virtual override returns (bool) {
		   _approve(_msgSender(), spender, amount);
		   return true;
	   }	   function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
		   _transfer(sender, recipient, amount);
		   _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
		   return true;
	   }	   function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
		   _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
		   return true;
	   }	   function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
		   _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
		   return true;
	   }

	   function _transfer(address sender, address recipient, uint256 amount) internal virtual {
		   require(sender != address(0), "ERC20: transfer from the zero address");
		   require(recipient != address(0), "ERC20: transfer to the zero address");

		   _beforeTokenTransfer(sender, recipient, amount);

		   _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");

		   if(block.timestamp >= DEFLATION_START_TIME){
			   uint256 _burnedAmount = amount.mul(BURN_RATE).div(100);

			   if(_totalSupply.sub(_burnedAmount) < MAX_SUPPLY_FLOOR || isWhitelisted(sender)){
				   _burnedAmount = 0;
			   } else if (_totalSupply.sub(_burnedAmount) < 250000e18 && _totalSupply.sub(_burnedAmount) > MAX_SUPPLY_FLOOR) {
				   _burnedAmount = _burnedAmount.mul(2); //4%
			   }

			   if (_burnedAmount > 0) {
				   _totalSupply = _totalSupply.sub(_burnedAmount);
				   emit Burn(sender, _burnedAmount);
			   }
			   amount = amount.sub(_burnedAmount);
		   }

		   _balances[recipient] = _balances[recipient].add(amount);

		   emit Transfer(sender, recipient, amount);
	   }	   function _approve(address owner, address spender, uint256 amount) internal virtual {
		   require(owner != address(0), "ERC20: approve from the zero address");
		   require(spender != address(0), "ERC20: approve to the zero address");

		   _allowances[owner][spender] = amount;
		   emit Approval(owner, spender, amount);
	   }

	   function burn(uint256 _value) public {

		   if(_totalSupply.sub(_value) >= MAX_SUPPLY_FLOOR ){
			   _burn(msg.sender, _value);
		   }

	   }

	   function _burn(address account, uint256 amount) internal virtual {
		   require(account != address(0), "ERC20: burn from the zero address");

		   _beforeTokenTransfer(account, address(0), amount);

		   _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
		   _totalSupply = _totalSupply.sub(amount);

		   emit Burn(account, amount);
		   emit Transfer(account, address(0), amount);
	   }	   function _setupDecimals(uint8 decimals_) internal {
		   _decimals = decimals_;
	   }	   function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
	}	contract Token is ERC20{

	   constructor (string memory name, string memory symbol) public {
		   _name = name;
		   _symbol = symbol;
		   _decimals = 18;
		   _totalSupply = INITIAL_SUPPLY;
		   _balances[msg.sender] = _balances[msg.sender].add(INITIAL_SUPPLY);
	   }	}	contract Staking is Ownable {

	   using SafeMath for uint256;
	   using SafeERC20 for Token;
	   using Address for address;

	   Token public token;

	   // annual yield period
	   uint256 private constant DURATION = 365 days;
	   uint256 private constant MINIMUM_AMOUNT = 5e18;
	   uint256 public _poolAmount = 0;
	   uint256 public _totalTokenBalance;
	   bool public haveStarted = false;

	   mapping(address => uint256) private _stakerTokenBalance;
	   mapping(address => uint256) public _stakerRewardRate;
	   mapping(address => uint256) public _stakerStakingPlan;
	   mapping(address => uint256) public _stakerWithdrawFeeRate;

	   mapping(address => uint256) public _stakerLastClaimTime;
	   mapping(address => uint256) public _stakerStakingTime;
	   mapping(address => uint256) public _stakerTokenRewards;
	   mapping(address => uint256) public _stakerTokenRewardsClaimed;

	   event Stake(address indexed from, uint amount);
	   event Withdraw(address indexed to, uint amount);
	   event Claim(address indexed to, uint amount);

	   constructor(address _token) public{
		   token = Token(_token);
	   }	   function stake(uint plan, uint amount) public shouldStarted {

		   require(_stakerStakingPlan[msg.sender] == 0, "Withdraw your current plan.");

		   _stakerStakingTime[msg.sender] = block.timestamp;
		   _stakerStakingPlan[msg.sender] = plan;

		   updateRewards(msg.sender);

		   require(!address(msg.sender).isContract(), "Please use your individual account.");
		   require(amount >= MINIMUM_AMOUNT, "Should stake at least 5 Token.");

		   token.safeTransferFrom(msg.sender, address(this), amount);
		   _totalTokenBalance = _totalTokenBalance.add(amount);
		   _stakerTokenBalance[msg.sender] = _stakerTokenBalance[msg.sender].add(amount);

		   emit Stake(msg.sender, amount);
	   }

	   function withdraw(uint amount) public shouldStarted {
		   updateRewards(msg.sender);

		   require(amount <= _stakerTokenBalance[msg.sender] && _stakerTokenBalance[msg.sender] > 0, "Bad withdraw.");

		   _totalTokenBalance = _totalTokenBalance.sub(amount);
		   _stakerTokenBalance[msg.sender] = _stakerTokenBalance[msg.sender].sub(amount);
		   _stakerTokenRewardsClaimed[msg.sender] = 0;
		   _stakerLastClaimTime[msg.sender] = 0;		   if(_stakerWithdrawFeeRate[msg.sender] > 0){
			   uint256 _burnedAmount = amount.mul(_stakerWithdrawFeeRate[msg.sender]).div(100);
			   amount = amount.sub(_burnedAmount);
			   token.burn(_burnedAmount);
		   }

		   token.safeTransfer(msg.sender, amount);

		   emit Withdraw(msg.sender, amount);
	   }

	   function claim(uint amount) public shouldStarted {
		   updateRewards(msg.sender);

		   require( _stakerTokenRewards[msg.sender] > 0, "Bad claim.");
		   require( amount <= _poolAmount && _poolAmount > 0, "The Pool is Empty.");

		   _stakerTokenRewards[msg.sender] = _stakerTokenRewards[msg.sender].sub(amount);
		   _stakerTokenRewardsClaimed[msg.sender] = _stakerTokenRewardsClaimed[msg.sender].add(amount);
		   _poolAmount = _poolAmount.sub(amount);
		   _stakerLastClaimTime[msg.sender] = block.timestamp;
		   token.safeTransfer(msg.sender, amount);

		   emit Claim(msg.sender, amount);
	   }

	   modifier shouldStarted() {
		   require(haveStarted == true, "Have not started.");
		   _;
	   }

	   function getRewardsAmountPerSeconds(address account) public view returns(uint256) {
		   return balanceOf(account).mul(_stakerRewardRate[msg.sender]).div(100)
				   .div(DURATION);
	   }

	   function balanceOf(address account) public view returns(uint256) {
		   return _stakerTokenBalance[account];
	   }

	   function getTotalRewardsAmount(address account) public view returns (uint256) {

		   return block.timestamp.sub(_stakerStakingTime[account]).mul(getRewardsAmountPerSeconds(account));
	   }

	   function addPoolAmount(uint amount) public onlyOwner{

		   require(amount > 0, "Should add be more than 0 Token.");
		   _poolAmount = _poolAmount.add(amount);
		   token.safeTransferFrom(msg.sender, address(this), amount);
	   }

	   function updatePoolAmount(uint amount) public onlyOwner{
		   _poolAmount = amount;
	   }

	   function withdrawPoolAmount(uint amount) public onlyOwner{
		   require( amount <= _poolAmount && _poolAmount > 0, "The Pool is Empty.");
		   _poolAmount = _poolAmount.sub(amount);
		   token.safeTransfer(msg.sender, amount);
	   }	   function updateRewards(address account) internal {

		   if(_stakerStakingPlan[msg.sender] == 1){

			   if(block.timestamp < _stakerStakingTime[msg.sender] + 15 days){
					_stakerRewardRate[msg.sender] = 0;
					_stakerWithdrawFeeRate[msg.sender] = 5;
			   } else if(block.timestamp >= _stakerStakingTime[msg.sender] + 15 days && block.timestamp <= _stakerStakingTime[msg.sender] + 45 days){
					_stakerRewardRate[msg.sender] = 0;
					_stakerWithdrawFeeRate[msg.sender] = 0;
			   } else if(block.timestamp > _stakerStakingTime[msg.sender] + 45 days && _stakerLastClaimTime[msg.sender] == 0){
				   _stakerRewardRate[msg.sender] = 48;
				   _stakerWithdrawFeeRate[msg.sender] = 0;
			   } else {
					_stakerRewardRate[msg.sender] = 38;
					_stakerWithdrawFeeRate[msg.sender] = 0;
			   }

		   } else if(_stakerStakingPlan[msg.sender] == 2){

			   if(block.timestamp < _stakerStakingTime[msg.sender] + 25 days){

				   _stakerRewardRate[msg.sender] = 0;
				   _stakerWithdrawFeeRate[msg.sender] = 5;

			   } else if(block.timestamp >= _stakerStakingTime[msg.sender] + 25 days && block.timestamp <= _stakerStakingTime[msg.sender] + 75 days){
					_stakerRewardRate[msg.sender] = 0;
					_stakerWithdrawFeeRate[msg.sender] = 0;
			   } else if(block.timestamp > _stakerStakingTime[msg.sender] + 75 days && _stakerLastClaimTime[msg.sender] == 0){
				   _stakerRewardRate[msg.sender] = 70;
				   _stakerWithdrawFeeRate[msg.sender] = 0;
			   } else {
					_stakerRewardRate[msg.sender] = 60;
					_stakerWithdrawFeeRate[msg.sender] = 0;
			   }

		   } else if(_stakerStakingPlan[msg.sender] == 3){

			   if(block.timestamp < _stakerStakingTime[msg.sender] + 50 days){

				   _stakerRewardRate[msg.sender] = 0;
				   _stakerWithdrawFeeRate[msg.sender] = 5;

			   } else if(block.timestamp >= _stakerStakingTime[msg.sender] + 50 days && block.timestamp <= _stakerStakingTime[msg.sender] + 150 days){
					_stakerRewardRate[msg.sender] = 0;
					_stakerWithdrawFeeRate[msg.sender] = 0;
			   } else if(block.timestamp > _stakerStakingTime[msg.sender] + 150 days && _stakerLastClaimTime[msg.sender] == 0){
				   _stakerRewardRate[msg.sender] = 94;
				   _stakerWithdrawFeeRate[msg.sender] = 0;
			   } else {
					_stakerRewardRate[msg.sender] = 84;
					_stakerWithdrawFeeRate[msg.sender] = 0;
			   }

		   }

		   if (account != address(0)) {
				_stakerTokenRewards[account] = getTotalRewardsAmount(account).sub(_stakerTokenRewardsClaimed[account]);
		   }
	   }

	   function startStaking() external onlyOwner {
		   updateRewards(address(0));
		   haveStarted = true;
	   }	}