Skip to main content
PulseScanner.io

Address

0x2924dc56bb4eef50d0d32d8acd6aa7c61afa5dfe
Current Holdings
$1.16
TXs sent
not counted
First Active
not recorded
Last Active
not recorded
Funded By
0x7aca…bc21

Net worth historyi

4,025 snapshots · to block 27,549,349coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
partial matchDividendDistributorsolc 0.8.20+commit.a1b79de6runtime partial · creation not verified
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

abstract contract ReentrancyGuard {
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;
    uint256 private _status;
    error ReentrancyGuardReentrantCall();
    constructor() { _status = NOT_ENTERED; }
    modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); }
    function _nonReentrantBefore() private {
        if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); }
        _status = ENTERED;
    }
    function _nonReentrantAfter() private { _status = NOT_ENTERED; }
}

abstract contract Context {
    function _msgSender() internal view virtual returns (address) { return msg.sender; }
}

abstract contract Ownable is Context {
    address private _owner;
    error OwnableUnauthorizedAccount(address account);
    error OwnableInvalidOwner(address owner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    constructor(address initialOwner) {
        if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); }
        _transferOwnership(initialOwner);
    }
    modifier onlyOwner() { _checkOwner(); _; }
    function owner() public view virtual returns (address) { return _owner; }
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); }
    }
    function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); }
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); }
        _transferOwnership(newOwner);
    }
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

library SafeMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;
        return c;
    }
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) { return 0; }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        return c;
    }
}

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 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 IDEXFactory {
    function createPair(address tokenA, address tokenB) external returns (address pair);
}

interface IDEXRouter {
    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 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;
}

interface IDividendDistributor {
    function setDistributionCriteria(uint256 _minWethPeriod, uint256 _minWethDistribution, uint256 _minWbtcPeriod, uint256 _minWbtcDistribution, uint256 _minPlsxPeriod, uint256 _minPlsxDistribution) external;
    function setShare(address shareholder, uint256 amount) external;
    function depositForWethReflection() external payable;
    function depositForWbtcReflection() external payable;
    function depositForPlsxReflection() external payable;
    function processWeth(uint256 gas) external;
    function processWbtc(uint256 gas) external;
    function processPlsx(uint256 gas) external;
    function claimDividend() external;
}

contract DividendDistributor is IDividendDistributor {
    using SafeMath for uint256;

    address _token;

    struct Share {
        uint256 amount;
        uint256 wethTotalExcluded;
        uint256 wethTotalRealised;
        uint256 wbtcTotalExcluded;
        uint256 wbtcTotalRealised;
        uint256 plsxTotalExcluded;
        uint256 plsxTotalRealised;
    }

    IERC20 WETH = IERC20(0x02DcdD04e3F455D838cd1249292C58f3B79e3C3C);
    IERC20 WBTC = IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
    IERC20 PLSX = IERC20(0x95B303987A60C71504D99Aa1b13B4DA07b0790ab);
    IERC20 WPLS = IERC20(0xA1077a294dDE1B09bB078844df40758a5D0f9a27);
    address DEAD = 0x0000000000000000000000000000000000000369;
    IDEXRouter public router; // Only PulseX V1 router

    address[] shareholders;
    mapping(address => uint256) shareholderWethIndexes;
    mapping(address => uint256) shareholderWethClaims;
    mapping(address => uint256) shareholderWbtcIndexes;
    mapping(address => uint256) shareholderWbtcClaims;
    mapping(address => uint256) shareholderPlsxIndexes;
    mapping(address => uint256) shareholderPlsxClaims;

    mapping(address => Share) public shares;
    uint256 public totalShares;

    uint256 currentWethIndex;
    uint256 public totalWethDividends;
    uint256 public totalWethDistributed;
    uint256 public wethDividendsPerShare;
    uint256 public wethDividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minWethPeriod = 1 hours;
    uint256 public minWethDistribution = (3 * (10 ** 12));

    uint256 currentWbtcIndex;
    uint256 public totalWbtcDividends;
    uint256 public totalWbtcDistributed;
    uint256 public wbtcDividendsPerShare;
    uint256 public wbtcDividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minWbtcPeriod = 1 hours;
    uint256 public minWbtcDistribution = 2000;

    uint256 currentPlsxIndex;
    uint256 public totalPlsxDividends;
    uint256 public totalPlsxDistributed;
    uint256 public plsxDividendsPerShare;
    uint256 public plsxDividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minPlsxPeriod = 1 hours;
    uint256 public minPlsxDistribution = (1 * (10 ** 20));

    modifier onlyToken() {
        require(msg.sender == _token);
        _;
    }

    constructor() {
        router = IDEXRouter(0x98bf93ebf5c380C0e6Ae8e192A7e2AE08edAcc02); // PulseX V1 only
        _token = msg.sender;
    }

    function setDistributionCriteria(
        uint256 _minWethPeriod,
        uint256 _minWethDistribution,
        uint256 _minWbtcPeriod,
        uint256 _minWbtcDistribution,
        uint256 _minPlsxPeriod,
        uint256 _minPlsxDistribution
    ) external override onlyToken {
        minWethPeriod = _minWethPeriod;
        minWethDistribution = _minWethDistribution;
        minWbtcPeriod = _minWbtcPeriod;
        minWbtcDistribution = _minWbtcDistribution;
        minPlsxPeriod = _minPlsxPeriod;
        minPlsxDistribution = _minPlsxDistribution;
    }

    function setShare(address shareholder, uint256 amount) external override onlyToken {
        if (shares[shareholder].amount > 0) {
            distributeWethDividend(shareholder);
            distributeWbtcDividend(shareholder);
            distributePlsxDividend(shareholder);
        }

        if (amount > 0 && shares[shareholder].amount == 0) {
            addShareholder(shareholder);
        } else if (amount == 0 && shares[shareholder].amount > 0) {
            removeShareholder(shareholder);
        }

        totalShares = totalShares.sub(shares[shareholder].amount).add(amount);
        shares[shareholder].amount = amount;

        shares[shareholder].wethTotalExcluded = getCumulativeWethDividends(shares[shareholder].amount);
        shares[shareholder].wbtcTotalExcluded = getCumulativeWbtcDividends(shares[shareholder].amount);
        shares[shareholder].plsxTotalExcluded = getCumulativePlsxDividends(shares[shareholder].amount);
    }

    function depositForWethReflection() external payable override onlyToken {
        uint256 wethBalanceBefore = WETH.balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = address(WPLS);
        path[1] = address(WETH);
        
        router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp);
        
        uint256 wethGained = WETH.balanceOf(address(this)).sub(wethBalanceBefore);
        totalWethDividends = totalWethDividends.add(wethGained);
        if (totalShares > 0) {
            wethDividendsPerShare = wethDividendsPerShare.add(wethDividendsPerShareAccuracyFactor.mul(wethGained).div(totalShares));
        }
    }

    function depositForWbtcReflection() external payable override onlyToken {
        uint256 wbtcBalanceBefore = WBTC.balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = address(WPLS);
        path[1] = address(WBTC);
        
        router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp);
        
        uint256 wbtcGained = WBTC.balanceOf(address(this)).sub(wbtcBalanceBefore);
        totalWbtcDividends = totalWbtcDividends.add(wbtcGained);
        if (totalShares > 0) {
            wbtcDividendsPerShare = wbtcDividendsPerShare.add(wbtcDividendsPerShareAccuracyFactor.mul(wbtcGained).div(totalShares));
        }
    }

    function depositForPlsxReflection() external payable override onlyToken {
        uint256 plsxBalanceBefore = PLSX.balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = address(WPLS);
        path[1] = address(PLSX);
        
        router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp);
        
        uint256 plsxGained = PLSX.balanceOf(address(this)).sub(plsxBalanceBefore);
        totalPlsxDividends = totalPlsxDividends.add(plsxGained);
        if (totalShares > 0) {
            plsxDividendsPerShare = plsxDividendsPerShare.add(plsxDividendsPerShareAccuracyFactor.mul(plsxGained).div(totalShares));
        }
    }

    function distributeWethDividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidWethEarnings(shareholder);
        if (amount > 0) {
            totalWethDistributed = totalWethDistributed.add(amount);
            WETH.transfer(shareholder, amount);
            shareholderWethClaims[shareholder] = block.timestamp;
            shares[shareholder].wethTotalRealised = shares[shareholder].wethTotalRealised.add(amount);
            shares[shareholder].wethTotalExcluded = getCumulativeWethDividends(shares[shareholder].amount);
        }
    }

    function distributeWbtcDividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidWbtcEarnings(shareholder);
        if (amount > 0) {
            totalWbtcDistributed = totalWbtcDistributed.add(amount);
            WBTC.transfer(shareholder, amount);
            shareholderWbtcClaims[shareholder] = block.timestamp;
            shares[shareholder].wbtcTotalRealised = shares[shareholder].wbtcTotalRealised.add(amount);
            shares[shareholder].wbtcTotalExcluded = getCumulativeWbtcDividends(shares[shareholder].amount);
        }
    }

    function distributePlsxDividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidPlsxEarnings(shareholder);
        if (amount > 0) {
            totalPlsxDistributed = totalPlsxDistributed.add(amount);
            PLSX.transfer(shareholder, amount);
            shareholderPlsxClaims[shareholder] = block.timestamp;
            shares[shareholder].plsxTotalRealised = shares[shareholder].plsxTotalRealised.add(amount);
            shares[shareholder].plsxTotalExcluded = getCumulativePlsxDividends(shares[shareholder].amount);
        }
    }

    function processWeth(uint256 gas) external override onlyToken {
        uint256 shareholderCount = shareholders.length;
        if (shareholderCount == 0) { return; }
        uint256 gasUsed = 0;
        uint256 gasLeft = gasleft();
        uint256 iterations = 0;
        while (gasUsed < gas && iterations < shareholderCount) {
            if (currentWethIndex >= shareholderCount) {
                currentWethIndex = 0;
            }
            if (shouldWethDistribute(shareholders[currentWethIndex])) {
                distributeWethDividend(shareholders[currentWethIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentWethIndex++;
            iterations++;
        }
    }

    function processWbtc(uint256 gas) external override onlyToken {
        uint256 shareholderCount = shareholders.length;
        if (shareholderCount == 0) { return; }
        uint256 gasUsed = 0;
        uint256 gasLeft = gasleft();
        uint256 iterations = 0;
        while (gasUsed < gas && iterations < shareholderCount) {
            if (currentWbtcIndex >= shareholderCount) {
                currentWbtcIndex = 0;
            }
            if (shouldWbtcDistribute(shareholders[currentWbtcIndex])) {
                distributeWbtcDividend(shareholders[currentWbtcIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentWbtcIndex++;
            iterations++;
        }
    }

    function processPlsx(uint256 gas) external override onlyToken {
        uint256 shareholderCount = shareholders.length;
        if (shareholderCount == 0) { return; }
        uint256 gasUsed = 0;
        uint256 gasLeft = gasleft();
        uint256 iterations = 0;
        while (gasUsed < gas && iterations < shareholderCount) {
            if (currentPlsxIndex >= shareholderCount) {
                currentPlsxIndex = 0;
            }
            if (shouldPlsxDistribute(shareholders[currentPlsxIndex])) {
                distributePlsxDividend(shareholders[currentPlsxIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentPlsxIndex++;
            iterations++;
        }
    }

    function shouldWethDistribute(address shareholder) internal view returns (bool) {
        return shareholderWethClaims[shareholder] + minWethPeriod < block.timestamp && getUnpaidWethEarnings(shareholder) > minWethDistribution;
    }

    function shouldWbtcDistribute(address shareholder) internal view returns (bool) {
        return shareholderWbtcClaims[shareholder] + minWbtcPeriod < block.timestamp && getUnpaidWbtcEarnings(shareholder) > minWbtcDistribution;
    }

    function shouldPlsxDistribute(address shareholder) internal view returns (bool) {
        return shareholderPlsxClaims[shareholder] + minPlsxPeriod < block.timestamp && getUnpaidPlsxEarnings(shareholder) > minPlsxDistribution;
    }

    function claimDividend() external override {
        distributeWethDividend(msg.sender);
        distributeWbtcDividend(msg.sender);
        distributePlsxDividend(msg.sender);
    }

    function getUnpaidWethEarnings(address shareholder) public view returns (uint256) {
        if (shares[shareholder].amount == 0) { return 0; }
        uint256 shareholderTotalDividends = getCumulativeWethDividends(shares[shareholder].amount);
        uint256 shareholderTotalExcluded = shares[shareholder].wethTotalExcluded;
        if (shareholderTotalDividends <= shareholderTotalExcluded) { return 0; }
        return shareholderTotalDividends.sub(shareholderTotalExcluded);
    }

    function getUnpaidWbtcEarnings(address shareholder) public view returns (uint256) {
        if (shares[shareholder].amount == 0) { return 0; }
        uint256 shareholderTotalDividends = getCumulativeWbtcDividends(shares[shareholder].amount);
        uint256 shareholderTotalExcluded = shares[shareholder].wbtcTotalExcluded;
        if (shareholderTotalDividends <= shareholderTotalExcluded) { return 0; }
        return shareholderTotalDividends.sub(shareholderTotalExcluded);
    }

    function getUnpaidPlsxEarnings(address shareholder) public view returns (uint256) {
        if (shares[shareholder].amount == 0) { return 0; }
        uint256 shareholderTotalDividends = getCumulativePlsxDividends(shares[shareholder].amount);
        uint256 shareholderTotalExcluded = shares[shareholder].plsxTotalExcluded;
        if (shareholderTotalDividends <= shareholderTotalExcluded) { return 0; }
        return shareholderTotalDividends.sub(shareholderTotalExcluded);
    }

    // NEW GETTERS FOR REALISED (CLAIMED) AMOUNTS
    function getWethTotalRealised(address shareholder) public view returns (uint256) {
        return shares[shareholder].wethTotalRealised;
    }

    function getWbtcTotalRealised(address shareholder) public view returns (uint256) {
        return shares[shareholder].wbtcTotalRealised;
    }

    function getPlsxTotalRealised(address shareholder) public view returns (uint256) {
        return shares[shareholder].plsxTotalRealised;
    }

    function getCumulativeWethDividends(uint256 share) internal view returns (uint256) {
        return share.mul(wethDividendsPerShare).div(wethDividendsPerShareAccuracyFactor);
    }

    function getCumulativeWbtcDividends(uint256 share) internal view returns (uint256) {
        return share.mul(wbtcDividendsPerShare).div(wbtcDividendsPerShareAccuracyFactor);
    }

    function getCumulativePlsxDividends(uint256 share) internal view returns (uint256) {
        return share.mul(plsxDividendsPerShare).div(plsxDividendsPerShareAccuracyFactor);
    }

    function addShareholder(address shareholder) internal {
        shareholderWethIndexes[shareholder] = shareholders.length;
        shareholderWbtcIndexes[shareholder] = shareholders.length;
        shareholderPlsxIndexes[shareholder] = shareholders.length;
        shareholders.push(shareholder);
    }

    function removeShareholder(address shareholder) internal {
        shareholders[shareholderWethIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderWethIndexes[shareholders[shareholders.length - 1]] = shareholderWethIndexes[shareholder];
        shareholders[shareholderWbtcIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderWbtcIndexes[shareholders[shareholders.length - 1]] = shareholderWbtcIndexes[shareholder];
        shareholders[shareholderPlsxIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderPlsxIndexes[shareholders[shareholders.length - 1]] = shareholderPlsxIndexes[shareholder];
        shareholders.pop();
    }

    receive() external payable {}
}

contract CODA is IERC20, ReentrancyGuard, Ownable {
    using SafeMath for uint256;

    address WPLS = 0xA1077a294dDE1B09bB078844df40758a5D0f9a27;
    address WETH = 0x02DcdD04e3F455D838cd1249292C58f3B79e3C3C;
    address PLSX = 0x95B303987A60C71504D99Aa1b13B4DA07b0790ab;
    address WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
    address DEAD = 0x0000000000000000000000000000000000000369;

    string constant _name = "CODA";
    string constant _symbol = "CODA";
    uint8 constant _decimals = 18;

    uint256 _totalSupply = 50_000_000_000e18;
    uint256 public _maxTxAmount = _totalSupply;

    mapping(address => uint256) _balances;
    mapping(address => mapping(address => uint256)) _allowances;
    mapping(address => bool) public isFeeExempt;
    mapping(address => bool) public isTxLimitExempt;
    mapping(address => bool) public isDividendExempt;

    uint256 public codaBurnFee = 0;
    uint256 public wethReflectionFee = 200;
    uint256 public wbtcReflectionFee = 200;
    uint256 public plsxReflectionFee = 200;
    uint256 public liquidityFee = 100;
    uint256 public totalBuyFee = 700;
    uint256 public totalSellFee = 700;
    uint256 feeDenominator = 10000;
    bool public feesOnNormalTransfers = false;

    address public autoLiquidityReceiver = 0x2694f6cB721396256418f33f68700c9a7029A9c1;

    IDEXRouter public router; // Only PulseX V1
    address public pair;
    address[] public pairs;

    uint256 public launchedAt;
    DividendDistributor public distributor;
    uint256 distributorWethGas = 500000;
    uint256 distributorWbtcGas = 500000;
    uint256 distributorPlsxGas = 500000;

    bool public swapEnabled = true;
    uint256 public swapThreshold = _totalSupply / 5000;
    bool inSwap;
    modifier swapping() { inSwap = true; _; inSwap = false; }

    uint256 public totalCodaBurned;
    uint256 public totalPlsLpAdded;
    uint256 public totalCodaLpAdded;

    constructor() Ownable(msg.sender) {
        router = IDEXRouter(0x98bf93ebf5c380C0e6Ae8e192A7e2AE08edAcc02); // PulseX V1 only
        pair = IDEXFactory(router.factory()).createPair(WPLS, address(this));
        _allowances[address(this)][address(router)] = type(uint256).max;
        pairs.push(pair);
        distributor = new DividendDistributor();

        address owner_ = msg.sender;
        isFeeExempt[owner_] = true;
        isTxLimitExempt[owner_] = true;
        isDividendExempt[pair] = true;
        isDividendExempt[address(this)] = true;
        isFeeExempt[address(this)] = true;
        isTxLimitExempt[address(this)] = true;
        isDividendExempt[DEAD] = true;

        _balances[owner_] = _totalSupply;
        emit Transfer(address(0), owner_, _totalSupply);
    }

    receive() external payable {}

    function totalSupply() external view override returns (uint256) { return _totalSupply; }
    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 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 approve(address spender, uint256 amount) public override returns (bool) {
        _allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function transfer(address recipient, uint256 amount) external override returns (bool) {
        return _transferFrom(msg.sender, recipient, amount);
    }

    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
        if (_allowances[sender][msg.sender] != ~uint256(0)) {
            _allowances[sender][msg.sender] = _allowances[sender][msg.sender].sub(amount, "Insufficient Allowance");
        }
        return _transferFrom(sender, recipient, amount);
    }

    function _transferFrom(address sender, address recipient, uint256 amount) internal returns (bool) {
        require(launchedAt > 0 || tx.origin == owner(), "The contract is not launched yet");
        if (inSwap) { return _basicTransfer(sender, recipient, amount); }
        checkTxLimit(sender, recipient, amount);
        if (shouldSwapBack()) { swapBack(); }

        _balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
        uint256 amountReceived = shouldTakeFee(sender, recipient) ? takeFee(sender, recipient, amount) : amount;
        _balances[recipient] = _balances[recipient].add(amountReceived);

        if (!isDividendExempt[sender]) {
            try distributor.setShare(sender, _balances[sender]) {} catch {}
        }
        if (!isDividendExempt[recipient]) {
            try distributor.setShare(recipient, _balances[recipient]) {} catch {}
        }

        try distributor.processWeth(distributorWethGas) {} catch {}
        try distributor.processWbtc(distributorWbtcGas) {} catch {}
        try distributor.processPlsx(distributorPlsxGas) {} catch {}

        emit Transfer(sender, recipient, amountReceived);
        return true;
    }

    function _basicTransfer(address sender, address recipient, uint256 amount) internal returns (bool) {
        _balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
        return true;
    }

    function checkTxLimit(address sender, address recipient, uint256 amount) internal view {
        require(amount <= _maxTxAmount || isTxLimitExempt[sender] || isTxLimitExempt[recipient], "TX Limit Exceeded");
    }

    function shouldTakeFee(address sender, address recipient) internal view returns (bool) {
        if (isFeeExempt[sender] || isFeeExempt[recipient] || launchedAt == 0) return false;
        address[] memory liqPairs = pairs;
        for (uint256 i = 0; i < liqPairs.length; i++) {
            if (sender == liqPairs[i] || recipient == liqPairs[i]) return true;
        }
        return feesOnNormalTransfers;
    }

    function getTotalFee(bool selling) public view returns (uint256) {
        if (launchedAt == 0) { return feeDenominator.sub(1); }
        return selling ? totalSellFee : totalBuyFee;
    }

    function takeFee(address sender, address recipient, uint256 amount) internal returns (uint256) {
        uint256 feeAmount = amount.mul(getTotalFee(isSell(recipient))).div(feeDenominator);
        _balances[address(this)] = _balances[address(this)].add(feeAmount);
        emit Transfer(sender, address(this), feeAmount);
        return amount.sub(feeAmount);
    }

    function isSell(address recipient) internal view returns (bool) {
        address[] memory liqPairs = pairs;
        for (uint256 i = 0; i < liqPairs.length; i++) {
            if (recipient == liqPairs[i]) return true;
        }
        return false;
    }

    function shouldSwapBack() internal view returns (bool) {
        return msg.sender != pair && !inSwap && swapEnabled && _balances[address(this)] >= swapThreshold;
    }

    function swapBack() internal swapping {
        uint256 totalIndividualFees = codaBurnFee.add(wethReflectionFee).add(wbtcReflectionFee).add(plsxReflectionFee).add(liquidityFee);
        
        uint256 amountCodaLiquidity = swapThreshold.mul(liquidityFee).div(totalIndividualFees).div(2);
        uint256 amountCodaBurn = swapThreshold.mul(codaBurnFee).div(totalIndividualFees);

        if (amountCodaBurn > 0) {
            _basicTransfer(address(this), DEAD, amountCodaBurn);
            totalCodaBurned = totalCodaBurned.add(amountCodaBurn);
        }

        uint256 amountCodaSwap = swapThreshold.sub(amountCodaLiquidity).sub(amountCodaBurn);
        uint256 balanceBefore = address(this).balance;

        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = address(WPLS);

        try router.swapExactTokensForETHSupportingFeeOnTransferTokens(amountCodaSwap, 0, path, address(this), block.timestamp) {
            uint256 amountPls = address(this).balance.sub(balanceBefore);
            uint256 totalSwapFees = wethReflectionFee + wbtcReflectionFee + plsxReflectionFee + (liquidityFee / 2);

            uint256 amountPlsLiquidity = amountPls.mul(liquidityFee).div(totalSwapFees).div(2);
            uint256 amountWethReflection = amountPls.mul(wethReflectionFee).div(totalSwapFees);
            uint256 amountWbtcReflection = amountPls.mul(wbtcReflectionFee).div(totalSwapFees);
            uint256 amountPlsxReflection = amountPls.mul(plsxReflectionFee).div(totalSwapFees);

            if (amountCodaLiquidity > 0) {
                try router.addLiquidityETH{value: amountPlsLiquidity}(address(this), amountCodaLiquidity, 0, amountPlsLiquidity, autoLiquidityReceiver, block.timestamp) {
                    totalPlsLpAdded = totalPlsLpAdded.add(amountPlsLiquidity);
                    totalCodaLpAdded = totalCodaLpAdded.add(amountCodaLiquidity);
                    emit AutoLiquify(amountCodaLiquidity, amountPlsLiquidity);
                } catch {
                    emit AutoLiquify(0, 0);
                }
            }

            if (amountWethReflection > 0) {
                try distributor.depositForWethReflection{value: amountWethReflection}() {} catch {}
            }

            if (amountWbtcReflection > 0) {
                try distributor.depositForWbtcReflection{value: amountWbtcReflection}() {} catch {}
            }

            if (amountPlsxReflection > 0) {
                try distributor.depositForPlsxReflection{value: amountPlsxReflection}() {} catch {}
            }

            if (address(this).balance > 0) {
                (bool success, ) = payable(owner()).call{value: address(this).balance, gas: 30000}("");
                success;
            }

            emit SwapBackSuccess(amountCodaSwap);
        } catch Error(string memory e) {
            emit SwapBackFailed(string(abi.encodePacked("SwapBack failed with error ", e)));
        } catch {
            emit SwapBackFailed("SwapBack failed without an error message from PulseX");
        }
    }

    function launch() external onlyOwner {
        require(launchedAt == 0, "Already launched.");
        launchedAt = block.timestamp;
        emit Launched(block.number, block.timestamp);
    }

    function setTxLimit(uint256 amount) external onlyOwner {
        require(amount >= _totalSupply / 2000);
        _maxTxAmount = amount;
    }

    function setIsDividendExempt(address holder, bool exempt) external onlyOwner {
        require(holder != address(this) && holder != pair);
        isDividendExempt[holder] = exempt;
        if (exempt) {
            distributor.setShare(holder, 0);
        } else {
            distributor.setShare(holder, _balances[holder]);
        }
    }

    function setIsFeeExempt(address holder, bool exempt) external onlyOwner {
        isFeeExempt[holder] = exempt;
    }

    function setIsTxLimitExempt(address holder, bool exempt) external onlyOwner {
        isTxLimitExempt[holder] = exempt;
    }

    function setFees(
        uint256 _codaBurnFee,
        uint256 _wethReflectionFee,
        uint256 _wbtcReflectionFee,
        uint256 _plsxReflectionFee,
        uint256 _liquidityFee,
        bool _feesOnNormalTransfers
    ) external onlyOwner {
        require(_codaBurnFee <= 100, "Burn fee cannot exceed 1%");
        require(_wethReflectionFee <= 300, "WETH reflection fee cannot exceed 3%");
        require(_wbtcReflectionFee <= 300, "pWBTC reflection fee cannot exceed 3%");
        require(_plsxReflectionFee <= 300, "PLSX reflection fee cannot exceed 3%");
        require(_liquidityFee <= 200, "Liquidity fee cannot exceed 2%");
        codaBurnFee = _codaBurnFee;
        wethReflectionFee = _wethReflectionFee;
        wbtcReflectionFee = _wbtcReflectionFee;
        plsxReflectionFee = _plsxReflectionFee;
        liquidityFee = _liquidityFee;
        uint256 total = codaBurnFee.add(wethReflectionFee).add(wbtcReflectionFee).add(plsxReflectionFee).add(liquidityFee);
        totalBuyFee = total;
        totalSellFee = total;
        require(total <= feeDenominator, "Total fees cannot exceed 10%");
        feesOnNormalTransfers = _feesOnNormalTransfers;
        emit ParameterUpdated();
    }

    function setLiquidityFeeReceiver(address _autoLiquidityReceiver) external onlyOwner {
        autoLiquidityReceiver = _autoLiquidityReceiver;
        emit ParameterUpdated();
    }

    function setSwapBackSettings(bool _enabled, uint256 _amount) external onlyOwner {
        swapEnabled = _enabled;
        swapThreshold = _amount;
        emit ParameterUpdated();
    }

    function setDistributionCriteria(
        uint256 _minWethPeriod,
        uint256 _minWethDistribution,
        uint256 _minWbtcPeriod,
        uint256 _minWbtcDistribution,
        uint256 _minPlsxPeriod,
        uint256 _minPlsxDistribution
    ) external onlyOwner {
        distributor.setDistributionCriteria(_minWethPeriod, _minWethDistribution, _minWbtcPeriod, _minWbtcDistribution, _minPlsxPeriod, _minPlsxDistribution);
        emit ParameterUpdated();
    }

    function setDistributorSettings(uint256 wethGas, uint256 wbtcGas, uint256 plsxGas) external onlyOwner {
        distributorWethGas = wethGas;
        distributorWbtcGas = wbtcGas;
        distributorPlsxGas = plsxGas;
        require(distributorWethGas <= 1000000 && distributorWbtcGas <= 1000000 && distributorPlsxGas <= 1000000, "Max gas is 1000000");
        emit ParameterUpdated();
    }

    function getCirculatingSupply() public view returns (uint256) {
        return _totalSupply.sub(balanceOf(DEAD));
    }

    function claimDividend() external {
        distributor.claimDividend();
    }

    // PER-WALLET TOTAL EARNED TRACKING
    function getTotalWethEarned(address holder) public view returns (uint256) {
        return distributor.getUnpaidWethEarnings(holder) + distributor.getWethTotalRealised(holder);
    }

    function getTotalWbtcEarned(address holder) public view returns (uint256) {
        return distributor.getUnpaidWbtcEarnings(holder) + distributor.getWbtcTotalRealised(holder);
    }

    function getTotalPlsxEarned(address holder) public view returns (uint256) {
        return distributor.getUnpaidPlsxEarnings(holder) + distributor.getPlsxTotalRealised(holder);
    }

    function addPair(address newPair) external onlyOwner {
        pairs.push(newPair);
        emit ParameterUpdated();
    }

    function removeLastPair() external onlyOwner {
        pairs.pop();
        emit ParameterUpdated();
    }

    event AutoLiquify(uint256 amountCoda, uint256 amountPLS);
    event Launched(uint256 blockNumber, uint256 timestamp);
    event ParameterUpdated();
    event SwapBackSuccess(uint256 amount);
    event SwapBackFailed(string message);
}