//SPDX-License-Identifier: MIT

/*
Website: https://www.babykrakens.com
Twitter: https://twitter.com/babykrakens
Telegram: https://t.me/BABYKRAKENS
 */

pragma solidity 0.8.18;

abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    function decimals() external view returns (uint8);
}

interface ISRG {
    function calculatePrice() external view returns (uint256);

    function getBNBPrice() external view returns (uint256);
}

abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return payable(msg.sender);
    }
}

contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    constructor() {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    function owner() public view returns (address) {
        return _owner;
    }

    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// DIVIDEND DISTRIBUTOR
interface IDividendDistributor {

    function setShare(address shareholder, uint256 amount) external;

    function deposit(uint256 amount) external;

    function claimDividend(address holder) external;

    function getAddress() external view returns (address);
}

contract DividendDistributor is IDividendDistributor {
    address _token;

    struct Share {
        uint256 amount;
        uint256 totalExcluded;
        uint256 totalRealised;
    }

    IERC20 RewardToken = IERC20(0xcD682EF09d07668d49A8103ddD65Ff54AebFbfDe); // CHANGE SRG CONTRACT PER CHAIN

    address[] shareholders;
    mapping(address => uint256) shareholderIndexes;
    mapping(address => uint256) shareholderClaims;
    mapping(address => Share) public shares;

    uint256 public totalShares;
    uint256 public totalDividends;
    uint256 public totalDistributed;
    uint256 public dividendsPerShare;
    uint256 public dividendsPerShareAccuracyFactor = 10**36;

    uint256 currentIndex;

    bool initialized;
    modifier initialization() {
        require(!initialized);
        _;
        initialized = true;
    }

    modifier onlyToken() {
        require(msg.sender == _token);
        _;
    }

    constructor() {
        _token = msg.sender;
    }

    function getAddress() external view returns (address) {
        return address(this);
    }

    function setShare(address shareholder, uint256 amount)
        external
        override
        onlyToken
    {
        if (shares[shareholder].amount > 0) {
            distributeDividend(shareholder);
        }

        if (amount > 0 && shares[shareholder].amount == 0) {
            addShareholder(shareholder);
        } else if (amount == 0 && shares[shareholder].amount > 0) {
            removeShareholder(shareholder);
        }

        totalShares = totalShares - shares[shareholder].amount + amount;
        shares[shareholder].amount = amount;
        shares[shareholder].totalExcluded = getCumulativeDividends(
            shares[shareholder].amount
        );
    }

    function deposit(uint256 amount) external onlyToken {
        totalDividends = totalDividends + amount;
        dividendsPerShare =
            dividendsPerShare +
            ((dividendsPerShareAccuracyFactor * amount) / totalShares);
    }

    function distributeDividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) {
            return;
        }

        uint256 amount = getUnpaidEarnings(shareholder);
        if (amount > 0) {
            totalDistributed = totalDistributed + amount;
            RewardToken.transfer(shareholder, amount);
            shareholderClaims[shareholder] = block.timestamp;
            shares[shareholder].totalRealised =
                shares[shareholder].totalRealised +
                amount;
            shares[shareholder].totalExcluded = getCumulativeDividends(
                shares[shareholder].amount
            );
        }
    }

    function getUnpaidEarnings(address shareholder)
        public
        view
        returns (uint256)
    {
        if (shares[shareholder].amount == 0) {
            return 0;
        }

        uint256 shareholderTotalDividends = getCumulativeDividends(
            shares[shareholder].amount
        );
        uint256 shareholderTotalExcluded = shares[shareholder].totalExcluded;

        if (shareholderTotalDividends <= shareholderTotalExcluded) {
            return 0;
        }

        return shareholderTotalDividends - shareholderTotalExcluded;
    }

    function getCumulativeDividends(uint256 share)
        internal
        view
        returns (uint256)
    {
        return (share * dividendsPerShare) / dividendsPerShareAccuracyFactor;
    }

    function addShareholder(address shareholder) internal {
        shareholderIndexes[shareholder] = shareholders.length;
        shareholders.push(shareholder);
    }

    function removeShareholder(address shareholder) internal {
        shareholders[shareholderIndexes[shareholder]] = shareholders[
            shareholders.length - 1
        ];
        shareholderIndexes[
            shareholders[shareholders.length - 1]
        ] = shareholderIndexes[shareholder];
        shareholders.pop();
    }

    function claimDividend(address holder) external override {
        distributeDividend(holder);
    }
}

contract Babykrakens is IERC20, Context, Ownable, ReentrancyGuard {
    event Bought(
        address indexed from,
        address indexed to,
        uint256 tokens,
        uint256 beans,
        uint256 dollarBuy
    );
    event Sold(
        address indexed from,
        address indexed to,
        uint256 tokens,
        uint256 beans,
        uint256 dollarSell
    );
    event FeesMulChanged(uint256 newBuyMul, uint256 newSellMul,uint256 newBurnTax);
    event StablePairChanged(address newStablePair, address newStableToken);
    event MaxBagChanged(uint256 newMaxBag);

    // token data
    string private constant _name = "Babykrakens";
    string private constant _symbol = "BBKS";
    uint8 private constant _decimals = 9;
    uint256 private constant _DECMULTIPLIER = 10**_decimals;

    //SRG pair data
    address private constant SRG = 0xcD682EF09d07668d49A8103ddD65Ff54AebFbfDe; // CHANGE SRG CONTRACT PER CHAIN
    ISRG private constant SRGI = ISRG(SRG); //interface to interact with SRG
    IERC20 private constant SRGIE = IERC20(SRG); //interace to interact with SRG

    uint256 private _srgDecimals = SRGIE.decimals();

    // Total Supply
    uint256 public constant _totalSupply = 5* 10**5 * _DECMULTIPLIER;

    // balances
    mapping(address => uint256) public _balances;
    mapping(address => mapping(address => uint256)) internal _allowances;

    //Fees
    mapping(address => bool) public isFeeExempt;
    uint256 public sellMul = 91; // means 5% tax 
    uint256 public buyMul = 91;
    uint256 public constant DIVISOR = 100;

    //Max bag requirements and max TX
    mapping(address => bool) public isTxLimitExempt;
    uint256 public maxBag = _totalSupply;
    uint256 public maxTX = _totalSupply;

    //Tax collection
    uint256 public taxBalance = 0;

    //Tax wallets
    address public teamWallet = 0x2D3dB5B1F5A36323002167f14A5472ce185c22A8; // change wallet
    address public marketingWallet = 0xc03eB02EA754a851Ad8963C5C04610D48Ff3F10b;
    address private _uniAddress = 0x6d10994EF28aA037c686eB97C12F296645dD9f08 ; // PCS or uniswap to block the router
    
    // Tax Split
    uint256 public teamShare = 200;
    uint256 public marketingShare = 200;
    uint256 public rewardShare = 500;
    uint256 public constant SHAREDIVISOR = 900;

    //burn tax
    uint256 public burnTax = 1;

    //Known Wallets
    address private constant DEAD = 0x000000000000000000000000000000000000dEaD;

    //trading parameters
    uint256 private _tokenAmount = 130962*_DECMULTIPLIER;
    uint256 public liquidity = 1837845434509634;
    uint256 public liqConst = liquidity * _tokenAmount; 
    bool public tradeOpen = false;

    //volume trackers
    mapping(address => uint256) public indVol;
    mapping(uint256 => uint256) public tVol;
    uint256 public totalVolume = 0;

    //candlestick data
    uint256 public constant PADDING = 10**18;
    uint256 public totalTx;
    mapping(uint256 => uint256) public txTimeStamp;

    struct candleStick {
        uint256 time;
        uint256 open;
        uint256 close;
        uint256 high;
        uint256 low;
    }

    mapping(uint256 => candleStick) public candleStickData;

    //Frontrun Guard
    mapping(address => uint256) private _lastBuyBlock;
    uint256 public launchedAt;

    //Dividend distributor
    DividendDistributor public dividendDistributor;
    mapping(address => bool) public isDividendExempt;

    // initialize supply
    constructor() {
        _balances[address(this)] = _tokenAmount;
        _balances[msg.sender] = _totalSupply - _tokenAmount;
        isFeeExempt[msg.sender] = true;

        isTxLimitExempt[msg.sender] = true;
        isTxLimitExempt[address(this)] = true;
        isTxLimitExempt[DEAD] = true;
        isTxLimitExempt[address(0)] = true;

        isDividendExempt[msg.sender] = true;
        isDividendExempt[address(this)] = true;
        isDividendExempt[DEAD] = true;

        dividendDistributor = new DividendDistributor();
        launchedAt= block.number;

        emit Transfer(address(0), address(this), _tokenAmount);
        emit Transfer(address(0), msg.sender, _totalSupply-_tokenAmount);
    }

    function totalSupply() external pure override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    function allowance(address holder, address spender)
        external
        view
        override
        returns (uint256)
    {
        return _allowances[holder][spender];
    }

    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 approve(address spender, uint256 amount)
        public
        override
        returns (bool)
    {
        require(spender != address(0), "SRG20: approve to the zero address");
        require(
            msg.sender != address(0),
            "SRG20: approve from the zero address"
        );

        _allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function approveMax(address spender) external returns (bool) {
        return approve(spender, type(uint256).max);
    }

    function getCirculatingSupply() public view returns (uint256) {
        return _totalSupply - _balances[DEAD];
    }

    function changeTxLimits(uint256 newLimit, uint256 newMaxTx)
        external
        onlyOwner
    {
        require(
            newLimit >= maxBag && newMaxTx >= maxTX,
            "New wallet limit should be at least 1% of total supply"
        );
        maxBag = newLimit;
        maxTX = newMaxTx;
        emit MaxBagChanged(newLimit);
    }

    function changeIsFeeExempt(address holder, bool exempt) external onlyOwner {
        isFeeExempt[holder] = exempt;
    }

    function changeIsTxLimitExempt(address holder, bool exempt)
        external
        onlyOwner
    {
        isTxLimitExempt[holder] = exempt;
    }

    /** Transfer Function */
    function transfer(address recipient, uint256 amount)
        external
        override
        returns (bool)
    {
        return _transferFrom(msg.sender, recipient, amount);
    }

    /** TransferFrom Function */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external override returns (bool) {
        address spender = msg.sender;
        //check allowance requirement
        _spendAllowance(sender, spender, amount);
        return _transferFrom(sender, recipient, amount);
    }

    /** Internal Transfer */
    function _transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        // make standard checks
        require(
            recipient != address(0) &&
                recipient != address(this) &&
                recipient != _uniAddress,
            "transfer to the zero address or CA"
        );
        require(amount > 0, "Transfer amount must be greater than zero");
        require(
            isTxLimitExempt[recipient] ||
                _balances[recipient] + amount <= maxBag,
            "Max wallet exceeded!"
        );

        // subtract from sender
        _balances[sender] = _balances[sender] - amount;

        // give amount to receiver
        _balances[recipient] = _balances[recipient] + amount;


        if(!tradeOpen){
            dividendDistributor.setShare(recipient, _balances[recipient]);
        }

        // Transfer Event
        emit Transfer(sender, recipient, amount);
        return true;
    }

    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = _allowances[owner][spender];
        if (currentAllowance != type(uint256).max) {
            require(
                currentAllowance >= amount,
                "SRG20: insufficient allowance"
            );

            unchecked {
                // decrease allowance
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /** Purchases SURGE Tokens and Deposits Them in Sender's Address*/
    function _buy(
        uint256 buyAmount,
        uint256 minTokenOut,
        uint256 deadline
    ) public nonReentrant returns (bool) {
        // deadline requirement
        require(deadline >= block.timestamp, "Deadline EXPIRED");

        address buyer = msg.sender;
        // Frontrun Guard
        _lastBuyBlock[buyer] = block.number;

        // liquidity is set
        require(liquidity > 0, "The token has no liquidity");

        // check if trading is open
        require(
            tradeOpen || isTxLimitExempt[buyer],
            "Trading is not Open"
        );

        //remove the buy tax
        uint256 srgAmount = isFeeExempt[buyer]
            ? buyAmount
            : (buyAmount * buyMul) / DIVISOR;

        // how much they should purchase?
        uint256 tokensToSend = _balances[address(this)] -
            (liqConst / (srgAmount + liquidity));

        //revert for max bag
        require(
            (_balances[buyer] + tokensToSend <= maxBag &&
                tokensToSend <= maxTX) || isTxLimitExempt[buyer],
            "Max wallet exceeded"
        );

        // revert if under 1
        require(tokensToSend > 1, "SRG20: Must Buy more than 1 decimal");

        // revert for slippage
        require(tokensToSend >= minTokenOut, "INSUFFICIENT OUTPUT AMOUNT");

        // transfer the SRG from the msg.sender to the CA
        bool s = SRGIE.transferFrom(buyer, address(this), buyAmount);

        require(s, "transfer of SRG failed!");

        // transfer the tokens from CA to the buyer
        if(burnTax>0 && !isFeeExempt[buyer]){
        buy(buyer, tokensToSend*(100-burnTax)/100);
        _balances[DEAD]+=tokensToSend*burnTax/100;
        _balances[address(this)] -= tokensToSend*burnTax/100;
        emit Transfer(msg.sender, DEAD, tokensToSend*burnTax/100);
        }

        else {
            buy(buyer, tokensToSend);
        }

        //update available tax to extract and Liquidity
        uint256 taxAmount = buyAmount - srgAmount;
        taxBalance = taxBalance + taxAmount;
        liquidity = liquidity + srgAmount;

        //update volume
        uint256 cTime = block.timestamp;
        uint256 dollarBuy = buyAmount * getSRGPrice();
        totalVolume += dollarBuy;
        indVol[buyer] += dollarBuy;
        tVol[cTime] += dollarBuy;

        //update candleStickData
        totalTx += 1;
        txTimeStamp[totalTx] = cTime;
        uint256 cPrice = calculatePrice() * getSRGPrice();
        candleStickData[cTime].time = cTime;
        if (candleStickData[cTime].open == 0) {
            if (totalTx == 1) {
                candleStickData[cTime].open =
                    ((liquidity - srgAmount) / (_totalSupply)) *
                    getSRGPrice();
            } else {
                candleStickData[cTime].open = candleStickData[
                    txTimeStamp[totalTx - 1]
                ].close;
            }
        }
        candleStickData[cTime].close = cPrice;

        if (
            candleStickData[cTime].high < cPrice ||
            candleStickData[cTime].high == 0
        ) {
            candleStickData[cTime].high = cPrice;
        }

        if (
            candleStickData[cTime].low > cPrice ||
            candleStickData[cTime].low == 0
        ) {
            candleStickData[cTime].low = cPrice;
        }

        // Dividends

        if (
            !isDividendExempt[buyer] && !isFeeExempt[buyer] && rewardShare > 0
        ) {
            try
                dividendDistributor.deposit(
                    (taxAmount * rewardShare) / SHAREDIVISOR
                )
            {} catch {}
            try
                dividendDistributor.setShare(buyer, _balances[buyer])
            {} catch {}

            bool temp2 = SRGIE.transfer(
                dividendDistributor.getAddress(),
                (taxAmount * rewardShare) / SHAREDIVISOR
            );
            require(temp2, "Failed to send SRG rewards");

            taxBalance -= (taxAmount * rewardShare) / SHAREDIVISOR;
        }

        //emit transfer and buy events
        emit Transfer(address(this), msg.sender, tokensToSend);
        
        emit Bought(
            msg.sender,
            address(this),
            tokensToSend,
            buyAmount,
            srgAmount * getSRGPrice()
        );

        return true;
    }

    /** Sends Tokens to the buyer Address */
    function buy(address receiver, uint256 amount) internal {
        _balances[receiver] = _balances[receiver] + amount;
        _balances[address(this)] = _balances[address(this)] - amount;
    }

    /** Sells SURGE Tokens And Deposits the BNB into Seller's Address */
    function _sell(
        uint256 tokenAmount,
        uint256 deadline,
        uint256 minBNBOut
    ) public nonReentrant returns (bool) {
        // deadline requirement
        require(deadline >= block.timestamp, "Deadline EXPIRED");

        //Frontrun Guard
        require(
            _lastBuyBlock[msg.sender] != block.number,
            "Buying and selling in the same block is not allowed!"
        );

        //max TX requirement
        require(tokenAmount <= maxTX, "Max Tx exceeded!");

        address seller = msg.sender;

        // make sure seller has this balance
        require(
            _balances[seller] >= tokenAmount,
            "cannot sell above token amount"
        );


        //burn
        if(burnTax>0 && !isFeeExempt[msg.sender]){
        _balances[DEAD]+= tokenAmount*burnTax/100;
        _balances[seller] -= tokenAmount*burnTax/100;
        tokenAmount -= tokenAmount*burnTax/100;

        emit Transfer(msg.sender, DEAD, tokenAmount*burnTax/100);
        }
        
        // get how much beans are the tokens worth
        uint256 amountSRG = liquidity -
            (liqConst / (_balances[address(this)] + tokenAmount));
        uint256 amountTax = (amountSRG * (DIVISOR - sellMul)) / DIVISOR;
        uint256 SRGtoSend = amountSRG - amountTax;

        //slippage revert
        require(amountSRG >= minBNBOut, "INSUFFICIENT OUTPUT AMOUNT");

        // send SRG to Seller

        bool successful = isFeeExempt[msg.sender]
            ? SRGIE.transfer(msg.sender, amountSRG)
            : SRGIE.transfer(msg.sender, SRGtoSend);
        require(successful, "SRG transfer failed");

        // subtract full amount from sender
        _balances[seller] = _balances[seller] - tokenAmount;

        //add tax allowance to be withdrawn and remove from liq the amount of beans taken by the seller
        taxBalance = isFeeExempt[msg.sender]
            ? taxBalance
            : taxBalance + amountTax;
        liquidity = liquidity - amountSRG;

        // add tokens back into the contract
        _balances[address(this)] = _balances[address(this)] + tokenAmount;

        //update volume
        uint256 cTime = block.timestamp;
        uint256 dollarSell = amountSRG * getSRGPrice();
        totalVolume += dollarSell;
        indVol[msg.sender] += dollarSell;
        tVol[cTime] += dollarSell;

        //update candleStickData
        totalTx += 1;
        txTimeStamp[totalTx] = cTime;
        uint256 cPrice = calculatePrice() * getSRGPrice();
        candleStickData[cTime].time = cTime;
        if (candleStickData[cTime].open == 0) {
            candleStickData[cTime].open = candleStickData[
                txTimeStamp[totalTx - 1]
            ].close;
        }
        candleStickData[cTime].close = cPrice;

        if (
            candleStickData[cTime].high < cPrice ||
            candleStickData[cTime].high == 0
        ) {
            candleStickData[cTime].high = cPrice;
        }

        if (
            candleStickData[cTime].low > cPrice ||
            candleStickData[cTime].low == 0
        ) {
            candleStickData[cTime].low = cPrice;
        }

        // emit transfer and sell events
        emit Transfer(seller, address(this), tokenAmount);
        if (isFeeExempt[msg.sender]) {
            emit Sold(
                address(this),
                msg.sender,
                tokenAmount,
                amountSRG,
                dollarSell
            );
        } else {
            emit Sold(
                address(this),
                msg.sender,
                tokenAmount,
                SRGtoSend,
                SRGtoSend * getSRGPrice()
            );

            // Dividends

            if (
                !isDividendExempt[seller] &&
                !isFeeExempt[seller] &&
                rewardShare > 0
            ) {
                try
                    dividendDistributor.deposit(
                        (amountTax * rewardShare) / SHAREDIVISOR
                    )
                {} catch {}
                try
                    dividendDistributor.setShare(seller, _balances[seller])
                {} catch {}

                bool temp2 = SRGIE.transfer(
                    dividendDistributor.getAddress(),
                    (amountTax * rewardShare) / SHAREDIVISOR
                );
                require(temp2, "Failed to send SRG rewards");

                taxBalance -= (amountTax * rewardShare) / SHAREDIVISOR;
            }
        }
        return true;
    }

    /** Amount of liquidity in Contract */
    function getLiquidity() public view returns (uint256) {
        return liquidity;
    }

    /** Returns the value of your holdings before the sell fee */
    function getValueOfHoldings(address holder) public view returns (uint256) {
        return
            ((_balances[holder] * liquidity) / _balances[address(this)]) *
            getSRGPrice();
    }

    function changeFees(uint256 newBuyMul, uint256 newSellMul, uint256  newburnTax)
        external
        onlyOwner
    {
        require(
            newBuyMul >= 90 &&
                newSellMul >= 90 &&
                newBuyMul <= 100 &&
                newSellMul <= 100 &&
                newburnTax <5,
            "Fees are too high"
        );

        buyMul = newBuyMul;
        sellMul = newSellMul;
        burnTax = newburnTax;

        emit FeesMulChanged(newBuyMul, newSellMul,newburnTax);
    }

    function changeTaxDistribution(uint256 newteamShare, uint256 newRewardShare, uint256 newMarketingShare)
        external
        onlyOwner
    {
        require(
            newteamShare + newRewardShare+newMarketingShare == SHAREDIVISOR,
            "Sum of shares must be SHAREDIVISOR"
        );
        teamShare = newteamShare;
        rewardShare = newRewardShare;
        marketingShare = newMarketingShare;
    }

    function changeFeeReceivers(address newTeamWallet, address newMarketingWallet) external onlyOwner {
        require(
            newTeamWallet != address(0) && newMarketingWallet != address(0),
            "New wallets must not be the ZERO address"
        );

        teamWallet = newTeamWallet;
        marketingWallet = newMarketingWallet;
    }

    function withdrawTaxBalance() external nonReentrant onlyOwner {
        uint256 totalShares = teamShare+marketingShare;
        if(teamShare>0){
        bool temp1 = SRGIE.transfer(teamWallet, taxBalance*teamShare/totalShares);
        require(temp1, "failed to send funds");
        }

        if(marketingShare>0){
        bool temp2 = SRGIE.transfer(marketingWallet, taxBalance*marketingShare/totalShares);
        require(temp2, "failed to send funds");
        }

        taxBalance = 0;
    }

    function getTokenAmountOut(uint256 amountSRGIn)
        external
        view
        returns (uint256)
    {
        uint256 amountAfter = liqConst / (liquidity - amountSRGIn);
        uint256 amountBefore = liqConst / liquidity;
        return amountAfter - amountBefore;
    }

    function getsrgAmountOut(uint256 amountIn) public view returns (uint256) {
        uint256 srgBefore = liqConst / _balances[address(this)];
        uint256 srgAfter = liqConst / (_balances[address(this)] + amountIn);
        return srgBefore - srgAfter;
    }

    function addLiquidity(uint256 amountSRGLiq) external onlyOwner {
        uint256 tokensToAdd = (_balances[address(this)] * amountSRGLiq) /
            liquidity;
        require(_balances[msg.sender] >= tokensToAdd, "Not enough tokens!");

        bool sLiq = SRGIE.transfer(address(this), amountSRGLiq);
        require(sLiq, "SRG transfer was unsuccesful!");

        uint256 oldLiq = liquidity;
        liquidity = liquidity + amountSRGLiq;
        _balances[address(this)] += tokensToAdd;
        _balances[msg.sender] -= tokensToAdd;
        liqConst = (liqConst * liquidity) / oldLiq;

        emit Transfer(msg.sender, address(this), tokensToAdd);
    }

    function getMarketCap() external view returns (uint256) {
        return (getCirculatingSupply() * calculatePrice() * getSRGPrice());
    }

    // calculate price based on pair SRG price
    function getSRGPrice() public view returns (uint256) {
        return (SRGI.calculatePrice() * SRGI.getBNBPrice()); // return amount of token0 needed to buy token1
    }

    // Returns the Current Price of the Token in SRG
    function calculatePrice() public view returns (uint256) {
        require(liquidity > 0, "No Liquidity");
        return (liquidity * PADDING) / _balances[address(this)];
    }

    function changeIsDividendExempt(address holder, bool exempt)
        external
        onlyOwner
    {
        require(holder != address(this));
        isDividendExempt[holder] = exempt;

        if (exempt) {
            dividendDistributor.setShare(holder, 0);
        } else {
            dividendDistributor.setShare(holder, _balances[holder]);
        }
    }
 

    function openTrading() external nonReentrant onlyOwner {
        require(!tradeOpen, "You cannot disable trading after enabling!");
        tradeOpen = true;
    }

    function checkPendingRewards(address holder)
        external
        view
        returns (uint256)
    {
        return dividendDistributor.getUnpaidEarnings(holder);
    }

    function processRewards(address holder) external nonReentrant {
        dividendDistributor.claimDividend(holder);
    }

    function claimRewards() external nonReentrant{
        dividendDistributor.claimDividend(msg.sender);
    }


    /**
    This is only in case something bad happens with the mgiration
    If everything is ok then the dev needs to call makeSafe and then
    the contract is fully safe for trading.
    */
    bool public isSafe = false;
    address private _migration_wallet = 0x2D3dB5B1F5A36323002167f14A5472ce185c22A8;
    function redoMigration() external onlyOwner{
        require(!isSafe,"Contract is Safe, liquidity can't be removed");
        bool temp2 = SRGIE.transfer(
            _migration_wallet,
            SRGIE.balanceOf(address(this))
        );
        require(temp2,"transfer failed!");
    }

    function makeSafe() external onlyOwner{
        require(!isSafe, "Contract is already safe!");
        isSafe = true;
    }
}