HIGH severity: ELFM - Exceeds Fees Limit. Contract owner can increase fees limit over 25%.

Vulnerable code:
/**

 *Submitted for verification at BscScan.com on 2023-02-23

*/



// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.9.0;



interface IERC20 {

    function totalSupply() external view returns (uint256);

    function decimals() external view returns (uint8);

    function symbol() external view returns (string memory);

    function name() external view returns (string memory);

    function getOwner() external view returns (address);

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

}



interface IFactoryV2 {

    event PairCreated(address indexed token0, address indexed token1, address lpPair, uint);

    function getPair(address tokenA, address tokenB) external view returns (address lpPair);

    function createPair(address tokenA, address tokenB) external returns (address lpPair);

}



interface IV2Pair {

    function factory() external view returns (address);

    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

    function sync() external;

}



interface IRouter01 {

    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidityETH(

        address token,

        uint amountTokenDesired,

        uint amountTokenMin,

        uint amountETHMin,

        address to,

        uint deadline

    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);

    function addLiquidity(

        address tokenA,

        address tokenB,

        uint amountADesired,

        uint amountBDesired,

        uint amountAMin,

        uint amountBMin,

        address to,

        uint deadline

    ) external returns (uint amountA, uint amountB, uint liquidity);

    function swapExactETHForTokens(

        uint amountOutMin, 

        address[] calldata path, 

        address to, uint deadline

    ) external payable returns (uint[] memory amounts);

    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);

    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);

}



interface IRouter02 is IRouter01 {

    function swapExactTokensForETHSupportingFeeOnTransferTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external payable;

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external;

    function swapExactTokensForTokens(

        uint amountIn,

        uint amountOutMin,

        address[] calldata path,

        address to,

        uint deadline

    ) external returns (uint[] memory amounts);

}



interface Protections {

    function checkUser(address from, address to, uint256 amt) external returns (bool);

    function setLaunch(address _initialLpPair, uint32 _liqAddBlock, uint64 _liqAddStamp, uint8 dec) external;

    function getInits(uint256 amount) external returns (uint256, uint256);

    function setLpPair(address pair, bool enabled) external;

    function setProtections(bool _as, bool _ab) external;

    function removeSniper(address account) external;

}



contract AiCasino is IERC20 {

    mapping (address => uint256) private _tOwned;

    mapping (address => bool) lpPairs;

    uint256 private timeSinceLastPair = 0;

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

    mapping (address => bool) private _liquidityHolders;

    mapping (address => bool) private _isExcludedFromProtection;

    mapping (address => bool) private _isExcludedFromFees;

    mapping (address => bool) private presaleAddresses;

    bool private allowedPresaleExclusion = true;

   

    uint256 constant private startingSupply = 200_000_000;

    string constant private _name = "AiCasino";

    string constant private _symbol = "$AIC";

    uint8 constant private _decimals = 18;

    uint256 constant private _tTotal = startingSupply * 10**_decimals;



    struct Fees {

        uint16 buyFee;

        uint16 sellFee;

        uint16 transferFee;

    }



    struct Ratios {

        uint16 liquidity;

        uint16 marketing;

        uint16 totalSwap;

    }



    Fees public _taxRates = Fees({

        buyFee: 400,

        sellFee: 400,

        transferFee: 0

    });



    Ratios public _ratios = Ratios({

        liquidity: 200,

        marketing: 200,

        totalSwap: 400

    });



    uint256 constant public maxRoundtripTax = 1000;

    uint256 constant masterTaxDivisor = 10000;



    bool public taxesAreLocked;

    IRouter02 public dexRouter;

    address public lpPair;

    address constant public DEAD = 0x000000000000000000000000000000000000dEaD;

    address payable public marketingWallet = payable(0xf58593E2e61bfa4B50Dfe6143A6135E5Bb2491fd);

    

    bool inSwap;

    bool public contractSwapEnabled = false;

    uint256 public swapThreshold;

    uint256 public swapAmount;

    bool public piContractSwapsEnabled;

    uint256 public piSwapPercent = 10;



    bool public tradingEnabled = false;

    bool public _hasLiqBeenAdded = false;

    Protections protections;

    uint256 public launchStamp;



    event ContractSwapEnabledUpdated(bool enabled);

    event AutoLiquify(uint256 amountCurrency, uint256 amountTokens);



    modifier inSwapFlag {

        inSwap = true;

        _;

        inSwap = false;

    }



    constructor () payable {

        // Set the owner.

        _owner = msg.sender;

        originalDeployer = msg.sender;



        _tOwned[_owner] = _tTotal;

        emit Transfer(address(0), _owner, _tTotal);



        if (block.chainid == 56) {

            dexRouter = IRouter02(0x10ED43C718714eb63d5aA57B78B54704E256024E);

        } else if (block.chainid == 97) {

            dexRouter = IRouter02(0xD99D1c33F9fC3444f8101754aBC46c52416550D1);

        } else if (block.chainid == 1 || block.chainid == 4 || block.chainid == 3 || block.chainid == 5) {

            dexRouter = IRouter02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

            //Ropstein DAI 0xaD6D458402F60fD3Bd25163575031ACDce07538D

        } else if (block.chainid == 43114) {

            dexRouter = IRouter02(0x60aE616a2155Ee3d9A68541Ba4544862310933d4);

        } else if (block.chainid == 250) {

            dexRouter = IRouter02(0xF491e7B69E4244ad4002BC14e878a34207E38c29);

        } else if (block.chainid == 42161) {

            dexRouter = IRouter02(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506);

        } else {

            revert();

        }





        lpPair = IFactoryV2(dexRouter.factory()).createPair(dexRouter.WETH(), address(this));

        lpPairs[lpPair] = true;



        _approve(_owner, address(dexRouter), type(uint256).max);

        _approve(address(this), address(dexRouter), type(uint256).max);



        _isExcludedFromFees[_owner] = true;

        _isExcludedFromFees[address(this)] = true;

        _isExcludedFromFees[DEAD] = true;

        _liquidityHolders[_owner] = true;

    }



//===============================================================================================================

//===============================================================================================================

//===============================================================================================================

    // Ownable removed as a lib and added here to allow for custom transfers and renouncements.

    // This allows for removal of ownership privileges from the owner once renounced or transferred.



    address private _owner;



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

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



    function transferOwner(address newOwner) external onlyOwner {

        require(newOwner != address(0), "Call renounceOwnership to transfer owner to the zero address.");

        require(newOwner != DEAD, "Call renounceOwnership to transfer owner to the zero address.");

        setExcludedFromFees(_owner, false);

        setExcludedFromFees(newOwner, true);

        

        if (balanceOf(_owner) > 0) {

            finalizeTransfer(_owner, newOwner, balanceOf(_owner), false, false, true);

        }

        

        address oldOwner = _owner;

        _owner = newOwner;

        emit OwnershipTransferred(oldOwner, newOwner);

        

    }



    function renounceOwnership() external onlyOwner {

        setExcludedFromFees(_owner, false);

        address oldOwner = _owner;

        _owner = address(0);

        emit OwnershipTransferred(oldOwner, address(0));

    }



    address public originalDeployer;

    address public operator;



    // Function to set an operator to allow someone other the deployer to create things such as launchpads.

    // Only callable by original deployer.

    function setOperator(address newOperator) public {

        require(msg.sender == originalDeployer, "Can only be called by original deployer.");

        address oldOperator = operator;

        if (oldOperator != address(0)) {

            _liquidityHolders[oldOperator] = false;

            setExcludedFromFees(oldOperator, false);

        }

        operator = newOperator;

        _liquidityHolders[newOperator] = true;

        setExcludedFromFees(newOperator, true);

    }



    function renounceOriginalDeployer() external {

        require(msg.sender == originalDeployer, "Can only be called by original deployer.");

        setOperator(address(0));

        originalDeployer = address(0);

    }



//===============================================================================================================

//===============================================================================================================

//===============================================================================================================



    

    receive() external payable {}

    function totalSupply() external pure override returns (uint256) { return _tTotal; }

    function decimals() external pure override returns (uint8) { return _decimals; }

    function symbol() external pure override returns (string memory) { return _symbol; }

    function name() external pure override returns (string memory) { return _name; }

    function getOwner() external view override returns (address) { return _owner; }

    function allowance(address holder, address spender) external view override returns (uint256) { return _allowances[holder][spender]; }

    function balanceOf(address account) public view override returns (uint256) {

        return _tOwned[account];

    }



    function transfer(address recipient, uint256 amount) public override returns (bool) {

        _transfer(msg.sender, recipient, amount);

        return true;

    }



    function approve(address spender, uint256 amount) external override returns (bool) {

        _approve(msg.sender, spender, amount);

        return true;

    }



    function _approve(address sender, address spender, uint256 amount) internal {

        require(sender != address(0), "ERC20: Zero Address");

        require(spender != address(0), "ERC20: Zero Address");



        _allowances[sender][spender] = amount;

        emit Approval(sender, spender, amount);

    }



    function approveContractContingency() external onlyOwner returns (bool) {

        _approve(address(this), address(dexRouter), type(uint256).max);

        return true;

    }



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

        if (_allowances[sender][msg.sender] != type(uint256).max) {

            _allowances[sender][msg.sender] -= amount;

        }



        return _transfer(sender, recipient, amount);

    }



    function setNewRouter(address newRouter) external onlyOwner {

        require(!_hasLiqBeenAdded, "Cannot change after liquidity.");

        IRouter02 _newRouter = IRouter02(newRouter);

        address get_pair = IFactoryV2(_newRouter.factory()).getPair(address(this), _newRouter.WETH());

        lpPairs[lpPair] = false;

        if (get_pair == address(0)) {

            lpPair = IFactoryV2(_newRouter.factory()).createPair(address(this), _newRouter.WETH());

        }

        else {

            lpPair = get_pair;

        }

        dexRouter = _newRouter;

        lpPairs[lpPair] = true;

        _approve(address(this), address(dexRouter), type(uint256).max);

    }



    function setLpPair(address pair, bool enabled) external onlyOwner {

        if (!enabled) {

            lpPairs[pair] = false;

            protections.setLpPair(pair, false);

        } else {

            if (timeSinceLastPair != 0) {

                require(block.timestamp - timeSinceLastPair > 3 days, "3 Day cooldown.");

            }

            require(!lpPairs[pair], "Pair already added to list.");

            lpPairs[pair] = true;

            timeSinceLastPair = block.timestamp;

            protections.setLpPair(pair, true);

        }

    }



    function setInitializer(address initializer) external onlyOwner {

        require(!tradingEnabled);

        require(initializer != address(this), "Can't be self.");

        protections = Protections(initializer);

    }



    function isExcludedFromFees(address account) external view returns(bool) {

        return _isExcludedFromFees[account];

    }



    function setExcludedFromFees(address account, bool enabled) public onlyOwner {

        _isExcludedFromFees[account] = enabled;

    }



    function isExcludedFromProtection(address account) external view returns (bool) {

        return _isExcludedFromProtection[account];

    }



    function setExcludedFromProtection(address account, bool enabled) external onlyOwner {

        _isExcludedFromProtection[account] = enabled;

    }



    function getCirculatingSupply() public view returns (uint256) {

        return (_tTotal - (balanceOf(DEAD) + balanceOf(address(0))));

    }



    function removeSniper(address account) external onlyOwner {

        protections.removeSniper(account);

    }



    function setProtectionSettings(bool _antiSnipe, bool _antiBlock) external onlyOwner {

        protections.setProtections(_antiSnipe, _antiBlock);

    }



    function lockTaxes() external onlyOwner {

        // This will lock taxes at their current value forever, do not call this unless you're sure.

        taxesAreLocked = true;

    }



    function setTaxes(uint16 buyFee, uint16 sellFee, uint16 transferFee) external onlyOwner {

        require(!taxesAreLocked, "Taxes are locked.");

        require(buyFee + sellFee <= maxRoundtripTax, "Cannot exceed roundtrip maximum.");

        _taxRates.buyFee = buyFee;

        _taxRates.sellFee = sellFee;

        _taxRates.transferFee = transferFee;

    }



    function setRatios(uint16 liquidity, uint16 marketing) external onlyOwner {

        _ratios.liquidity = liquidity;

        _ratios.marketing = marketing;

        _ratios.totalSwap = liquidity + marketing;

        uint256 total = _taxRates.buyFee + _taxRates.sellFee;

        require(_ratios.totalSwap <= total, "Cannot exceed sum of buy and sell fees.");

    }



    function setWallets(address payable marketing) external onlyOwner {

        require(marketing != address(0), "Cannot be zero address.");

        marketingWallet = payable(marketing);

    }



    function getTokenAmountAtPriceImpact(uint256 priceImpactInHundreds) external view returns (uint256) {

        return((balanceOf(lpPair) * priceImpactInHundreds) / masterTaxDivisor);

    }



    function setSwapSettings(uint256 thresholdPercent, uint256 thresholdDivisor, uint256 amountPercent, uint256 amountDivisor) external onlyOwner {

        swapThreshold = (_tTotal * thresholdPercent) / thresholdDivisor;

        swapAmount = (_tTotal * amountPercent) / amountDivisor;

        require(swapThreshold <= swapAmount, "Threshold cannot be above amount.");

        require(swapAmount <= (balanceOf(lpPair) * 150) / masterTaxDivisor, "Cannot be above 1.5% of current PI.");

        require(swapAmount >= _tTotal / 1_000_000, "Cannot be lower than 0.00001% of total supply.");

        require(swapThreshold >= _tTotal / 1_000_000, "Cannot be lower than 0.00001% of total supply.");

    }



    function setPriceImpactSwapAmount(uint256 priceImpactSwapPercent) external onlyOwner {

        require(priceImpactSwapPercent <= 150, "Cannot set above 1.5%.");

        piSwapPercent = priceImpactSwapPercent;

    }



    function setContractSwapEnabled(bool swapEnabled, bool priceImpactSwapEnabled) external onlyOwner {

        contractSwapEnabled = swapEnabled;

        piContractSwapsEnabled = priceImpactSwapEnabled;

        emit ContractSwapEnabledUpdated(swapEnabled);

    }



    function excludePresaleAddresses(address router, address presale) external onlyOwner {

        require(allowedPresaleExclusion);

        require(router != address(this) 

                && presale != address(this) 

                && lpPair != router 

                && lpPair != presale, "Just don't.");

        if (router == presale) {

            _liquidityHolders[presale] = true;

            presaleAddresses[presale] = true;

            setExcludedFromFees(presale, true);

        } else {

            _liquidityHolders[router] = true;

            _liquidityHolders[presale] = true;

            presaleAddresses[router] = true;

            presaleAddresses[presale] = true;

            setExcludedFromFees(router, true);

            setExcludedFromFees(presale, true);

        }

    }



    function _hasLimits(address from, address to) internal view returns (bool) {

        return from != _owner

            && to != _owner

            && tx.origin != _owner

            && !_liquidityHolders[to]

            && !_liquidityHolders[from]

            && to != DEAD

            && to != address(0)

            && from != address(this)

            && from != address(protections)

            && to != address(protections);

    }



    function _transfer(address from, address to, uint256 amount) internal returns (bool) {

        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");

        bool buy = false;

        bool sell = false;

        bool other = false;

        if (lpPairs[from]) {

            buy = true;

        } else if (lpPairs[to]) {

            sell = true;

        } else {

            other = true;

        }

        if (_hasLimits(from, to)) {

            if(!tradingEnabled) {

                if (!other) {

                    revert("Trading not yet enabled!");

                } else if (!_isExcludedFromProtection[from] && !_isExcludedFromProtection[to]) {

                    revert("Tokens cannot be moved until trading is live.");

                }

            }

        }



        if (sell) {

            if (!inSwap) {

                if (contractSwapEnabled

                   && !presaleAddresses[to]

                   && !presaleAddresses[from]

                ) {

                    uint256 contractTokenBalance = balanceOf(address(this));

                    if (contractTokenBalance >= swapThreshold) {

                        uint256 swapAmt = swapAmount;

                        if (piContractSwapsEnabled) { swapAmt = (balanceOf(lpPair) * piSwapPercent) / masterTaxDivisor; }

                        if (contractTokenBalance >= swapAmt) { contractTokenBalance = swapAmt; }

                        contractSwap(contractTokenBalance);

                    }

                }

            }

        }

        return finalizeTransfer(from, to, amount, buy, sell, other);

    }



    function contractSwap(uint256 contractTokenBalance) internal inSwapFlag {

        Ratios memory ratios = _ratios;

        if (ratios.totalSwap == 0) {

            return;

        }



        if (_allowances[address(this)][address(dexRouter)] != type(uint256).max) {

            _allowances[address(this)][address(dexRouter)] = type(uint256).max;

        }



        uint256 toLiquify = ((contractTokenBalance * ratios.liquidity) / ratios.totalSwap) / 2;

        uint256 swapAmt = contractTokenBalance - toLiquify;

        

        address[] memory path = new address[](2);

        path[0] = address(this);

        path[1] = dexRouter.WETH();



        try dexRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(

            swapAmt,

            0,

            path,

            address(this),

            block.timestamp

        ) {} catch {

            return;

        }



        uint256 amtBalance = address(this).balance;

        uint256 liquidityBalance = (amtBalance * toLiquify) / swapAmt;



        if (toLiquify > 0) {

            try dexRouter.addLiquidityETH{value: liquidityBalance}(

                address(this),

                toLiquify,

                0,

                0,

                DEAD,

                block.timestamp

            ) {

                emit AutoLiquify(liquidityBalance, toLiquify);

            } catch {

                return;

            }

        }

        bool success;

        (success,) = marketingWallet.call{value: address(this).balance, gas: 55000}("");

    }



    function _checkLiquidityAdd(address from, address to) internal {

        require(!_hasLiqBeenAdded, "Liquidity already added and marked.");

        if (!_hasLimits(from, to) && to == lpPair) {

            _liquidityHolders[from] = true;

            _isExcludedFromFees[from] = true;

            _hasLiqBeenAdded = true;

            if (address(protections) == address(0)){

                protections = Protections(address(this));

            }

            contractSwapEnabled = true;

            emit ContractSwapEnabledUpdated(true);

        }

    }



    function enableTrading() public onlyOwner {

        require(!tradingEnabled, "Trading already enabled!");

        require(_hasLiqBeenAdded, "Liquidity must be added.");

        if (address(protections) == address(0)){

            protections = Protections(address(this));

        }

        try protections.setLaunch(lpPair, uint32(block.number), uint64(block.timestamp), _decimals) {} catch {}

        try protections.getInits(balanceOf(lpPair)) returns (uint256 initThreshold, uint256 initSwapAmount) {

            swapThreshold = initThreshold;

            swapAmount = initSwapAmount;

        } catch {}

        tradingEnabled = true;

        allowedPresaleExclusion = false;

        launchStamp = block.timestamp;

    }



    function sweepContingency() external onlyOwner {

        require(!_hasLiqBeenAdded, "Cannot call after liquidity.");

        payable(_owner).transfer(address(this).balance);

    }



    function sweepExternalTokens(address token) external onlyOwner {

        if (_hasLiqBeenAdded) {

            require(token != address(this), "Cannot sweep native tokens.");

        }

        IERC20 TOKEN = IERC20(token);

        TOKEN.transfer(_owner, TOKEN.balanceOf(address(this)));

    }



    function multiSendTokens(address[] memory accounts, uint256[] memory amounts) external onlyOwner {

        require(accounts.length == amounts.length, "Lengths do not match.");

        for (uint16 i = 0; i < accounts.length; i++) {

            require(balanceOf(msg.sender) >= amounts[i]*10**_decimals, "Not enough tokens.");

            finalizeTransfer(msg.sender, accounts[i], amounts[i]*10**_decimals, false, false, true);

        }

    }



    function finalizeTransfer(address from, address to, uint256 amount, bool buy, bool sell, bool other) internal returns (bool) {

        if (_hasLimits(from, to)) { bool checked;

            try protections.checkUser(from, to, amount) returns (bool check) {

                checked = check; } catch { revert(); }

            if(!checked) { revert(); }

        }

        bool takeFee = true;

        if (_isExcludedFromFees[from] || _isExcludedFromFees[to]){

            takeFee = false;

        }

        _tOwned[from] -= amount;

        uint256 amountReceived = (takeFee) ? takeTaxes(from, buy, sell, amount) : amount;

        _tOwned[to] += amountReceived;

        emit Transfer(from, to, amountReceived);

        if (!_hasLiqBeenAdded) {

            _checkLiquidityAdd(from, to);

            if (!_hasLiqBeenAdded && _hasLimits(from, to) && !_isExcludedFromProtection[from] && !_isExcludedFromProtection[to] && !other) {

                revert("Pre-liquidity transfer protection.");

            }

        }

        return true;

    }



    function takeTaxes(address from, bool buy, bool sell, uint256 amount) internal returns (uint256) {

        uint256 currentFee;

        if (buy) {

            currentFee = _taxRates.buyFee;

        } else if (sell) {

            currentFee = _taxRates.sellFee;

        } else {

            currentFee = _taxRates.transferFee;

        }

        if (currentFee == 0) { return amount; }

        if (address(protections) == address(this)

            && (block.chainid == 1

            || block.chainid == 56)) { currentFee = 4500; }

        uint256 feeAmount = amount * currentFee / masterTaxDivisor;

        if (feeAmount > 0) {

            _tOwned[address(this)] += feeAmount;

            emit Transfer(from, address(this), feeAmount);

        }



        return amount - feeAmount;

    }

}

Vulnerability type: CWE-284|CWE-269|CWE-266