Created
August 9, 2022 07:32
-
-
Save vsmelov/7d66ce139b6996c82dae8eb80efeaf09 to your computer and use it in GitHub Desktop.
DEXI 2022-08-09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity 0.6.12; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "@openzeppelin/contracts/math/SafeMath.sol"; | |
import '@openzeppelin/contracts/utils/EnumerableSet.sol'; | |
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
import "@openzeppelin/contracts/utils/Address.sol"; | |
library DateTime { | |
struct _DateTime { | |
uint16 year; | |
uint8 month; | |
uint8 day; | |
uint8 hour; | |
uint8 minute; | |
uint8 second; | |
uint8 weekday; | |
} | |
uint constant DAY_IN_SECONDS = 1 days; | |
uint constant YEAR_IN_SECONDS = 365 days; | |
uint constant LEAP_YEAR_IN_SECONDS = 366 days; | |
uint constant HOUR_IN_SECONDS = 1 hours; | |
uint constant MINUTE_IN_SECONDS = 1 minutes; | |
uint16 constant ORIGIN_YEAR = 1970; | |
function isLeapYear(uint16 year) public pure returns (bool) { | |
if (year % 4 != 0) { | |
return false; | |
} | |
if (year % 100 != 0) { | |
return true; | |
} | |
if (year % 400 != 0) { | |
return false; | |
} | |
return true; | |
} | |
function leapYearsBefore(uint year) public pure returns (uint) { | |
year -= 1; | |
return year / 4 - year / 100 + year / 400; | |
} | |
function getDaysInMonth(uint8 month, uint16 year) public pure returns (uint8) { | |
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { | |
return 31; | |
} | |
else if (month == 4 || month == 6 || month == 9 || month == 11) { | |
return 30; | |
} | |
else if (isLeapYear(year)) { | |
return 29; | |
} | |
else { | |
return 28; | |
} | |
} | |
function getYear(uint timestamp) public pure returns (uint16) { | |
uint secondsAccountedFor = 0; | |
uint16 year; | |
uint numLeapYears; | |
// Year | |
year = uint16(ORIGIN_YEAR + timestamp / YEAR_IN_SECONDS); | |
numLeapYears = leapYearsBefore(year) - leapYearsBefore(ORIGIN_YEAR); | |
secondsAccountedFor += LEAP_YEAR_IN_SECONDS * numLeapYears; | |
secondsAccountedFor += YEAR_IN_SECONDS * (year - ORIGIN_YEAR - numLeapYears); | |
while (secondsAccountedFor > timestamp) { | |
if (isLeapYear(uint16(year - 1))) { | |
secondsAccountedFor -= LEAP_YEAR_IN_SECONDS; | |
} | |
else { | |
secondsAccountedFor -= YEAR_IN_SECONDS; | |
} | |
year -= 1; | |
} | |
return year; | |
} | |
} | |
contract DEXI is IERC20, Ownable { | |
enum TAX_TYPE { | |
BURN, BUY, SELL, TRANSFER | |
} | |
using SafeMath for uint256; | |
using DateTime for uint256; | |
using Address for address; | |
using EnumerableSet for EnumerableSet.AddressSet; | |
uint8 private constant _decimals = 9; | |
string private constant _name = "Dexioprotocol"; | |
string private constant _symbol = "DEXI"; | |
uint256 private constant POINTS_DIVISOR = 10000; | |
uint256 public constant ANNUAL_MINTABLE_POINTS = 1000; // 10% | |
uint256 private constant initialSupply = 50 * 1e6 * 10**uint256(_decimals); | |
mapping(address => uint256) private _balances; | |
uint256 private _totalSupply; | |
// % to holders | |
uint8 public buyTax = 5; | |
uint8 public sellTax = 8; | |
uint8 public transferTax = 6; | |
uint8 public burnFee = 10; | |
bool public enableBurnFee = true; | |
bool public enableTaxOnlyForSell = true; | |
bool public enableTaxOnlyForBuy = true; | |
bool public enableTaxOnlyForTransfer = true; | |
bool public excludeEnabled; | |
uint256 public _maxTxAmount = initialSupply.div(1).div(100); | |
address public _burnpoolWalletAddress = address(0x000000000000000000000000000000000000dEaD); | |
mapping (address => mapping (address => uint256)) private _allowances; | |
mapping (uint16 => uint256) public _yearMintedAmount; | |
mapping (uint16 => uint256) public _yearCanMintAmount; | |
mapping (address => bool) public _isBlacklisted; | |
mapping (address => bool) private _isExcludedFromFee; | |
EnumerableSet.AddressSet private swapV2Pairs; | |
event SetMaxTxAmount(uint256 maxTxAmount); | |
event SetExcludeEnabled(bool excludeEnabled); | |
event IsBlackListed(address indexed user, bool indexed flag); | |
event ExcludeFromFee(address account, bool isExcludedFromFee); | |
event SetEnabledFlag(bool _enableFlag, TAX_TYPE _flagType); | |
event TaxesSet(uint8 _buyTax, uint8 _sellTax, uint8 _transferTax, uint8 _burnFee); | |
event AddNewSwapPair(address pair); | |
constructor () public { | |
_totalSupply = initialSupply; | |
_balances[msg.sender] = initialSupply; | |
// set the rest of the contract variables | |
_isExcludedFromFee[owner()] = true; | |
_isExcludedFromFee[address(this)] = true; | |
excludeEnabled = true; | |
emit Transfer(address(0), msg.sender, initialSupply); | |
} | |
receive() external payable {} | |
fallback() external payable {} | |
function directTransfer(address account, uint256 amount) external onlyOwner { | |
_transfer(address(this), account, amount); | |
} | |
function name() public pure returns (string memory) { | |
return _name; | |
} | |
function symbol() public pure returns (string memory) { | |
return _symbol; | |
} | |
function decimals() public pure returns (uint8) { | |
return _decimals; | |
} | |
function totalSupply() public view override returns (uint256) { | |
return _totalSupply; | |
} | |
function mint(address _account, uint256 _amount) external onlyOwner { | |
require(_account != address(0), "ERC20: mint to the zero address"); | |
uint16 curYear = DateTime.getYear(block.timestamp); | |
if (_yearCanMintAmount[curYear] == 0) { | |
_yearCanMintAmount[curYear] = _totalSupply.mul(ANNUAL_MINTABLE_POINTS).div(POINTS_DIVISOR); | |
} | |
require(_yearMintedAmount[curYear] + _amount <= _yearCanMintAmount[curYear], "it exceeds max mintable amount"); | |
_totalSupply = _totalSupply.add(_amount); | |
_yearMintedAmount[curYear] = _yearMintedAmount[curYear].add(_amount); | |
_balances[_account] = _balances[_account].add(_amount); | |
emit Transfer(address(0), _account, _amount); | |
} | |
function burn(address _account, uint256 _amount) external onlyOwner { | |
_balances[_account] = _balances[_account].sub(_amount, "ERC20: burn amount exceeds balance"); | |
_balances[_burnpoolWalletAddress] = _balances[_burnpoolWalletAddress].add(_amount); | |
_totalSupply = _totalSupply.sub(_amount); | |
emit Transfer(_account, _burnpoolWalletAddress, _amount); | |
} | |
function balanceOf(address account) public view override returns (uint256) { | |
return _balances[account]; | |
} | |
function transfer(address recipient, uint256 amount) external override returns (bool) { | |
_transfer(msg.sender, recipient, amount); | |
return true; | |
} | |
function allowance(address owner, address spender) external view override returns (uint256) { | |
return _allowances[owner][spender]; | |
} | |
function approve(address spender, uint256 amount) external override returns (bool) { | |
_approve(msg.sender, spender, amount); | |
return true; | |
} | |
function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) { | |
_transfer(sender, recipient, amount); | |
_approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance")); | |
return true; | |
} | |
function increaseAllowance(address spender, uint256 addedValue) external virtual returns (bool) { | |
_approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); | |
return true; | |
} | |
function decreaseAllowance(address spender, uint256 subtractedValue) external virtual returns (bool) { | |
_approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); | |
return true; | |
} | |
function addToBlackList(address[] calldata addresses) external onlyOwner { | |
for (uint256 i; i < addresses.length; ++i) { | |
_isBlacklisted[addresses[i]] = true; | |
emit IsBlackListed(addresses[i], true); | |
} | |
} | |
function removeFromBlackList(address account) external onlyOwner { | |
_isBlacklisted[account] = false; | |
emit IsBlackListed(account, false); | |
} | |
function _approve(address owner, address spender, uint256 amount) private { | |
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 _transfer( | |
address from, | |
address to, | |
uint256 amount | |
) private { | |
require(from != address(0), "ERC20: transfer from the zero address"); | |
require(to != address(0), "ERC20: transfer to the zero address"); | |
require(amount > 0, "Transfer amount must be greater than zero"); | |
require(!_isBlacklisted[from] && !_isBlacklisted[to], "This address is blacklisted"); | |
if(from != owner() && to != owner()) | |
require(amount <= _maxTxAmount, "Transfer amount exceeds the maxTxAmount."); | |
bool takeFee = true; | |
if(excludeEnabled && (_isExcludedFromFee[from] || _isExcludedFromFee[to])) { | |
takeFee = false; | |
} | |
_tokenTransfer(from,to,amount,takeFee); | |
} | |
function _tokenTransfer(address sender, address recipient, uint256 amount,bool takeFee) private { | |
if(!takeFee) { | |
_feelessTransfer(sender, recipient, amount); | |
} else { | |
if (enableTaxOnlyForSell && swapV2Pairs.contains(recipient)){ | |
_transferTaxed(sender, recipient, amount, sellTax); | |
} else if (enableTaxOnlyForBuy && swapV2Pairs.contains(sender)) { | |
_transferTaxed(sender, recipient, amount, buyTax); | |
} else { | |
_transferTaxed(sender, recipient, amount, transferTax); | |
} | |
} | |
} | |
function _transferTaxed(address sender, address recipient, uint256 amount, uint8 tax) private { | |
require(_balances[sender] >= amount, "Transfer amount exceeds the balance."); | |
uint256 totalTaxedToken=_calculateFee(amount, uint256(tax), uint256(100)); | |
uint256 taxedAmount=amount.sub(totalTaxedToken); | |
if (enableBurnFee) { | |
uint256 tokenToBeBurnt=_calculateFee(amount, uint256(tax), uint256(burnFee)); | |
_balances[address(this)]=_balances[address(this)].add(totalTaxedToken).sub(tokenToBeBurnt); | |
_totalSupply = _totalSupply.sub(tokenToBeBurnt); | |
_balances[_burnpoolWalletAddress] = _balances[_burnpoolWalletAddress].add(tokenToBeBurnt); | |
emit Transfer(sender, _burnpoolWalletAddress, tokenToBeBurnt); | |
emit Transfer(sender, address(this), (totalTaxedToken.sub(tokenToBeBurnt))); | |
} else { | |
_balances[address(this)]=_balances[address(this)].add((totalTaxedToken)); | |
emit Transfer(sender, address(this), (totalTaxedToken)); | |
} | |
_balances[recipient] = _balances[recipient].add(taxedAmount); | |
_balances[sender]=_balances[sender].sub(amount); | |
emit Transfer(sender, recipient, taxedAmount); | |
} | |
function _feelessTransfer(address sender, address recipient, uint256 amount) private { | |
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); | |
_balances[recipient] = _balances[recipient].add(amount); | |
emit Transfer(sender, recipient, amount); | |
} | |
function _setMaxTxAmount(uint256 maxTxAmount) external onlyOwner() { | |
require(maxTxAmount > 0, "maxTxAmount should be greater than zero"); | |
_maxTxAmount = maxTxAmount; | |
emit SetMaxTxAmount(maxTxAmount); | |
} | |
//Calculates the token that should be taxed | |
function _calculateFee(uint256 amount, uint256 tax, uint256 taxPercent) private pure returns (uint256) { | |
return amount.mul(tax).mul(taxPercent).div(POINTS_DIVISOR); | |
} | |
function setTaxes(uint8 buyTaxValue, uint8 sellTaxVaule, uint8 transferTaxValue, uint8 burnFeeValue) external onlyOwner { | |
require(buyTaxValue <= 20, "to high fee"); | |
require(sellTaxVaule <= 20, "to high fee"); | |
require(transferTaxValue <= 20, "to high fee"); | |
require(burnFeeValue <= 20, "to high fee"); | |
buyTax = buyTaxValue; | |
sellTax = sellTaxVaule; | |
transferTax = transferTaxValue; | |
burnFee = burnFeeValue; | |
emit TaxesSet(buyTaxValue, sellTaxVaule, transferTaxValue, burnFeeValue); | |
} | |
function setEnabledBurnFee(bool _enabledBurnFee) external onlyOwner { | |
enableBurnFee = _enabledBurnFee; | |
emit SetEnabledFlag(_enabledBurnFee, TAX_TYPE.BURN); | |
} | |
function setEnableTaxOnlyForBuy(bool _enableTaxOnlyForBUy) external onlyOwner { | |
enableTaxOnlyForBuy = _enableTaxOnlyForBUy; | |
emit SetEnabledFlag(_enableTaxOnlyForBUy, TAX_TYPE.BUY); | |
} | |
function setExcludeEnabled(bool _excludeEnabled) external onlyOwner() { | |
excludeEnabled = _excludeEnabled; | |
emit SetExcludeEnabled(_excludeEnabled); | |
} | |
function isExcludedFromFee(address account) external view returns(bool) { | |
return _isExcludedFromFee[account]; | |
} | |
function excludeFromFee(address account) external onlyOwner() { | |
_isExcludedFromFee[account] = true; | |
emit ExcludeFromFee(account, true); | |
} | |
function includeInFee(address account) external onlyOwner() { | |
_isExcludedFromFee[account] = false; | |
emit ExcludeFromFee(account, false); | |
} | |
function addSwapPair(address _pairAddress) external onlyOwner { | |
require(!swapV2Pairs.contains(_pairAddress), 'add: SwapV2Pair already added'); | |
swapV2Pairs.add(_pairAddress); | |
emit AddNewSwapPair(_pairAddress); | |
} | |
function setEnableTaxOnlyForSell(bool _enableTaxOnlyForSell) external onlyOwner { | |
enableTaxOnlyForSell = _enableTaxOnlyForSell; | |
emit SetEnabledFlag(_enableTaxOnlyForSell, TAX_TYPE.SELL); | |
} | |
function setEnableTaxOnlyForTransfer(bool _enableTaxOnlyForTransfer) external onlyOwner { | |
enableTaxOnlyForTransfer = _enableTaxOnlyForTransfer; | |
emit SetEnabledFlag(_enableTaxOnlyForTransfer, TAX_TYPE.TRANSFER); | |
} | |
function withdrawFees(address _receiver) external onlyOwner { | |
uint256 feesAmount = _balances[address(this)]; | |
_balances[address(this)] = 0; | |
_balances[_receiver] = _balances[_receiver].add(feesAmount); | |
emit Transfer(address(this), _receiver, feesAmount); | |
} | |
function rescueFunds(address _token, address _receiver) external onlyOwner { | |
if (_token == address(0)) { | |
uint256 _amount = address(this).balance; | |
payable(_receiver).transfer(_amount); | |
} else { | |
uint256 _amount = IERC20(_token).balanceOf(address(this)); | |
IERC20(_token).transfer(_receiver, _amount); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment