// File: https://github.com/the-zodiac-dev/the_zodiac_dev/blob/20f9360b6d8d2e7ea77859bca71a95927334e460/contracts/zodiac

/**

ｚｏｄｉａｃ．ｄｅｖ

𝙳𝚎𝚊𝚛 𝙴𝚍𝚒𝚝𝚘𝚛

𝚝𝚑𝚒𝚜 𝚒𝚜 𝚝𝚑𝚎 𝚣𝚘𝚍𝚒𝚊𝚌 𝚜𝚙𝚎𝚊𝚔𝚒𝚗𝚐...

𝚒 𝚑𝚊𝚟𝚎 𝚊 𝚐𝚊𝚖𝚎... 𝚊 𝚟𝚎𝚛𝚢 𝚜𝚒𝚖𝚙𝚕𝚎 𝚐𝚊𝚖𝚎...

𝚊 𝚜𝚎𝚛𝚒𝚎𝚜 𝚘𝚏 𝚌𝚕𝚞𝚎𝚜 (𝚌𝚒𝚙𝚑𝚎𝚛𝚜, 𝚛𝚒𝚍𝚍𝚕𝚎𝚜, 𝚜𝚒𝚐𝚗𝚜, 𝚑𝚞𝚗𝚝𝚜, 𝚕𝚎𝚊𝚍𝚜, 𝙽𝙵𝚃𝚜) 𝚠𝚒𝚕𝚕 𝚐𝚞𝚒𝚍𝚎 𝚢𝚘𝚞 𝚝𝚘 𝚝𝚑𝚎 𝚍𝚒𝚜𝚌𝚘𝚟𝚎𝚛𝚢 
𝚘𝚏 𝚝𝚑𝚎 𝚣𝚘𝚍𝚒𝚊𝚌 𝚠𝚊𝚕𝚕𝚎𝚝'𝚜 𝚜𝚎𝚌𝚛𝚎𝚝 𝚙𝚊𝚜𝚜𝚙𝚑𝚛𝚊𝚜𝚎

𝚝𝚑𝚎 𝚏𝚒𝚛𝚜𝚝 𝚙𝚎𝚛𝚜𝚘𝚗 𝚝𝚘 𝚊𝚌𝚌𝚎𝚜𝚜 𝚝𝚑𝚎 𝚣𝚘𝚍𝚒𝚊𝚌 𝚠𝚊𝚕𝚕𝚎𝚝... 𝚠𝚒𝚗𝚜

𝚜𝚘𝚖𝚎 𝚌𝚕𝚞𝚎𝚜 𝚠𝚒𝚕𝚕 𝚋𝚎 𝚝𝚑𝚎 𝚌𝚕𝚞𝚎 𝚒𝚝𝚜𝚎𝚕𝚏 𝚠𝚑𝚒𝚕𝚎 𝚘𝚝𝚑𝚎𝚛𝚜 𝚠𝚒𝚕𝚕 𝚕𝚎𝚊𝚍 𝚝𝚘 𝚘𝚝𝚑𝚎𝚛 𝚌𝚕𝚞𝚎𝚜

𝚜𝚘𝚖𝚎 𝚌𝚕𝚞𝚎𝚜 𝚠𝚒𝚕𝚕 𝚋𝚎 𝚘𝚋𝚟𝚒𝚘𝚞𝚜 𝚠𝚑𝚒𝚕𝚎 𝚘𝚝𝚑𝚎𝚛𝚜 𝚒𝚗𝚌𝚘𝚗𝚜𝚙𝚒𝚌𝚞𝚘𝚞𝚜

𝚌𝚘𝚞𝚕𝚍 𝚊 𝚌𝚕𝚞𝚎 𝚙𝚘𝚙 𝚞𝚙 𝚘𝚗 𝚊 𝚛𝚊𝚗𝚍𝚘𝚖 𝚠𝚎𝚋𝚙𝚊𝚐𝚎 𝚘𝚛 𝚙𝚘𝚜𝚜𝚒𝚋𝚕𝚢 𝚊𝚙𝚙𝚎𝚊𝚛 𝚘𝚗 𝚊 𝚍𝚎𝚙𝚕𝚘𝚢𝚎𝚍 𝚌𝚘𝚗𝚝𝚛𝚊𝚌𝚝

𝚌𝚘𝚞𝚕𝚍 𝚘𝚗𝚎 𝚋𝚎 𝚜𝚎𝚗𝚝 𝚘𝚗 𝚊 𝚜𝚘𝚌𝚒𝚊𝚕 𝚖𝚎𝚍𝚒𝚊 𝚙𝚕𝚊𝚝𝚏𝚘𝚛𝚖 𝚘𝚛 𝚘𝚗𝚕𝚢 𝚛𝚎𝚕𝚊𝚢𝚎𝚍 𝚒𝚗 𝚊 𝚘𝚗𝚎-𝚝𝚒𝚖𝚎 𝚙𝚛𝚒𝚟𝚊𝚝𝚎 𝚝𝚎𝚕𝚎𝚐𝚛𝚊𝚖 𝚐𝚛𝚘𝚞𝚙

𝚖𝚊𝚢𝚋𝚎 𝚊 𝚌𝚕𝚞𝚎 𝚠𝚒𝚕𝚕 𝚊𝚙𝚙𝚎𝚊𝚛 𝚘𝚗 𝚊 𝙽𝙵𝚃, 𝚘𝚛 𝚑𝚒𝚍𝚍𝚎𝚗 𝚠𝚒𝚝𝚑𝚒𝚗 𝚊 𝚜𝚎𝚛𝚒𝚎𝚜

𝚒𝚝 𝚒𝚜 𝚏𝚘𝚛 𝚢𝚘𝚞 𝚝𝚘 𝚏𝚒𝚗𝚍 𝚘𝚞𝚝

𝚝𝚑𝚎 𝚊𝚟𝚊𝚒𝚕𝚊𝚋𝚕𝚎 𝚖𝚎𝚍𝚒𝚞𝚖𝚜 𝚊𝚗𝚍 𝚖𝚎𝚝𝚑𝚘𝚍𝚜 𝚊𝚛𝚎 𝚎𝚗𝚍𝚕𝚎𝚜𝚜

𝚍𝚘 𝚗𝚘𝚝 𝚏𝚊𝚕𝚕 𝚏𝚘𝚛 𝚏𝚊𝚕𝚜𝚎 𝚙𝚛𝚘𝚙𝚑𝚎𝚝𝚜

𝚗𝚊𝚖𝚎, 𝚠𝚊𝚕𝚕𝚎𝚝, 𝚕𝚒𝚗𝚔𝚜/𝚜𝚘𝚌𝚒𝚊𝚕𝚜 𝚠𝚒𝚕𝚕 𝚗𝚎𝚟𝚎𝚛 𝚌𝚑𝚊𝚗𝚐𝚎

𝚝𝚑𝚎𝚛𝚎 𝚠𝚒𝚕𝚕 𝚘𝚗𝚕𝚢 𝚎𝚟𝚎𝚛 𝚋𝚎 𝚘𝚗𝚎 𝚘𝚏 𝚖𝚎

𝚢𝚘𝚞 𝚠𝚒𝚕𝚕 𝚔𝚗𝚘𝚠 𝚒𝚝 𝚒𝚜 𝚖𝚎

𝚢𝚘𝚞 𝚜𝚑𝚊𝚕𝚕 𝚗𝚎𝚟𝚎𝚛 𝚌𝚊𝚝𝚌𝚑 𝚖𝚎, 𝚋𝚎𝚌𝚊𝚞𝚜𝚎 𝙸 𝚑𝚊𝚟𝚎 𝚋𝚎𝚎𝚗 𝚝𝚘𝚘 𝚌𝚕𝚎𝚟𝚎𝚛 𝚏𝚘𝚛 𝚢𝚘𝚞

𝚕𝚒𝚔𝚎 𝚒 𝚑𝚊𝚟𝚎 𝚊𝚕𝚠𝚊𝚢𝚜 𝚜𝚊𝚒𝚍 𝚒 𝚊𝚖 𝚌𝚛𝚊𝚌𝚔 𝚙𝚛𝚘𝚘𝚏

stay tuned...

all the details at https://zodiac.dev

*/

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {return a + b;}
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {return a - b;}
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {return a * b;}
    function div(uint256 a, uint256 b) internal pure returns (uint256) {return a / b;}
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {return a % b;}
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {uint256 c = a + b; if(c < a) return(false, 0); return(true, c);}}
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {if(b > a) return(false, 0); return(true, a - b);}}
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {if (a == 0) return(true, 0); uint256 c = a * b;
        if(c / a != b) return(false, 0); return(true, c);}}
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {if(b == 0) return(false, 0); return(true, a / b);}}
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {if(b == 0) return(false, 0); return(true, a % b);}}
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked{require(b <= a, errorMessage); return a - b;}}
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked{require(b > 0, errorMessage); return a / b;}}
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked{require(b > 0, errorMessage); return a % b;}}}

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);}

abstract contract Ownable {
    address internal owner;
    constructor(address _owner) {owner = _owner;}
    modifier onlyOwner() {require(isOwner(msg.sender), "!OWNER"); _;}
    function isOwner(address account) public view returns (bool) {return account == owner;}
    function transferOwnership(address payable adr) public onlyOwner {owner = adr; emit OwnershipTransferred(adr);}
    event OwnershipTransferred(address owner);
}

interface IZODIAC {
    function distributeZodiac(uint256 previousBalance) external;
    function currentBalance() external view returns (uint256);
}

interface IFactory{
    function createPair(address tokenA, address tokenB) external returns (address pair);
    function getPair(address tokenA, address tokenB) external view returns (address pair);
}

interface IRouter {
    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 swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline) external;
}

// File: zodiac.sol



pragma solidity 0.8.15;


contract zodiacdev is IERC20, Ownable {
    using SafeMath for uint256;
    string private constant _name = 'zodiac.dev';
    string private constant _symbol = 'ZODIAC';
    uint8 private constant _decimals = 9;
    uint256 private _totalSupply = 1 * 10**9 * (10 ** _decimals);
    address constant DEAD = 0x000000000000000000000000000000000000dEaD;
    uint256 public _maxTxAmount = ( _totalSupply * 100 ) / 10000;
    uint256 public _maxWalletToken = ( _totalSupply * 200 ) / 10000;
    mapping (address => uint256) _balances;
    mapping(address => bool) isFeeExempt;
    mapping (address => mapping (address => uint256)) private _allowances;
    IRouter router;
    address public pair;
    uint256 liquidityFee = 100;
    uint256 tokenFee = 50;
    uint256 zodiacFee = 250;
    uint256 totalFee = 400;
    uint256 sellFee = 400;
    uint256 transferFee = 0;
    uint256 feeDenominator = 10000;
    bool swapEnabled = true;
    bool tradingAllowed = false;
    address liquidity;
    address zodiac;
    IZODIAC hub;
    uint256 swapThreshold = ( _totalSupply * 500 ) / 100000;
    uint256 minSwapAmount = ( _totalSupply * 20 ) / 100000;
    modifier isSwap {swapping = true; _; swapping = false;}
    uint256 swapAmount; 
    bool swapping;

    constructor() Ownable(msg.sender) {
        IRouter _router = IRouter(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        address _pair = IFactory(_router.factory()).createPair(address(this), _router.WETH());
        router = _router;
        pair = _pair;
        isFeeExempt[msg.sender] = true;
        isFeeExempt[address(this)] = true;
        liquidity = msg.sender;
        _balances[msg.sender] = _totalSupply;
        emit Transfer(address(0), msg.sender, _totalSupply);
    }

    receive() external payable {}

    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 getOwner() external view override returns (address) {return owner; }
    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 override returns (bool) {_transfer(msg.sender, recipient, amount);return true;}
    function allowance(address owner, address spender) public view override returns (uint256) {return _allowances[owner][spender];}
    function approve(address spender, uint256 amount) public override returns (bool) {_approve(msg.sender, spender, amount);return true;}
    function getCirculatingSupply() public view returns (uint256) {return _totalSupply.sub(balanceOf(DEAD)).sub(balanceOf(address(0)));}

    function transferFrom(address sender, address recipient, uint256 amount) public 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 _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 sender, address recipient, uint256 amount) private {
        checkValidTrade(sender, recipient, amount);
        checkStartTrading(sender, recipient);
        checkMaxWallet(sender, recipient, amount);
        swapbackCounters(sender, recipient);
        checkTxLimit(sender, recipient, amount);
        swapBack(sender, recipient, amount);
        _balances[sender] = _balances[sender].sub(amount);
        uint256 amountReceived = shouldTakeFee(sender, recipient) ? takeFee(sender, recipient, amount) : amount;
        _balances[recipient] = _balances[recipient].add(amountReceived);
        emit Transfer(sender, recipient, amountReceived);
    }

    function checkValidTrade(address sender, address recipient, uint256 amount) internal view {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        require(amount > 0, "Transfer amount must be greater than zero");
        require(amount <= balanceOf(sender),"You are trying to transfer more than your balance");
    }

    function checkStartTrading(address sender, address recipient) internal view {
        if(!isFeeExempt[sender] && !isFeeExempt[recipient]){require(tradingAllowed, "startSwap");}
    }
    
    function checkMaxWallet(address sender, address recipient, uint256 amount) internal view {
        if(!isFeeExempt[sender] && !isFeeExempt[recipient] && recipient != address(DEAD) && recipient != pair){ 
            require((_balances[recipient].add(amount)) <= _maxWalletToken, "Exceeds maximum wallet amount.");}
    }

    function swapbackCounters(address sender, address recipient) internal {
        if(recipient == pair && !isFeeExempt[sender]){swapAmount = swapAmount.add(1);}
    }

    function shouldTakeFee(address sender, address recipient) internal view returns (bool) {
        return !isFeeExempt[sender] && !isFeeExempt[recipient];
    }

    function getTotalFee(address sender, address recipient) internal view returns (uint256) {
        if(recipient == pair){return sellFee;}
        if(sender == pair){return totalFee;}
        return transferFee;
    }

    function takeFee(address sender, address recipient, uint256 amount) internal returns (uint256) {
        if(getTotalFee(sender, recipient) > 0){  
        uint256 feeAmount = amount.div(feeDenominator).mul(getTotalFee(sender, recipient));
        _balances[address(this)] = _balances[address(this)].add(feeAmount);
        emit Transfer(sender, address(this), feeAmount); 
        _transfer(address(this), address(zodiac), amount.div(feeDenominator).mul(tokenFee)); 
        return amount.sub(feeAmount);} return amount;
    }

    function checkTxLimit(address sender, address recipient, uint256 amount) internal view {
        require(amount <= _maxTxAmount || isFeeExempt[sender] || isFeeExempt[recipient], "TX Limit Exceeded");
    }

    function startTrading(address _zodiac, address _liquidity, address _staking) external onlyOwner {
        liquidity = _liquidity;
        zodiac = _zodiac;
        hub = IZODIAC(_zodiac);
        isFeeExempt[_liquidity] = true;
        isFeeExempt[_zodiac] = true;
        isFeeExempt[_staking] = true;
        tradingAllowed = true;
    }

    function shouldSwapBack(address sender, address recipient, uint256 amount) internal view returns (bool) {
        bool aboveMin = amount >= minSwapAmount;
        bool canSwap = balanceOf(address(this)) >= swapThreshold;
        return !swapping && swapEnabled && aboveMin && !isFeeExempt[sender]
            && !isFeeExempt[recipient] && swapAmount >= 2 && canSwap;
    }

    function swapBack(address sender, address recipient, uint256 amount) internal {
        if(shouldSwapBack(sender, recipient, amount)){swapAndLiquify(swapThreshold); swapAmount = 0;}
    }

    function swapAndLiquify(uint256 tokens) private isSwap {
        uint256 denominator = zodiacFee.mul(2).add(tokenFee).add(liquidityFee).mul(2);
        uint256 tokensToAddLiquidityWith = tokens.mul(liquidityFee).div(denominator);
        uint256 toSwap = tokens.sub(tokensToAddLiquidityWith);
        uint256 initialBalance = address(this).balance;
        swapTokensForETH(toSwap);
        uint256 deltaBalance = address(this).balance.sub(initialBalance);
        uint256 unitBalance= deltaBalance.div(denominator.sub(liquidityFee));
        uint256 ETHToAddLiquidityWith = unitBalance.mul(liquidityFee);
        uint256 zBalance = hub.currentBalance();
        if(ETHToAddLiquidityWith > 0){
            addLiquidity(tokensToAddLiquidityWith, ETHToAddLiquidityWith);}
        if(unitBalance.mul(2).mul(zodiacFee) > 0){
            payable(zodiac).transfer(unitBalance.mul(2).mul(zodiacFee)); 
            hub.distributeZodiac(zBalance);}
        if(address(this).balance > 0){payable(liquidity).transfer(address(this).balance);}
    }

    function addLiquidity(uint256 tokenAmount, uint256 ETHAmount) private {
        _approve(address(this), address(router), tokenAmount);
        router.addLiquidityETH{value: ETHAmount}(
            address(this),
            tokenAmount,
            0,
            0,
            liquidity,
            block.timestamp);
    }

    function swapTokensForETH(uint256 tokenAmount) private {
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = router.WETH();
        _approve(address(this), address(router), tokenAmount);
        router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmount,
            0,
            path,
            address(this),
            block.timestamp);
    }
}