ETH Price: $2,441.96 (+1.53%)

Transaction Decoder

Block:
21022599 at Oct-22-2024 05:25:35 PM +UTC
Transaction Fee:
0.001084374252611855 ETH $2.65
Gas Used:
57,791 Gas / 18.763721905 Gwei

Emitted Events:

175 UniswapV2Pair.Transfer( from=[Receiver] DAOTOKEN, to=0x7f6af9C71EC60f282b01575a4bE0930150013c53, value=10876362634496394036197 )

Account State Difference:

  Address   Before After State Difference Code
0x41902A30...E287e1626
(DefiAllOdds: Deployer)
0.087513573168957428 Eth
Nonce: 12
0.086429198916345573 Eth
Nonce: 13
0.001084374252611855
(Flashbots: Builder 2)
8.893523195250311293 Eth8.893631946354111293 Eth0.0001087511038
0xFF4D9A73...62eFA8566

Execution Trace

DAOTOKEN.CALL( )
  • UniswapV2Pair.balanceOf( 0x682F3317a8dB21Ba205DC84a0B7BD5010333bda7 ) => ( 10876362634496394036197 )
  • UniswapV2Pair.transfer( to=0x7f6af9C71EC60f282b01575a4bE0930150013c53, value=10876362634496394036197 ) => ( True )
    File 1 of 2: DAOTOKEN
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.12;
    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);
    }
    library Address {
        error AddressInsufficientBalance(address account);
        error AddressEmptyCode(address target);
        error FailedInnerCall();
        function functionCall(address target, bytes memory data) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0);
        }
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            if (address(this).balance < value) {
                revert AddressInsufficientBalance(address(this));
            }
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata);
        }
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata
        ) internal view returns (bytes memory) {
            if (!success) {
                _revert(returndata);
            } else {
                if (returndata.length == 0 && target.code.length == 0) {
                    revert AddressEmptyCode(target);
                }
                return returndata;
            }
        }
        function _revert(bytes memory returndata) private pure {
            if (returndata.length > 0) {
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert FailedInnerCall();
            }
        }
    }
    library SafeERC20 {
        using Address for address;
        error SafeERC20FailedOperation(address token);
        error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
        }
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
        }
        function _callOptionalReturn(IERC20 token, bytes memory data) private {
            bytes memory returndata = address(token).functionCall(data);
            if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                revert SafeERC20FailedOperation(address(token));
            }
        }
    }
    library MerkleProof {
       
        error MerkleProofInvalidMultiproof();
        function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
            return processProof(proof, leaf) == root;
        }
        function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
            return processProofCalldata(proof, leaf) == root;
        }
        function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
            bytes32 computedHash = leaf;
            for (uint256 i = 0; i < proof.length; i++) {
                computedHash = _hashPair(computedHash, proof[i]);
            }
            return computedHash;
        }
        function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
            bytes32 computedHash = leaf;
            for (uint256 i = 0; i < proof.length; i++) {
                computedHash = _hashPair(computedHash, proof[i]);
            }
            return computedHash;
        }
        function multiProofVerify(
            bytes32[] memory proof,
            bool[] memory proofFlags,
            bytes32 root,
            bytes32[] memory leaves
        ) internal pure returns (bool) {
            return processMultiProof(proof, proofFlags, leaves) == root;
        }
        function multiProofVerifyCalldata(
            bytes32[] calldata proof,
            bool[] calldata proofFlags,
            bytes32 root,
            bytes32[] memory leaves
        ) internal pure returns (bool) {
            return processMultiProofCalldata(proof, proofFlags, leaves) == root;
        }
        function processMultiProof(
            bytes32[] memory proof,
            bool[] memory proofFlags,
            bytes32[] memory leaves
        ) internal pure returns (bytes32 merkleRoot) {
            uint256 leavesLen = leaves.length;
            uint256 proofLen = proof.length;
            uint256 totalHashes = proofFlags.length;
            if (leavesLen + proofLen != totalHashes + 1) {
                revert MerkleProofInvalidMultiproof();
            }
            bytes32[] memory hashes = new bytes32[](totalHashes);
            uint256 leafPos = 0;
            uint256 hashPos = 0;
            uint256 proofPos = 0;
            for (uint256 i = 0; i < totalHashes; i++) {
                bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                bytes32 b = proofFlags[i]
                    ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                    : proof[proofPos++];
                hashes[i] = _hashPair(a, b);
            }
            if (totalHashes > 0) {
                if (proofPos != proofLen) {
                    revert MerkleProofInvalidMultiproof();
                }
                unchecked {
                    return hashes[totalHashes - 1];
                }
            } else if (leavesLen > 0) {
                return leaves[0];
            } else {
                return proof[0];
            }
        }
        function processMultiProofCalldata(
            bytes32[] calldata proof,
            bool[] calldata proofFlags,
            bytes32[] memory leaves
        ) internal pure returns (bytes32 merkleRoot) {
            uint256 leavesLen = leaves.length;
            uint256 proofLen = proof.length;
            uint256 totalHashes = proofFlags.length;
            if (leavesLen + proofLen != totalHashes + 1) {
                revert MerkleProofInvalidMultiproof();
            }
            bytes32[] memory hashes = new bytes32[](totalHashes);
            uint256 leafPos = 0;
            uint256 hashPos = 0;
            uint256 proofPos = 0;
            for (uint256 i = 0; i < totalHashes; i++) {
                bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                bytes32 b = proofFlags[i]
                    ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                    : proof[proofPos++];
                hashes[i] = _hashPair(a, b);
            }
            if (totalHashes > 0) {
                if (proofPos != proofLen) {
                    revert MerkleProofInvalidMultiproof();
                }
                unchecked {
                    return hashes[totalHashes - 1];
                }
            } else if (leavesLen > 0) {
                return leaves[0];
            } else {
                return proof[0];
            }
        }
        function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
            return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
        }
        function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
            assembly {
                mstore(0x00, a)
                mstore(0x20, b)
                value := keccak256(0x00, 0x40)
            }
        }
    }
    interface IUniswapV2Factory {
        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);
        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);
        function createPair(address tokenA, address tokenB) external returns (address pair);
        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
    }
    interface IUniswapV2Router01 {
        function factory() external pure returns (address);
        function WETH() external pure returns (address);
        function addLiquidity(
            address tokenA,
            address tokenB,
            uint amountADesired,
            uint amountBDesired,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB, uint liquidity);
        function addLiquidityETH(
            address token,
            uint amountTokenDesired,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
        function removeLiquidity(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB);
        function removeLiquidityETH(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountToken, uint amountETH);
        function removeLiquidityWithPermit(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountA, uint amountB);
        function removeLiquidityETHWithPermit(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountToken, uint amountETH);
        function swapExactTokensForTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapTokensForExactTokens(
            uint amountOut,
            uint amountInMax,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
            external
            payable
            returns (uint[] memory amounts);
        function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
            external
            returns (uint[] memory amounts);
        function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
            external
            returns (uint[] memory amounts);
        function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
            external
            payable
            returns (uint[] memory amounts);
        function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
        function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
        function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
        function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
        function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
    }
    interface IUniswapV2Router02 is IUniswapV2Router01 {
        function removeLiquidityETHSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountETH);
        function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax, uint8 v, bytes32 r, bytes32 s
        ) external returns (uint amountETH);
        function swapExactTokensForTokensSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
        function swapExactETHForTokensSupportingFeeOnTransferTokens(
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external payable;
        function swapExactTokensForETHSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
    }
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    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);
        }
    }
    contract DAOTOKEN is Ownable, IERC20 {
        using SafeERC20 for IERC20;
        event ChangeBuyTax(uint256 prevTax, uint256 newTax);
        event ChangeSellTax(uint256 prevTax, uint256 newTax);
        bool private _swap;
        uint8 private constant _decimals = 18;
        
        uint16 public buyTax = 500;
        uint16 public sellTax = 500;
        uint16 public constant denominator = 10_000;
        
        uint256 public constant maxSupply = 100_000_000 ether; 
        uint256 private _totalSupply = 61_000_000 ether; 
        uint256 public threshold = 0.25 ether; 
        uint256 public swapPct = 10_000; 
        uint256 public immutable genesis;
        uint256 public startLiquidity;
        uint256 public constant firstDate2024 = 1704067200; // 1st Jan 2024 00:00 GMT+0000.
        
        address payable private _multiSig;
        address public immutable pair;
        bytes32 public OGRoot;
        bytes32 public annualRoot;
        string private constant _name = "DAOGAME";
        string private constant _symbol = "DAOG";
        
        IUniswapV2Router02 immutable private uniV2Router;
       
        uint256[] public remainingCommunity = [1_000_000 ether, 1_000_000 ether];
        uint256[] public remainingTeam = [2_500_000 ether, 2_500_000 ether];
        uint256[] public remainingRewards = [12_000_000 ether, 10_000_000 ether, 10_000_000 ether];
        mapping(address => bool) private _isPool;
        mapping(address => uint256) private _balances;
        mapping(address => mapping (address => uint256)) private _allowances;
        mapping(address => bool) public exempted; 
        mapping(address => bytes32[]) public proofs; 
        constructor(address multiSig_, address router_) Ownable(msg.sender){
            require(
                multiSig_ != address(0) &&
                router_ != address(0),
                "zero address"
            );
            genesis = block.timestamp;
            exempted[_msgSender()] = true;
            exempted[multiSig_] = true;
            exempted[address(this)] = true;
            _balances[multiSig_] = 1_000_000 ether;
            _balances[_msgSender()] = 60_000_000 ether;
            uniV2Router = IUniswapV2Router02(router_); // mainnet 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
            _multiSig = payable(multiSig_);
            pair = IUniswapV2Factory(uniV2Router.factory()).createPair(uniV2Router.WETH(), address(this));
            _isPool[pair] = true;
        }
        modifier lockSwap {
            _swap = true;
            _;
            _swap = false;
        }
        receive() external payable {}
        function name() external pure returns (string memory) {
            return _name;
        }
        function symbol() external pure returns (string memory) {
            return _symbol;
        }
        function decimals() external pure returns (uint8) {
            return _decimals;
        }
        function totalSupply() external view override returns(uint256) {
            return _totalSupply;
        }
        function balanceOf(address account) external view override returns (uint256) {
            return _balances[account];
        }
        function allowance(address owner, address spender) external view override returns (uint256) {
            return _allowances[owner][spender];
        }
        function isPool(address addr) external view returns (bool){
            return _isPool[addr];
        }
        function approve(address spender, uint256 amount) external override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
        }
        function transfer(address recipient, uint256 amount) external override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
        function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
            require (_allowances[sender][_msgSender()] >= amount, "ERC20: transfer amount exceeds allowance");
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()] - amount);
            return true;
        }
        function setProof(bytes32[] memory _proof) external {
            proofs[_msgSender()] = _proof;
        }
        function setBuyTax(uint16 newTax) external onlyOwner {
            require (newTax <= 500, "tax cannot exceed 5%");
            emit ChangeBuyTax(buyTax, newTax);
            buyTax = newTax;
        }
        function setSellTax(uint16 newTax) external onlyOwner {
            require (newTax <= 500, "tax cannot exceed 5%");
            emit ChangeSellTax(sellTax, newTax);
            sellTax = newTax;
        }
        function setExempted(address _address, bool exempt_) external onlyOwner {
           exempted[_address] = exempt_;
        }
        function setPool(address addr, bool isPool_) external onlyOwner {
            require(addr != address(0), "zero address cannot be pool");
            _isPool[addr] = isPool_;
        }
        function safeTokenSwap(uint256 amount) external onlyOwner {
            _tokensToETH(amount);
        }
        function safeETHtransfer() external onlyOwner {
            (bool success,) = _multiSig.call{value: address(this).balance}("");
            require(success, "Failed to send Ether");
        }
        function setOGRoot(bytes32 _OGRoot) external onlyOwner {
            OGRoot = _OGRoot;
        }
        
        function setAnnualRoot(bytes32 _annualRoot) external onlyOwner {
            annualRoot = _annualRoot;
        }
        function setStartLiquidity() external onlyOwner {
            require(startLiquidity == 0, "already set");
            startLiquidity = block.timestamp;
        }
        function setThreshold(uint256 _threshold) external onlyOwner {
            threshold = _threshold;
        }
        function setSwapPct(uint256 _swapPct) external onlyOwner {
            require(_swapPct <= denominator, "wrong pct");
            swapPct = _swapPct;
        }
        function mintCommunity() external onlyOwner {
            _mint(remainingCommunity);
        }
        function mintTeam() external onlyOwner {
            _mint(remainingTeam);
        }
        function mintRewards() external onlyOwner {
            uint256 available;
            if(block.timestamp >= firstDate2024 + 2 * (365.25 * 1 days)) {
                available += remainingRewards[2];
                delete remainingRewards[2];
            }
            if(block.timestamp >= firstDate2024 +  (365.25 * 1 days)) {
                available += remainingRewards[1];
                delete remainingRewards[1];
            }
            if(block.timestamp >= firstDate2024) {
                available += remainingRewards[0];
                delete remainingRewards[0];
            }
            _mintAvailable(available);
        }
        function setMultiSig(address payable multiSig_) external onlyOwner {
            _multiSig = multiSig_;
        }
        function withdrawLiquidity() external onlyOwner {
            // lock 1 year
            require(
                startLiquidity != 0 &&
                block.timestamp >= startLiquidity + (365.25 * 1 days),
                "not yet"
            );
            uint256 lpBalance = IERC20(pair).balanceOf(address(this));
            require(lpBalance != 0, "zero lp balance");
            IERC20(pair).safeTransfer(_multiSig, lpBalance);
        }
        function _approve(address owner, address spender, uint256 amount) private {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
        function _transfer(address sender, address recipient, uint256 amount) private {
            require(amount != 0, "cannot transfer zero");
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            require(_balances[sender] >= amount, "ERC20: transfer exceeds balance");
            require(!(_isPool[sender] && _isPool[recipient]), "cannot transfer pool to pool");
            
            require(
                startLiquidity != 0
                || exempted[sender]
                || exempted[recipient],
                 "unauthorized transfer"
            );
            
            uint256 taxedAmount = amount;
            
            if(startLiquidity != 0){
                uint256 tax;
                bool buy;
                bool sell;
                
                // if buy
                if(_isPool[sender]) {
                    buy = true;
                } else if(_isPool[recipient]) {
                    sell = true;
                }
                // whitelist verification
                if(buy && !exempted[recipient]) {
                    if(block.timestamp <= startLiquidity + 1 hours / 2) {
                        _verify(recipient, OGRoot);
                    } else if(block.timestamp <= startLiquidity + 1 hours) {
                        _verify(recipient, annualRoot);
                    }
                    
                    // apply buy tax
                    tax = amount * buyTax / denominator;  
                } else if(sell && !exempted[sender]) {
                    // apply sell tax
                    tax = amount * sellTax / denominator;
                }
                if(tax != 0){
                    unchecked {
                        taxedAmount -= tax;
                        _balances[address(this)] += tax;
                    }
                    emit Transfer(sender, address(this), tax);
                }
                if(sell && _balances[address(this)] != 0) {
                    address[] memory path = _getPath();
                    uint256 amountOut = uniV2Router.getAmountsOut(_balances[address(this)], path)[1];
                    // DAOG amount
                    if (amountOut >= threshold && !_swap && swapPct != 0) {
                        _tokensToETH(_balances[address(this)] * swapPct / denominator);
                    }
                }
            }
            
        
            // 0.5% limit 1st 24h
            if(block.timestamp <= startLiquidity + 1 days ){
                _checkLimits(
                    recipient, 
                    taxedAmount,
                    50
                );
            
            // 1% limit next 72h
            } else if(block.timestamp <= startLiquidity + 4 days) {
                _checkLimits(
                    recipient, 
                    taxedAmount,
                    100
                );
            }
            unchecked{
                _balances[recipient] += taxedAmount;
                _balances[sender] -= amount;
            }
            emit Transfer(sender, recipient, taxedAmount);
        }
        function _mint(uint256[] storage remaining) private {
            uint256 available;
            if(block.timestamp >= genesis + (365.25 * 2 days) ) {
                available += remaining[1];
                delete remaining[1];
            }
            if(block.timestamp >= genesis + (365.25 * 1 days)) {
                available += remaining[0];
                delete remaining[0];
            }
            
            _mintAvailable(available);
        }
        function _checkLimits(
            address recipient, 
            uint256 taxedAmount, 
            uint8 pct
        ) private view {
            uint256 limit = maxSupply * pct / denominator;
            string memory pctStr = pct == 50 ? "0.5% supply": "1% supply";
            
            if(!exempted[recipient] && !_isPool[recipient]) {
                require(
                    _balances[recipient] + taxedAmount <= limit,
                    string.concat("recipient balance ", pctStr)
                );
            }
        }
        function _verify(address _whitelisted, bytes32 _root) private view {
            string memory group = _root == OGRoot ? "OG" : "Annual";
            
            require(
                MerkleProof.verify(
                    proofs[_whitelisted], 
                    _root, 
                    keccak256(abi.encodePacked(_whitelisted))
                ),
                string.concat("not whitelisted ", group)
            );
        }
        function _getPath() private view returns(address[] memory) {
            address[] memory path = new address[](2);
            path[0] = address(this);
            path[1] = uniV2Router.WETH();
            return path;
        }
        function _tokensToETH(uint256 amount) private lockSwap {
            if(_multiSig != address(0)){
                address[] memory path = _getPath();
                _approve(address(this), address(uniV2Router), amount);
                
                uniV2Router
                .swapExactTokensForETHSupportingFeeOnTransferTokens(
                    amount,
                    0,
                    path,
                    _multiSig,
                    block.timestamp
                );
            }
        }
        function _mintAvailable(uint256 available) private {
            require(available != 0, "nothing to withdraw");
            unchecked {
                _balances[_multiSig] += available;
                _totalSupply += available;
            }
            require(_totalSupply <= maxSupply, "wrong supply");
            emit Transfer(address(0), _multiSig, available);
        }
    }

    File 2 of 2: UniswapV2Pair
    // File: contracts/interfaces/IUniswapV2Pair.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Pair {
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external pure returns (string memory);
        function symbol() external pure returns (string memory);
        function decimals() external pure returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    
        function DOMAIN_SEPARATOR() external view returns (bytes32);
        function PERMIT_TYPEHASH() external pure returns (bytes32);
        function nonces(address owner) external view returns (uint);
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint112 reserve0, uint112 reserve1);
    
        function MINIMUM_LIQUIDITY() external pure returns (uint);
        function factory() external view returns (address);
        function token0() external view returns (address);
        function token1() external view returns (address);
        function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
        function price0CumulativeLast() external view returns (uint);
        function price1CumulativeLast() external view returns (uint);
        function kLast() external view returns (uint);
    
        function mint(address to) external returns (uint liquidity);
        function burn(address to) external returns (uint amount0, uint amount1);
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
        function skim(address to) external;
        function sync() external;
    
        function initialize(address, address) external;
    }
    
    // File: contracts/interfaces/IUniswapV2ERC20.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2ERC20 {
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external pure returns (string memory);
        function symbol() external pure returns (string memory);
        function decimals() external pure returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    
        function DOMAIN_SEPARATOR() external view returns (bytes32);
        function PERMIT_TYPEHASH() external pure returns (bytes32);
        function nonces(address owner) external view returns (uint);
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    }
    
    // File: contracts/libraries/SafeMath.sol
    
    pragma solidity =0.5.16;
    
    // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
    
    library SafeMath {
        function add(uint x, uint y) internal pure returns (uint z) {
            require((z = x + y) >= x, 'ds-math-add-overflow');
        }
    
        function sub(uint x, uint y) internal pure returns (uint z) {
            require((z = x - y) <= x, 'ds-math-sub-underflow');
        }
    
        function mul(uint x, uint y) internal pure returns (uint z) {
            require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
        }
    }
    
    // File: contracts/UniswapV2ERC20.sol
    
    pragma solidity =0.5.16;
    
    
    
    contract UniswapV2ERC20 is IUniswapV2ERC20 {
        using SafeMath for uint;
    
        string public constant name = 'Uniswap V2';
        string public constant symbol = 'UNI-V2';
        uint8 public constant decimals = 18;
        uint  public totalSupply;
        mapping(address => uint) public balanceOf;
        mapping(address => mapping(address => uint)) public allowance;
    
        bytes32 public DOMAIN_SEPARATOR;
        // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        mapping(address => uint) public nonces;
    
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        constructor() public {
            uint chainId;
            assembly {
                chainId := chainid
            }
            DOMAIN_SEPARATOR = keccak256(
                abi.encode(
                    keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                    keccak256(bytes(name)),
                    keccak256(bytes('1')),
                    chainId,
                    address(this)
                )
            );
        }
    
        function _mint(address to, uint value) internal {
            totalSupply = totalSupply.add(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(address(0), to, value);
        }
    
        function _burn(address from, uint value) internal {
            balanceOf[from] = balanceOf[from].sub(value);
            totalSupply = totalSupply.sub(value);
            emit Transfer(from, address(0), value);
        }
    
        function _approve(address owner, address spender, uint value) private {
            allowance[owner][spender] = value;
            emit Approval(owner, spender, value);
        }
    
        function _transfer(address from, address to, uint value) private {
            balanceOf[from] = balanceOf[from].sub(value);
            balanceOf[to] = balanceOf[to].add(value);
            emit Transfer(from, to, value);
        }
    
        function approve(address spender, uint value) external returns (bool) {
            _approve(msg.sender, spender, value);
            return true;
        }
    
        function transfer(address to, uint value) external returns (bool) {
            _transfer(msg.sender, to, value);
            return true;
        }
    
        function transferFrom(address from, address to, uint value) external returns (bool) {
            if (allowance[from][msg.sender] != uint(-1)) {
                allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
            }
            _transfer(from, to, value);
            return true;
        }
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
            require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
            bytes32 digest = keccak256(
                abi.encodePacked(
                    '\x19\x01',
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );
            address recoveredAddress = ecrecover(digest, v, r, s);
            require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
            _approve(owner, spender, value);
        }
    }
    
    // File: contracts/libraries/Math.sol
    
    pragma solidity =0.5.16;
    
    // a library for performing various math operations
    
    library Math {
        function min(uint x, uint y) internal pure returns (uint z) {
            z = x < y ? x : y;
        }
    
        // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
        function sqrt(uint y) internal pure returns (uint z) {
            if (y > 3) {
                z = y;
                uint x = y / 2 + 1;
                while (x < z) {
                    z = x;
                    x = (y / x + x) / 2;
                }
            } else if (y != 0) {
                z = 1;
            }
        }
    }
    
    // File: contracts/libraries/UQ112x112.sol
    
    pragma solidity =0.5.16;
    
    // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
    
    // range: [0, 2**112 - 1]
    // resolution: 1 / 2**112
    
    library UQ112x112 {
        uint224 constant Q112 = 2**112;
    
        // encode a uint112 as a UQ112x112
        function encode(uint112 y) internal pure returns (uint224 z) {
            z = uint224(y) * Q112; // never overflows
        }
    
        // divide a UQ112x112 by a uint112, returning a UQ112x112
        function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
            z = x / uint224(y);
        }
    }
    
    // File: contracts/interfaces/IERC20.sol
    
    pragma solidity >=0.5.0;
    
    interface IERC20 {
        event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external view returns (string memory);
        function symbol() external view returns (string memory);
        function decimals() external view returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    }
    
    // File: contracts/interfaces/IUniswapV2Factory.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Factory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);
    
        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);
    
        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);
    
        function createPair(address tokenA, address tokenB) external returns (address pair);
    
        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
    }
    
    // File: contracts/interfaces/IUniswapV2Callee.sol
    
    pragma solidity >=0.5.0;
    
    interface IUniswapV2Callee {
        function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
    }
    
    // File: contracts/UniswapV2Pair.sol
    
    pragma solidity =0.5.16;
    
    
    
    
    
    
    
    
    contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
        using SafeMath  for uint;
        using UQ112x112 for uint224;
    
        uint public constant MINIMUM_LIQUIDITY = 10**3;
        bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
    
        address public factory;
        address public token0;
        address public token1;
    
        uint112 private reserve0;           // uses single storage slot, accessible via getReserves
        uint112 private reserve1;           // uses single storage slot, accessible via getReserves
        uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
    
        uint public price0CumulativeLast;
        uint public price1CumulativeLast;
        uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
    
        uint private unlocked = 1;
        modifier lock() {
            require(unlocked == 1, 'UniswapV2: LOCKED');
            unlocked = 0;
            _;
            unlocked = 1;
        }
    
        function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
            _reserve0 = reserve0;
            _reserve1 = reserve1;
            _blockTimestampLast = blockTimestampLast;
        }
    
        function _safeTransfer(address token, address to, uint value) private {
            (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
            require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
        }
    
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint112 reserve0, uint112 reserve1);
    
        constructor() public {
            factory = msg.sender;
        }
    
        // called once by the factory at time of deployment
        function initialize(address _token0, address _token1) external {
            require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
            token0 = _token0;
            token1 = _token1;
        }
    
        // update reserves and, on the first call per block, price accumulators
        function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
            require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
            uint32 blockTimestamp = uint32(block.timestamp % 2**32);
            uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
            if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                // * never overflows, and + overflow is desired
                price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
            }
            reserve0 = uint112(balance0);
            reserve1 = uint112(balance1);
            blockTimestampLast = blockTimestamp;
            emit Sync(reserve0, reserve1);
        }
    
        // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
        function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
            address feeTo = IUniswapV2Factory(factory).feeTo();
            feeOn = feeTo != address(0);
            uint _kLast = kLast; // gas savings
            if (feeOn) {
                if (_kLast != 0) {
                    uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                    uint rootKLast = Math.sqrt(_kLast);
                    if (rootK > rootKLast) {
                        uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                        uint denominator = rootK.mul(5).add(rootKLast);
                        uint liquidity = numerator / denominator;
                        if (liquidity > 0) _mint(feeTo, liquidity);
                    }
                }
            } else if (_kLast != 0) {
                kLast = 0;
            }
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function mint(address to) external lock returns (uint liquidity) {
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            uint balance0 = IERC20(token0).balanceOf(address(this));
            uint balance1 = IERC20(token1).balanceOf(address(this));
            uint amount0 = balance0.sub(_reserve0);
            uint amount1 = balance1.sub(_reserve1);
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            if (_totalSupply == 0) {
                liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
               _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
            } else {
                liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
            }
            require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
            _mint(to, liquidity);
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Mint(msg.sender, amount0, amount1);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function burn(address to) external lock returns (uint amount0, uint amount1) {
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            address _token0 = token0;                                // gas savings
            address _token1 = token1;                                // gas savings
            uint balance0 = IERC20(_token0).balanceOf(address(this));
            uint balance1 = IERC20(_token1).balanceOf(address(this));
            uint liquidity = balanceOf[address(this)];
    
            bool feeOn = _mintFee(_reserve0, _reserve1);
            uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
            amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
            amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
            require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
            _burn(address(this), liquidity);
            _safeTransfer(_token0, to, amount0);
            _safeTransfer(_token1, to, amount1);
            balance0 = IERC20(_token0).balanceOf(address(this));
            balance1 = IERC20(_token1).balanceOf(address(this));
    
            _update(balance0, balance1, _reserve0, _reserve1);
            if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
            emit Burn(msg.sender, amount0, amount1, to);
        }
    
        // this low-level function should be called from a contract which performs important safety checks
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
            require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
            (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
            require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
    
            uint balance0;
            uint balance1;
            { // scope for _token{0,1}, avoids stack too deep errors
            address _token0 = token0;
            address _token1 = token1;
            require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
            if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
            if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
            if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
            balance0 = IERC20(_token0).balanceOf(address(this));
            balance1 = IERC20(_token1).balanceOf(address(this));
            }
            uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
            uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
            require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
            { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
            uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
            uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
            require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
            }
    
            _update(balance0, balance1, _reserve0, _reserve1);
            emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
        }
    
        // force balances to match reserves
        function skim(address to) external lock {
            address _token0 = token0; // gas savings
            address _token1 = token1; // gas savings
            _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
            _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
        }
    
        // force reserves to match balances
        function sync() external lock {
            _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
        }
    }