Skip to main content
PulseScanner.io

Address

0x094ccd94271ba882aa6222933fa1e018775d03c0
Current Holdings
$0.00
TXs sent
not counted
First Active
2025-10-27
block 24,866,581
Last Active
310 days ago
block 24,972,432
Funded By
0x7c5b…b7cc

Net worth historyi

22 snapshots · to block 27,455,298coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchZEROCHILLsolc 0.8.20+commit.a1b79de6runtime exact · creation exact
//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 IWPLS {
    function deposit() external payable;
    function withdraw(uint256) external;
}

interface IDividendDistributor {
    function setDistributionCriteria(uint256 _minZEROPeriod, uint256 _minZERODistribution, uint256 _minDaiPeriod, uint256 _minDaiDistribution, uint256 _minDOLAPeriod, uint256 _minDOLADistribution, uint256 _minWPLSPeriod, uint256 _minWPLSDistribution) external;
    function setShare(address shareholder, uint256 amount) external;
    function depositForZEROReflection() external payable;
    function depositForDaiReflection() external payable;
    function depositForDOLAReflection() external payable;
    function depositForWPLSReflection() external payable;
    function processZERO(uint256 gas) external;
    function processDai(uint256 gas) external;
    function processDOLA(uint256 gas) external;
    function processWPLS(uint256 gas) external;
    function claimDividend() external;
}

contract DividendDistributor is IDividendDistributor {
    using SafeMath for uint256;

    address _token;

    struct Share {
        uint256 amount;
        uint256 ZEROTotalExcluded;
        uint256 ZEROTotalRealised;
        uint256 DaiTotalExcluded;
        uint256 DaiTotalRealised;
        uint256 DOLATotalExcluded;
        uint256 DOLATotalRealised;
        uint256 WPLSTotalExcluded;
        uint256 WPLSTotalRealised;
    }

    IERC20 ZERO = IERC20(0xf6703DBff070F231eEd966D33B1B6D7eF5207d26);
    IERC20 Dai = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F);
    IERC20 DOLA = IERC20(0x865377367054516e17014CcdED1e7d814EDC9ce4);
    IERC20 WPLS = IERC20(0xA1077a294dDE1B09bB078844df40758a5D0f9a27);
    IERC20 WRAPPEDNATIVE = IERC20(0xA1077a294dDE1B09bB078844df40758a5D0f9a27);
    address DEAD = 0x0000000000000000000000000000000000000369;
    IDEXRouter public router;

    address[] shareholders;
    mapping(address => uint256) shareholderZEROIndexes;
    mapping(address => uint256) shareholderZEROClaims;
    mapping(address => uint256) shareholderDaiIndexes;
    mapping(address => uint256) shareholderDaiClaims;
    mapping(address => uint256) shareholderDOLAIndexes;
    mapping(address => uint256) shareholderDOLAClaims;
    mapping(address => uint256) shareholderWPLSIndexes;
    mapping(address => uint256) shareholderWPLSClaims;

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

    uint256 currentZEROIndex;
    uint256 public totalZERODividends;
    uint256 public totalZERODistributed;
    uint256 public ZERODividendsPerShare;
    uint256 public ZERODividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minZEROPeriod = 1 hours;
    uint256 public minZERODistribution = (1 * (10 ** 18));

    uint256 currentDaiIndex;
    uint256 public totalDaiDividends;
    uint256 public totalDaiDistributed;
    uint256 public DaiDividendsPerShare;
    uint256 public DaiDividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minDaiPeriod = 1 hours;
    uint256 public minDaiDistribution = 1000000;

    uint256 currentDOLAIndex;
    uint256 public totalDOLADividends;
    uint256 public totalDOLADistributed;
    uint256 public DOLADividendsPerShare;
    uint256 public DOLADividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minDOLAPeriod = 1 hours;
    uint256 public minDOLADistribution = 1000000;

    uint256 currentWPLSIndex;
    uint256 public totalWPLSDividends;
    uint256 public totalWPLSDistributed;
    uint256 public WPLSDividendsPerShare;
    uint256 public WPLSDividendsPerShareAccuracyFactor = 10 ** 36;
    uint256 public minWPLSPeriod = 1 hours;
    uint256 public minWPLSDistribution = 1000000;

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

    constructor() {
        router = IDEXRouter(0x165C3410fC91EF562C50559f7d2289fEbed552d9);
        _token = msg.sender;
    }

    function setDistributionCriteria(
        uint256 _minZEROPeriod,
        uint256 _minZERODistribution,
        uint256 _minDaiPeriod,
        uint256 _minDaiDistribution,
        uint256 _minDOLAPeriod,
        uint256 _minDOLADistribution,
        uint256 _minWPLSPeriod,
        uint256 _minWPLSDistribution
    ) external override onlyToken {
        minZEROPeriod = _minZEROPeriod;
        minZERODistribution = _minZERODistribution;
        minDaiPeriod = _minDaiPeriod;
        minDaiDistribution = _minDaiDistribution;
        minDOLAPeriod = _minDOLAPeriod;
        minDOLADistribution = _minDOLADistribution;
        minWPLSPeriod = _minWPLSPeriod;
        minWPLSDistribution = _minWPLSDistribution;
    }

    function setShare(address shareholder, uint256 amount) external override onlyToken {
        if (shares[shareholder].amount > 0) {
            distributeZERODividend(shareholder);
            distributeDaiDividend(shareholder);
            distributeDOLADividend(shareholder);
            distributeWPLSDividend(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].ZEROTotalExcluded = getCumulativeZERODividends(shares[shareholder].amount);
        shares[shareholder].DaiTotalExcluded = getCumulativeDaiDividends(shares[shareholder].amount);
        shares[shareholder].DOLATotalExcluded = getCumulativeDOLADividends(shares[shareholder].amount);
        shares[shareholder].WPLSTotalExcluded = getCumulativeWPLSDividends(shares[shareholder].amount);
    }

    function depositForZEROReflection() external payable override onlyToken {
        uint256 ZEROBalanceBefore = ZERO.balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = address(WRAPPEDNATIVE);
        path[1] = address(ZERO);
        
        router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp);
        
        uint256 ZEROGained = ZERO.balanceOf(address(this)).sub(ZEROBalanceBefore);
        totalZERODividends = totalZERODividends.add(ZEROGained);
        if (totalShares > 0) {
            ZERODividendsPerShare = ZERODividendsPerShare.add(ZERODividendsPerShareAccuracyFactor.mul(ZEROGained).div(totalShares));
        }
    }

    function depositForDaiReflection() external payable override onlyToken {
        uint256 DaiBalanceBefore = Dai.balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = address(WRAPPEDNATIVE);
        path[1] = address(Dai);
        
        router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp);
        
        uint256 DaiGained = Dai.balanceOf(address(this)).sub(DaiBalanceBefore);
        totalDaiDividends = totalDaiDividends.add(DaiGained);
        if (totalShares > 0) {
            DaiDividendsPerShare = DaiDividendsPerShare.add(DaiDividendsPerShareAccuracyFactor.mul(DaiGained).div(totalShares));
        }
    }

    function depositForDOLAReflection() external payable override onlyToken {
        uint256 DOLABalanceBefore = DOLA.balanceOf(address(this));
        address[] memory path = new address[](2);
        path[0] = address(WRAPPEDNATIVE);
        path[1] = address(DOLA);
        
        router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: msg.value}(0, path, address(this), block.timestamp);
        
        uint256 DOLAGained = DOLA.balanceOf(address(this)).sub(DOLABalanceBefore);
        totalDOLADividends = totalDOLADividends.add(DOLAGained);
        if (totalShares > 0) {
            DOLADividendsPerShare = DOLADividendsPerShare.add(DOLADividendsPerShareAccuracyFactor.mul(DOLAGained).div(totalShares));
        }
    }

    function depositForWPLSReflection() external payable override onlyToken {
        uint256 WPLSBalanceBefore = WPLS.balanceOf(address(this));
        
        // Wrap native PLS to WPLS
        IWPLS(address(WPLS)).deposit{value: msg.value}();
        
        uint256 WPLSGained = WPLS.balanceOf(address(this)).sub(WPLSBalanceBefore);
        totalWPLSDividends = totalWPLSDividends.add(WPLSGained);
        if (totalShares > 0) {
            WPLSDividendsPerShare = WPLSDividendsPerShare.add(WPLSDividendsPerShareAccuracyFactor.mul(WPLSGained).div(totalShares));
        }
    }

    function distributeZERODividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidZEROEarnings(shareholder);
        if (amount > 0) {
            totalZERODistributed = totalZERODistributed.add(amount);
            ZERO.transfer(shareholder, amount);
            shareholderZEROClaims[shareholder] = block.timestamp;
            shares[shareholder].ZEROTotalRealised = shares[shareholder].ZEROTotalRealised.add(amount);
            shares[shareholder].ZEROTotalExcluded = getCumulativeZERODividends(shares[shareholder].amount);
        }
    }

    function distributeDaiDividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidDaiEarnings(shareholder);
        if (amount > 0) {
            totalDaiDistributed = totalDaiDistributed.add(amount);
            Dai.transfer(shareholder, amount);
            shareholderDaiClaims[shareholder] = block.timestamp;
            shares[shareholder].DaiTotalRealised = shares[shareholder].DaiTotalRealised.add(amount);
            shares[shareholder].DaiTotalExcluded = getCumulativeDaiDividends(shares[shareholder].amount);
        }
    }

    function distributeDOLADividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidDOLAEarnings(shareholder);
        if (amount > 0) {
            totalDOLADistributed = totalDOLADistributed.add(amount);
            DOLA.transfer(shareholder, amount);
            shareholderDOLAClaims[shareholder] = block.timestamp;
            shares[shareholder].DOLATotalRealised = shares[shareholder].DOLATotalRealised.add(amount);
            shares[shareholder].DOLATotalExcluded = getCumulativeDOLADividends(shares[shareholder].amount);
        }
    }

    function distributeWPLSDividend(address shareholder) internal {
        if (shares[shareholder].amount == 0) { return; }
        uint256 amount = getUnpaidWPLSEarnings(shareholder);
        if (amount > 0) {
            totalWPLSDistributed = totalWPLSDistributed.add(amount);
            WPLS.transfer(shareholder, amount);
            shareholderWPLSClaims[shareholder] = block.timestamp;
            shares[shareholder].WPLSTotalRealised = shares[shareholder].WPLSTotalRealised.add(amount);
            shares[shareholder].WPLSTotalExcluded = getCumulativeWPLSDividends(shares[shareholder].amount);
        }
    }

    function processZERO(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 (currentZEROIndex >= shareholderCount) {
                currentZEROIndex = 0;
            }
            if (shouldZERODistribute(shareholders[currentZEROIndex])) {
                distributeZERODividend(shareholders[currentZEROIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentZEROIndex++;
            iterations++;
        }
    }

    function processDai(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 (currentDaiIndex >= shareholderCount) {
                currentDaiIndex = 0;
            }
            if (shouldDaiDistribute(shareholders[currentDaiIndex])) {
                distributeDaiDividend(shareholders[currentDaiIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentDaiIndex++;
            iterations++;
        }
    }

    function processDOLA(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 (currentDOLAIndex >= shareholderCount) {
                currentDOLAIndex = 0;
            }
            if (shouldDOLADistribute(shareholders[currentDOLAIndex])) {
                distributeDOLADividend(shareholders[currentDOLAIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentDOLAIndex++;
            iterations++;
        }
    }

    function processWPLS(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 (currentWPLSIndex >= shareholderCount) {
                currentWPLSIndex = 0;
            }
            if (shouldWPLSDistribute(shareholders[currentWPLSIndex])) {
                distributeWPLSDividend(shareholders[currentWPLSIndex]);
            }
            gasUsed = gasUsed.add(gasLeft.sub(gasleft()));
            gasLeft = gasleft();
            currentWPLSIndex++;
            iterations++;
        }
    }

    function shouldZERODistribute(address shareholder) internal view returns (bool) {
        return shareholderZEROClaims[shareholder] + minZEROPeriod < block.timestamp && getUnpaidZEROEarnings(shareholder) > minZERODistribution;
    }

    function shouldDaiDistribute(address shareholder) internal view returns (bool) {
        return shareholderDaiClaims[shareholder] + minDaiPeriod < block.timestamp && getUnpaidDaiEarnings(shareholder) > minDaiDistribution;
    }

    function shouldDOLADistribute(address shareholder) internal view returns (bool) {
        return shareholderDOLAClaims[shareholder] + minDOLAPeriod < block.timestamp && getUnpaidDOLAEarnings(shareholder) > minDOLADistribution;
    }

    function shouldWPLSDistribute(address shareholder) internal view returns (bool) {
        return shareholderWPLSClaims[shareholder] + minWPLSPeriod < block.timestamp && getUnpaidWPLSEarnings(shareholder) > minWPLSDistribution;
    }

    function claimDividend() external override {
        distributeZERODividend(msg.sender);
        distributeDaiDividend(msg.sender);
        distributeDOLADividend(msg.sender);
        distributeWPLSDividend(msg.sender);
    }

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

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

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

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

    function getCumulativeZERODividends(uint256 share) internal view returns (uint256) {
        return share.mul(ZERODividendsPerShare).div(ZERODividendsPerShareAccuracyFactor);
    }

    function getCumulativeDaiDividends(uint256 share) internal view returns (uint256) {
        return share.mul(DaiDividendsPerShare).div(DaiDividendsPerShareAccuracyFactor);
    }

    function getCumulativeDOLADividends(uint256 share) internal view returns (uint256) {
        return share.mul(DOLADividendsPerShare).div(DOLADividendsPerShareAccuracyFactor);
    }

    function getCumulativeWPLSDividends(uint256 share) internal view returns (uint256) {
        return share.mul(WPLSDividendsPerShare).div(WPLSDividendsPerShareAccuracyFactor);
    }

    function addShareholder(address shareholder) internal {
        shareholderZEROIndexes[shareholder] = shareholders.length;
        shareholderDaiIndexes[shareholder] = shareholders.length;
        shareholderDOLAIndexes[shareholder] = shareholders.length;
        shareholderWPLSIndexes[shareholder] = shareholders.length;
        shareholders.push(shareholder);
    }

    function removeShareholder(address shareholder) internal {
        shareholders[shareholderZEROIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderZEROIndexes[shareholders[shareholders.length - 1]] = shareholderZEROIndexes[shareholder];
        shareholders[shareholderDaiIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderDaiIndexes[shareholders[shareholders.length - 1]] = shareholderDaiIndexes[shareholder];
        shareholders[shareholderDOLAIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderDOLAIndexes[shareholders[shareholders.length - 1]] = shareholderDOLAIndexes[shareholder];
        shareholders[shareholderWPLSIndexes[shareholder]] = shareholders[shareholders.length - 1];
        shareholderWPLSIndexes[shareholders[shareholders.length - 1]] = shareholderWPLSIndexes[shareholder];
        shareholders.pop();
    }

    receive() external payable {}
}

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

    address WPLS = 0xA1077a294dDE1B09bB078844df40758a5D0f9a27;
    address ZERO = 0xf6703DBff070F231eEd966D33B1B6D7eF5207d26;
    address Dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
    address DOLA = 0x865377367054516e17014CcdED1e7d814EDC9ce4;
    address WRAPPEDNATIVE = 0xA1077a294dDE1B09bB078844df40758a5D0f9a27;
    address DEAD = 0x0000000000000000000000000000000000000369;

    string constant _name = unicode"ZERØ CHILL";
    string constant _symbol = unicode"NØ CHILL";
    uint8 constant _decimals = 18;

    uint256 _totalSupply = 3693693000000000000000000;
    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 tokenBurnFee = 400;
    uint256 public ZEROReflectionFee = 200;
    uint256 public DaiReflectionFee = 100;
    uint256 public DOLAReflectionFee = 100;
    uint256 public WPLSReflectionFee = 100;
    uint256 public liquidityFee = 100;
    uint256 public totalBuyFee = 1000;
    uint256 public totalSellFee = 1000;
    uint256 feeDenominator = 10000;
    bool public feesOnNormalTransfers = true;

    address public autoLiquidityReceiver = 0x0000000000000000000000000000000000000369;

    IDEXRouter public router;
    address public pair;
    address[] public pairs;

    uint256 public launchedAt;
    DividendDistributor public distributor;
    uint256 distributorZEROGas = 500000;
    uint256 distributorDaiGas = 500000;
    uint256 distributorDOLAGas = 500000;
    uint256 distributorWPLSGas = 500000;

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

    uint256 public totalTokenBurned;
    uint256 public totalNativeLpAdded;
    uint256 public totalTokenLpAdded;

    constructor() Ownable(msg.sender) {
        router = IDEXRouter(0x165C3410fC91EF562C50559f7d2289fEbed552d9);
        pair = IDEXFactory(router.factory()).createPair(WRAPPEDNATIVE, 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.processZERO(distributorZEROGas) {} catch {}
        try distributor.processDai(distributorDaiGas) {} catch {}
        try distributor.processDOLA(distributorDOLAGas) {} catch {}
        try distributor.processWPLS(distributorWPLSGas) {} 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 = tokenBurnFee.add(ZEROReflectionFee).add(DaiReflectionFee).add(DOLAReflectionFee).add(WPLSReflectionFee).add(liquidityFee);
        
        uint256 amountTokenLiquidity = swapThreshold.mul(liquidityFee).div(totalIndividualFees).div(2);
        uint256 amountTokenBurn = swapThreshold.mul(tokenBurnFee).div(totalIndividualFees);

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

        uint256 amountTokenSwap = swapThreshold.sub(amountTokenLiquidity).sub(amountTokenBurn);
        uint256 balanceBefore = address(this).balance;

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

        try router.swapExactTokensForETHSupportingFeeOnTransferTokens(amountTokenSwap, 0, path, address(this), block.timestamp) {
            uint256 amountNative = address(this).balance.sub(balanceBefore);
            uint256 totalSwapFees = totalIndividualFees.sub(liquidityFee.div(2)).sub(tokenBurnFee);

            uint256 amountNativeLiquidity = amountNative.mul(liquidityFee).div(totalSwapFees).div(2);
            uint256 amountZEROReflection = amountNative.mul(ZEROReflectionFee).div(totalSwapFees);
            uint256 amountDaiReflection = amountNative.mul(DaiReflectionFee).div(totalSwapFees);
            uint256 amountDOLAReflection = amountNative.mul(DOLAReflectionFee).div(totalSwapFees);
            uint256 amountWPLSReflection = amountNative.mul(WPLSReflectionFee).div(totalSwapFees);

            if (amountTokenLiquidity > 0) {
                try router.addLiquidityETH{value: amountNativeLiquidity}(address(this), amountTokenLiquidity, 0, amountNativeLiquidity, autoLiquidityReceiver, block.timestamp) {
                    totalNativeLpAdded = totalNativeLpAdded.add(amountNativeLiquidity);
                    totalTokenLpAdded = totalTokenLpAdded.add(amountTokenLiquidity);
                    emit AutoLiquify(amountTokenLiquidity, amountNativeLiquidity);
                } catch {
                    emit AutoLiquify(0, 0);
                }
            }

            if (amountZEROReflection > 0) {
                try distributor.depositForZEROReflection{value: amountZEROReflection}() {} catch {}
            }

            if (amountDaiReflection > 0) {
                try distributor.depositForDaiReflection{value: amountDaiReflection}() {} catch {}
            }

            if (amountDOLAReflection > 0) {
                try distributor.depositForDOLAReflection{value: amountDOLAReflection}() {} catch {}
            }

            if (amountWPLSReflection > 0) {
                try distributor.depositForWPLSReflection{value: amountWPLSReflection}() {} catch {}
            }

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

            emit SwapBackSuccess(amountTokenSwap);
        } 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 Router");
        }
    }

    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 _tokenBurnFee,
        uint256 _ZEROReflectionFee,
        uint256 _DaiReflectionFee,
        uint256 _DOLAReflectionFee,
        uint256 _WPLSReflectionFee,
        uint256 _liquidityFee,
        uint256 _totalBuyFee,
        uint256 _totalSellFee,
        bool _feesOnNormalTransfers
    ) external onlyOwner {
        tokenBurnFee = _tokenBurnFee;
        ZEROReflectionFee = _ZEROReflectionFee;
        DaiReflectionFee = _DaiReflectionFee;
        DOLAReflectionFee = _DOLAReflectionFee;
        WPLSReflectionFee = _WPLSReflectionFee;
        liquidityFee = _liquidityFee;
        totalBuyFee = _totalBuyFee;
        totalSellFee = _totalSellFee;
        require(tokenBurnFee.add(ZEROReflectionFee).add(DaiReflectionFee).add(DOLAReflectionFee).add(WPLSReflectionFee).add(liquidityFee) <= feeDenominator, "The total of all combined fees must be 1000 for 10 percent.");
        require(totalBuyFee <= feeDenominator, "Buy fee too high");
        require(totalSellFee <= feeDenominator, "Sell fee too high");
        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 _minZEROPeriod,
        uint256 _minZERODistribution,
        uint256 _minDaiPeriod,
        uint256 _minDaiDistribution,
        uint256 _minDOLAPeriod,
        uint256 _minDOLADistribution,
        uint256 _minWPLSPeriod,
        uint256 _minWPLSDistribution
    ) external onlyOwner {
        distributor.setDistributionCriteria(_minZEROPeriod, _minZERODistribution, _minDaiPeriod, _minDaiDistribution, _minDOLAPeriod, _minDOLADistribution, _minWPLSPeriod, _minWPLSDistribution);
        emit ParameterUpdated();
    }

    function setDistributorSettings(uint256 ZEROGas, uint256 DaiGas, uint256 DOLAGas, uint256 WPLSGas) external onlyOwner {
        distributorZEROGas = ZEROGas;
        distributorDaiGas = DaiGas;
        distributorDOLAGas = DOLAGas;
        distributorWPLSGas = WPLSGas;
        require(distributorZEROGas <= 1000000 && distributorDaiGas <= 1000000 && distributorDOLAGas <= 1000000 && distributorWPLSGas <= 1000000, "Max gas is 1000000");
        emit ParameterUpdated();
    }

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

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

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

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

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