false
true
0

Contract Address Details

0x1aDCfd95C40E8eb576fC48D19445Afc1C76089cF

Token
Darth Wojak: pulselorian.com (DWOJAK)
Creator
0xb0c2b1–982523 at 0x5ea8da–a1ec9f
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
1,377 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
27556762
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
DWOJAK




Optimization enabled
true
Compiler version
v0.8.20+commit.a1b79de6




Optimization runs
1000000
EVM Version
default




Verified at
2023-07-16T22:48:50.837570Z

Constructor Arguments

0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9000000000000000000000000fb7103d7011dfa60c18c6961c5a38038d8048fe000000000000000000000000043f11890f3d8ee704595eba88f52ee7d983b6907000000000000000000000000000000000000000000000000000000000000001c446172746820576f6a616b3a2070756c73656c6f7269616e2e636f6d00000000000000000000000000000000000000000000000000000000000000000000000644574f4a414b0000000000000000000000000000000000000000000000000000

Arg [0] (string) : Darth Wojak: pulselorian.com
Arg [1] (string) : DWOJAK
Arg [2] (address) : 0x165c3410fc91ef562c50559f7d2289febed552d9
Arg [3] (address) : 0xfb7103d7011dfa60c18c6961c5a38038d8048fe0
Arg [4] (address) : 0x43f11890f3d8ee704595eba88f52ee7d983b6907

              

contracts/DWOJAK.sol

/*
 * @title DWOJAK - Darth Wojak - LP staking
 * @notice https://pulselorian.com/darthWojak
 *
 * DWOJAK is our attempt to develop a better internet currency with no fees
 * It allows staking liquidity pair of this token with WPLS to earn amazing yields
 * It's deflationary - fixed supply with burn on trades and stake/unstake
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity ^0.8.20;

import "./imports/Manageable.sol";
import "./lib/DSMath.sol";
import "./openzeppelin/access/Ownable.sol";
import "./openzeppelin/security/Pausable.sol";
import "./openzeppelin/token/ERC20/IERC20.sol";
import "./openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import "./openzeppelin/token/ERC20/utils/SafeERC20.sol";
import "./uniswap/v2-core/interfaces/IUniswapV2Factory.sol";
import "./uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol";

contract DWOJAK is
    Manageable,
    DSMath,
    Ownable,
    Pausable,
    IERC20,
    IERC20Metadata
{
    using SafeERC20 for IERC20;

    struct Stake {
        uint256 stakeAmt;
        uint256 rewardDebt;
        uint256 since;
    }

    struct StakeHolder {
        address user;
        Stake[] userStakes;
    }

    address[] public lpPairs;

    StakeHolder[] public stakeHolders;

    address private _feeAddr1;
    address private _feeAddr2;
    address private constant _BURN_ADDRESS = address(0x369);

    bool public enforceWalletTokenLimit = true;

    mapping(address => bool) private _excludedFromAntiWhale;
    mapping(address => bool) private _isAMMPair;
    mapping(address => uint256) private _pairIndex;
    mapping(address => bool) private _paysNoFee;
    mapping(address => mapping(address => uint256)) private _allowances;
    mapping(address => uint256) private _balances;
    mapping(address => uint256) private _stakeIndexMap;

    string private _name;
    string private _symbol;

    uint256 private _lastDistTS; // timestamp of last rewards calc
    uint256 private _deployedTS;
    uint256 private _rewardsPerToken; // inflated by _REWARDX times to allow for small values

    uint256 private constant _BIPS = 1e4;
    uint256 private constant _INF_RATE_PER_SEC_RAY = 9999999978 * 1e17;
    uint256 private constant _REWARDX = 1e12;
    uint256 private constant _SECS_IN_FOUR_WEEKS = 2419200;
    uint256 private constant _STAKE_FEE_BIPS = 100;
    uint256 private constant _TOTAL_SUPPLY = 1e27; // 1 billion + 18 decimals
    uint256 private constant _TRADE_BURN_BIPS = 40;
    uint256 private constant _PER_SEC_LIMIT_CHANGE = 1e21; // 1000 + 18 decimals

    uint256 private _maxWalletTokenLimit;
    uint256 public rewardsAvailableToEarn;
    uint256 public totalStakedSupply; // total staked tokens

    event AntiWhaleExclusionChanged(address wallet, bool excluded);
    event PaysNoFeesChanged(address wallet, bool paysNoFee);
    event Staked(
        address indexed user,
        uint256 stakeIndex,
        uint256 stakeAmt,
        uint256 rewardDebt,
        uint256 since
    );
    event Unstaked(
        address indexed user,
        uint256 stakeAmt,
        uint256 rewardDebt,
        uint256 since,
        uint256 till
    );

    constructor(
        string memory name_,
        string memory symbol_,
        address routerAddress_,
        address feeAddr1_,
        address feeAddr2_
    ) {
        _name = name_;
        _symbol = symbol_;
        _paysNoFee[msg.sender] = true;
        _excludedFromAntiWhale[msg.sender] = true;
        stakeHolders.push(); // Null staker is a must at index 0

        _feeAddr1 = feeAddr1_;
        _paysNoFee[feeAddr1_] = true;
        _excludedFromAntiWhale[feeAddr1_] = true;
        _feeAddr2 = feeAddr2_;
        _paysNoFee[feeAddr2_] = true;
        _excludedFromAntiWhale[feeAddr2_] = true;
        _paysNoFee[routerAddress_] = true;
        _excludedFromAntiWhale[routerAddress_] = true;

        uint256 ownerBal = _TOTAL_SUPPLY / 10;
        rewardsAvailableToEarn = (_TOTAL_SUPPLY * 9) / 10;

        _balances[msg.sender] = ownerBal;
        emit Transfer(address(0), msg.sender, ownerBal);

        _lastDistTS = block.timestamp;
        _deployedTS = block.timestamp;
        lpPairs.push(); // null address at index 0

        IUniswapV2Router02 _dexRouterV2 = IUniswapV2Router02(routerAddress_);
        IUniswapV2Factory _dexFactoryV2 = IUniswapV2Factory(
            _dexRouterV2.factory()
        );
        address lpPair = _dexFactoryV2.createPair(
            address(this),
            _dexRouterV2.WPLS()
        );
        lpPairs.push(address(lpPair));
        _pairIndex[address(lpPair)] = lpPairs.length - 1;
        _excludedFromAntiWhale[address(lpPair)] = true;
    }

    receive() external payable {}

    fallback() external payable {}

    function _addStakeHolder(address staker_) private returns (uint256) {
        stakeHolders.push();
        uint256 stakerIndex = stakeHolders.length - 1;
        stakeHolders[stakerIndex].user = staker_;
        _stakeIndexMap[staker_] = stakerIndex;
        return stakerIndex;
    }

    function _approve(address from_, address spender_, uint256 amt_) private {
        _allowances[from_][spender_] = amt_;
        emit Approval(from_, spender_, amt_);
    }

    function _calculateFees(
        uint256 amt_
    ) private pure returns (uint256 burnAmt, uint256 netAmt) {
        burnAmt = (amt_ * _TRADE_BURN_BIPS) / _BIPS;
        netAmt = amt_ - burnAmt;
        return (burnAmt, netAmt);
    }

    function _callAndParseAddressReturn(
        address token_,
        bytes4 selector_
    ) internal view returns (address) {
        (bool success, bytes memory data) = token_.staticcall(
            abi.encodeWithSelector(selector_)
        );

        // if not implemented, or returns empty data, return empty string
        if (!success || data.length == 0) {
            return address(0);
        }

        // if implemented, or returns data, return decoded int24 else return 0
        if (data.length == 32) {
            return abi.decode(data, (address));
        }

        return address(0);
    }

    function _calcInflation(
        uint256 nowTS_
    ) private view returns (uint256 inflation, uint256 tmpRewardsPerToken) {
        require(_lastDistTS != 0, "Inflation not started!");
        uint256 secsElapsed = (nowTS_ - _lastDistTS);
        if (secsElapsed != 0) {
            uint256 infFracRay = rpow(_INF_RATE_PER_SEC_RAY, secsElapsed);
            inflation =
                rewardsAvailableToEarn -
                (rewardsAvailableToEarn * infFracRay) /
                RAY;
            if (totalStakedSupply != 0) {
                tmpRewardsPerToken =
                    _rewardsPerToken +
                    (inflation * _REWARDX) /
                    totalStakedSupply;
            }
        } else {
            tmpRewardsPerToken = _rewardsPerToken;
        }

        return (inflation, tmpRewardsPerToken);
    }

    function _checkIfAMMPair(address target_) internal {
        if (target_.code.length == 0) return;
        if (!_isAMMPair[target_]) {
            address token0 = _getToken0(target_);
            if (token0 == address(0)) {
                return;
            }

            address token1 = _getToken1(target_);
            if (token1 == address(0)) {
                return;
            }

            _isAMMPair[target_] = true;
            _excludedFromAntiWhale[target_] = true;
        }
    }

    function _creditInflation() private {
        uint256 nowTS = block.timestamp;
        if (nowTS > _lastDistTS) {
            (uint256 inflation, uint256 tmpRewardsPerToken) = _calcInflation(
                nowTS
            );
            if (inflation != 0) {
                _lastDistTS = nowTS;
                rewardsAvailableToEarn -= inflation;
                _balances[address(this)] += inflation;
                emit Transfer(address(0), address(this), inflation);
                _rewardsPerToken = tmpRewardsPerToken;
            }
        }
    }

    function _getCurrStake(
        uint256 stakerIndex_,
        uint256 stakeIndex_
    ) private view returns (Stake memory currStake) {
        require(
            stakeIndex_ < stakeHolders[stakerIndex_].userStakes.length,
            "Stake index incorrect!"
        );

        currStake = stakeHolders[stakerIndex_].userStakes[stakeIndex_];

        return currStake;
    }

    function _getToken0(
        address target_
    ) internal view returns (address targetToken0) {
        targetToken0 = _callAndParseAddressReturn(
            target_,
            hex"0dfe1681" // token0()
        );

        return targetToken0;
    }

    function _getToken1(
        address target_
    ) internal view returns (address targetToken1) {
        targetToken1 = _callAndParseAddressReturn(
            target_,
            hex"d21220a7" // token1()
        );

        return targetToken1;
    }

    function _needsWhaleCheck(
        address from_,
        address to_
    ) internal view returns (bool) {
        return (enforceWalletTokenLimit &&
            from_ != owner() &&
            to_ != owner() &&
            !_excludedFromAntiWhale[to_]);
    }

    function _penaltyFor(
        uint256 fromTimestamp_,
        uint256 toTimestamp_
    ) private pure returns (uint256 penaltyBasis) {
        if (fromTimestamp_ + 52 weeks > toTimestamp_) {
            uint256 fourWeeksElapsed = (toTimestamp_ - fromTimestamp_) /
                _SECS_IN_FOUR_WEEKS;
            if (fourWeeksElapsed < 13) {
                penaltyBasis = (13 - fourWeeksElapsed) * 100;
            }
        }
        return penaltyBasis;
    }

    function _stake(address lpPair_, uint256 stakeAmt_) private {
        _creditInflation();

        uint256 saFee;
        uint256 stakeAmt;
        if (_paysNoFee[msg.sender]) {
            stakeAmt = stakeAmt_;
        } else {
            saFee = (stakeAmt_ * _STAKE_FEE_BIPS) / _BIPS;
            stakeAmt = stakeAmt_ - saFee - saFee;
        }
        IERC20 lpPair = IERC20(lpPair_);
        lpPair.safeTransferFrom(msg.sender, address(this), stakeAmt);
        if (saFee > 0) {
            lpPair.safeTransferFrom(msg.sender, _feeAddr1, saFee);
            lpPair.safeTransferFrom(msg.sender, _feeAddr2, saFee);
        }
        uint256 stakerIndex = _stakeIndexMap[msg.sender];

        if (stakerIndex == 0) {
            stakerIndex = _addStakeHolder(msg.sender);
        }
        uint256 rewardDebt = (_rewardsPerToken * stakeAmt) / _REWARDX;
        stakeHolders[stakerIndex].userStakes.push(
            Stake(stakeAmt, rewardDebt, block.timestamp)
        );

        totalStakedSupply += stakeAmt;
        emit Staked(
            msg.sender,
            stakeHolders[stakerIndex].userStakes.length - 1,
            stakeAmt,
            rewardDebt,
            block.timestamp
        );
    }

    function _transfer(
        address from_,
        address to_,
        uint256 amt_
    ) private whenNotPaused {
        require(_balances[from_] >= amt_, "Balance Low");

        if (enforceWalletTokenLimit) {
            _maxWalletTokenLimit =
                ((_TOTAL_SUPPLY * 15) / 10000) +
                (block.timestamp - _deployedTS) *
                _PER_SEC_LIMIT_CHANGE;

            if (_maxWalletTokenLimit > (_TOTAL_SUPPLY / 100)) {
                enforceWalletTokenLimit = false;
            }
        }

        if (_needsWhaleCheck(from_, to_)) {
            require(
                _balances[to_] + amt_ <= _maxWalletTokenLimit,
                "Whale Not Allowed"
            );
        }

        _checkIfAMMPair(from_);
        _checkIfAMMPair(to_);
        bool takeFee = true;

        if (_paysNoFee[from_] || _paysNoFee[to_]) {
            takeFee = false;
        }

        if (!_isAMMPair[from_] && !_isAMMPair[to_]) {
            takeFee = false;
        }

        if (takeFee) {
            (uint256 burnAmt, uint256 netAmt) = _calculateFees(amt_);

            _balances[from_] -= amt_;
            _balances[to_] += netAmt;
            emit Transfer(from_, to_, netAmt);

            if (burnAmt > 0) {
                _balances[_BURN_ADDRESS] += burnAmt;
                emit Transfer(from_, _BURN_ADDRESS, burnAmt);
            }
        } else {
            _balances[from_] -= amt_;
            _balances[to_] += amt_;
            emit Transfer(from_, to_, amt_);
        }
    }

    function _unstake(
        address lpPair_,
        uint256 unstakeAmt_,
        uint256 stakeIndex_
    ) private {
        bool transferred;
        uint256 index = _pairIndex[lpPair_];
        require(index != 0, "Invalid LP pair");

        Stake memory currStake = _withdrawStake(stakeIndex_, unstakeAmt_); // from before unstake started
        uint256 eligibleBasis = _BIPS;

        uint256 stakeRewards = (currStake.stakeAmt * _rewardsPerToken) /
            _REWARDX -
            currStake.rewardDebt;

        IERC20 lpPair = IERC20(lpPair_);
        if (_paysNoFee[msg.sender]) {
            lpPair.safeTransfer(msg.sender, unstakeAmt_);
            transferred = true;

            if (stakeRewards != 0) {
                _balances[address(this)] -= stakeRewards;
                _balances[msg.sender] += stakeRewards;
                emit Transfer(address(this), msg.sender, stakeRewards);
            }
        } else {
            uint256 usAmtFee = (unstakeAmt_ * _STAKE_FEE_BIPS) / _BIPS;
            uint256 withdrawAmtLessFees = unstakeAmt_ - usAmtFee - usAmtFee;
            uint256 usRwdFee = (stakeRewards * _STAKE_FEE_BIPS) / _BIPS;
            uint256 withdrawRwdLessFees = stakeRewards - usRwdFee - usRwdFee;
            eligibleBasis -= _penaltyFor(currStake.since, block.timestamp);

            uint256 amtToSendLessBurn = (withdrawAmtLessFees * eligibleBasis) /
                _BIPS;

            lpPair.safeTransfer(msg.sender, amtToSendLessBurn);
            lpPair.safeTransfer(_feeAddr1, usAmtFee);
            lpPair.safeTransfer(_feeAddr2, usAmtFee);
            transferred = true;

            uint256 lpPenalty = withdrawAmtLessFees - amtToSendLessBurn;
            if (lpPenalty != 0) {
                lpPair.safeTransfer(_feeAddr1, lpPenalty); // TODO change before launch
            }

            uint256 rwdToSendLessBurn = (withdrawRwdLessFees * eligibleBasis) /
                _BIPS;

            if (rwdToSendLessBurn != 0) {
                _balances[address(this)] -= stakeRewards; // includes fees and burn
                _balances[msg.sender] += rwdToSendLessBurn;
                _balances[_feeAddr1] += usRwdFee;
                _balances[_feeAddr2] += usRwdFee;
                emit Transfer(address(this), msg.sender, rwdToSendLessBurn);
                emit Transfer(address(this), _feeAddr1, usRwdFee);
                emit Transfer(address(this), _feeAddr2, usRwdFee);
            }

            uint256 memePenalty = withdrawRwdLessFees - rwdToSendLessBurn;
            if (memePenalty != 0) {
                _balances[_BURN_ADDRESS] += memePenalty;
                emit Transfer(address(this), _BURN_ADDRESS, memePenalty);
            }
        }

        totalStakedSupply -= unstakeAmt_;

        emit Unstaked(
            msg.sender,
            unstakeAmt_,
            currStake.rewardDebt,
            currStake.since,
            block.timestamp
        );
        require(transferred, "Unstake failed");
    }

    function _withdrawStake(
        uint256 stakeIndex_,
        uint256 unstakeAmt_
    ) private returns (Stake memory currStake) {
        uint256 stakerIndex = _stakeIndexMap[msg.sender];
        currStake = _getCurrStake(stakerIndex, stakeIndex_);

        require(currStake.stakeAmt >= unstakeAmt_, "Unstaking too much");

        if (currStake.stakeAmt == unstakeAmt_) {
            if (stakeIndex_ < stakeHolders[stakerIndex].userStakes.length - 1) {
                stakeHolders[stakerIndex].userStakes[
                    stakeIndex_
                ] = stakeHolders[stakerIndex].userStakes[
                    stakeHolders[stakerIndex].userStakes.length - 1
                ];
            }
            stakeHolders[stakerIndex].userStakes.pop();

            if (stakeHolders[stakerIndex].userStakes.length == 0) {
                if (stakerIndex < stakeHolders.length - 1) {
                    stakeHolders[stakerIndex] = stakeHolders[
                        stakeHolders.length - 1
                    ];
                    stakeHolders.pop();

                    _stakeIndexMap[msg.sender] = 0;
                    _stakeIndexMap[
                        stakeHolders[stakerIndex].user
                    ] = stakerIndex;
                } else {
                    stakeHolders.pop();
                    _stakeIndexMap[msg.sender] = 0;
                }
            }
        } else {
            Stake storage updatedStake = stakeHolders[stakerIndex].userStakes[
                stakeIndex_
            ];

            uint256 newStakeAmt = currStake.stakeAmt - unstakeAmt_;
            updatedStake.stakeAmt = newStakeAmt;
            updatedStake.rewardDebt =
                (_rewardsPerToken * newStakeAmt) /
                _REWARDX;
        }

        return (currStake);
    }

    function addLPPair(address lpPair_) external onlyManager {
        require(_pairIndex[lpPair_] == 0, "Already registered!");
        lpPairs.push(lpPair_);
        _pairIndex[lpPair_] = lpPairs.length - 1;
        _excludedFromAntiWhale[lpPair_] = true;
    }

    function allowance(
        address from_,
        address spender_
    ) external view override returns (uint256) {
        return _allowances[from_][spender_];
    }

    function approve(
        address spender_,
        uint256 amt_
    ) external override returns (bool) {
        address from = msg.sender;
        _approve(from, spender_, amt_);
        return true;
    }

    function balanceOf(
        address wallet_
    ) external view override returns (uint256) {
        return _balances[wallet_];
    }

    function burn(uint256 amt_) external {
        _balances[msg.sender] -= amt_;
        _balances[_BURN_ADDRESS] += amt_;
        emit Transfer(msg.sender, _BURN_ADDRESS, amt_);
    }

    function decimals() external pure override returns (uint8) {
        return 18;
    }

    function decreaseAllowance(
        address spender_,
        uint256 subtractedValue_
    ) external returns (bool) {
        address from = msg.sender;
        uint256 currentAllowance = _allowances[from][spender_];
        require(currentAllowance >= subtractedValue_, "Decreases below 0");
        unchecked {
            _approve(from, spender_, currentAllowance - subtractedValue_);
        }

        return true;
    }

    function excludeFromAntiWhale(
        address wallet_,
        bool exclude_
    ) external onlyManager {
        _excludedFromAntiWhale[wallet_] = exclude_;
        emit AntiWhaleExclusionChanged(wallet_, exclude_);
    }

    function excludeFromFees(
        address wallet_,
        bool payNoFee_
    ) external onlyManager {
        _paysNoFee[wallet_] = payNoFee_;
        emit PaysNoFeesChanged(wallet_, payNoFee_);
    }

    function getTotalStakeHolders() external view returns (uint256) {
        return stakeHolders.length - 1;
    }

    function getTotalStakes() external view returns (uint256 totalStakeCount) {
        for (
            uint256 stakerIndex;
            stakerIndex < stakeHolders.length;
            ++stakerIndex
        ) {
            totalStakeCount += stakeHolders[stakerIndex].userStakes.length;
        }

        return totalStakeCount;
    }

    function increaseAllowance(
        address spender_,
        uint256 addedValue_
    ) external returns (bool) {
        address from = msg.sender;
        _approve(from, spender_, _allowances[from][spender_] + addedValue_);
        return true;
    }

    function maxWalletTokenLimit() external view returns (uint256 limit) {
        limit =
            ((_TOTAL_SUPPLY * 15) / 10000) +
            (block.timestamp - _deployedTS) *
            _PER_SEC_LIMIT_CHANGE;

        if (limit > (_TOTAL_SUPPLY / 100)) {
            limit = _TOTAL_SUPPLY;
        }
    }

    function name() external view override returns (string memory) {
        return _name;
    }

    function pauseContract() external onlyManager {
        _pause();
    }

    function penaltyIfUnstakedNow(
        address wallet_,
        uint256 stakeIndex_
    ) external view returns (uint256 penaltyBasis) {
        uint256 stakerIndex = _stakeIndexMap[wallet_];
        Stake memory currStake = _getCurrStake(stakerIndex, stakeIndex_);

        return _penaltyFor(currStake.since, block.timestamp);
    }

    function reclaimETH() external payable {
        uint256 amt = address(this).balance;
        require(amt > 0, "Zero Balance");

        (bool sent, ) = manager().call{value: amt}("");
        require(sent, "Send Failed");
    }

    function reclaimToken(
        IERC20 token_,
        uint256 amt_
    ) external payable onlyManager {
        uint256 balance = (token_.balanceOf(address(this)));
        require(amt_ <= balance, "Balance low");
        token_.transfer(manager(), balance);
    }

    function removeLPPair(address lpPair_) external onlyManager {
        require(_pairIndex[lpPair_] != 0, "Not registered!");
        require(_pairIndex[lpPair_] < lpPairs.length, "Invalid pair!");
        uint256 index = _pairIndex[lpPair_];
        if (index < lpPairs.length - 1) {
            lpPairs[index] = lpPairs[lpPairs.length - 1];
            _pairIndex[lpPairs[index]] = index;
        }
        lpPairs.pop();
        _pairIndex[lpPair_] = 0;
    }

    function rewardsOf(
        address stakeholder_,
        uint256 stakeIndex_
    ) external view returns (uint256 rewards, uint256 eligibleBasis) {
        uint256 inflation;
        uint256 tmpRewardsPerToken;
        if (_lastDistTS != 0) {
            (inflation, tmpRewardsPerToken) = _calcInflation(block.timestamp);
        }

        uint256 stakerIndex = _stakeIndexMap[stakeholder_];

        Stake memory currStake = _getCurrStake(stakerIndex, stakeIndex_);

        eligibleBasis = _BIPS - _penaltyFor(currStake.since, block.timestamp);
        if (tmpRewardsPerToken > 0) {
            rewards = ((currStake.stakeAmt * tmpRewardsPerToken) /
                _REWARDX -
                currStake.rewardDebt);
        }
        return (rewards, eligibleBasis);
    }

    function setFeeAddresses(
        address feeAddr1_,
        address feeAddr2_
    ) external onlyOwner {
        if (feeAddr1_ != address(0)) {
            _feeAddr1 = feeAddr1_;
            _paysNoFee[feeAddr1_] = true;
        }
        if (feeAddr2_ != address(0)) {
            _feeAddr2 = feeAddr2_;
            _paysNoFee[feeAddr2_] = true;
        }
    }

    function stake(address lpPair_, uint256 stakeAmt_) external whenNotPaused {
        require(stakeAmt_ != 0, "Cannot stake Zero");
        uint256 index = _pairIndex[lpPair_];
        require(index != 0, "Invalid LP pair");

        _stake(lpPair_, stakeAmt_);
    }

    function stakesOf(
        address stakeholder_
    ) external view returns (Stake[] memory userStakes) {
        uint256 stakerIndex = _stakeIndexMap[stakeholder_];
        if (stakerIndex > 0) {
            return stakeHolders[stakerIndex].userStakes;
        }

        return userStakes;
    }

    function symbol() external view override returns (string memory) {
        return _symbol;
    }

    function totalSupply() external pure override returns (uint256) {
        return _TOTAL_SUPPLY;
    }

    function transfer(
        address to_,
        uint256 amt_
    ) external override returns (bool) {
        address from = msg.sender;
        _transfer(from, to_, amt_);
        return true;
    }

    function transferFrom(
        address from_,
        address to_,
        uint256 amt_
    ) external override returns (bool) {
        address spender = msg.sender;
        uint256 currentAllowance = _allowances[from_][spender];
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amt_, "Insufficient allowance");
            unchecked {
                _approve(from_, spender, currentAllowance - amt_);
            }
        }
        _transfer(from_, to_, amt_);
        return true;
    }

    function unPauseContract() external onlyManager {
        _unpause();
    }

    function unstake(
        address lpPair_,
        uint256 unstakeAmt_,
        uint256 stakeIndex_
    ) external whenNotPaused {
        _creditInflation();

        _unstake(lpPair_, unstakeAmt_, stakeIndex_);
    }
}
        

contracts/uniswap/v2-core/interfaces/IUniswapV2Factory.sol

/*
 * SPDX-License-Identifier: MIT
 */

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;
}
          

contracts/uniswap/v2-periphery/interfaces/IUniswapV2Router01.sol

/*
 * SPDX-License-Identifier: MIT
 */

pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    // function WETH() external pure returns (address);
    function WPLS() 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);
}
          

contracts/imports/Manageable.sol

/*
 * SPDX-License-Identifier: MIT
 */
pragma solidity ^0.8.20;

abstract contract Manageable {
    address private _manager;

    event ManagementTransferred(
        address indexed previousManager,
        address indexed newManager
    );

    constructor() {
        _manager = msg.sender;
        emit ManagementTransferred(address(0), msg.sender);
    }

    function _checkManager() private view {
        require(_manager == msg.sender, "M:Caller not manager");
    }

    function manager() public view returns (address) {
        return _manager;
    }

    modifier onlyManager() {
        _checkManager();
        _;
    }

    function transferManagement(address newManager_) external onlyManager {
        emit ManagementTransferred(_manager, newManager_);
        _manager = newManager_;
    }
}
          

contracts/lib/DSMath.sol

/*
 * SPDX-License-Identifier: MIT
 */

pragma solidity ^0.8.20;

contract DSMath {
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, "ds-math-add-overflow");
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
    }

    uint96 constant RAY = 10 ** 27;

    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), RAY >> 1) / RAY;
    }

    function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}
          

contracts/openzeppelin/access/Ownable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
          

contracts/openzeppelin/security/Pausable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}
          

contracts/openzeppelin/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
          

contracts/openzeppelin/token/ERC20/extensions/IERC20Metadata.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
          

contracts/openzeppelin/token/ERC20/extensions/IERC20Permit.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}
          

contracts/openzeppelin/token/ERC20/utils/SafeERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
     * 0 before setting it to a non-zero value.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}
          

contracts/openzeppelin/utils/Address.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
          

contracts/openzeppelin/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
          

contracts/uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol

/*
 * SPDX-License-Identifier: MIT
 */

pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

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;
}
          

Compiler Settings

{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":1000000,"enabled":true},"libraries":{}}
              

Contract ABI

[{"type":"constructor","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"address","name":"routerAddress_","internalType":"address"},{"type":"address","name":"feeAddr1_","internalType":"address"},{"type":"address","name":"feeAddr2_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addLPPair","inputs":[{"type":"address","name":"lpPair_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"spender_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"wallet_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"burn","inputs":[{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"subtractedValue_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"enforceWalletTokenLimit","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"excludeFromAntiWhale","inputs":[{"type":"address","name":"wallet_","internalType":"address"},{"type":"bool","name":"exclude_","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"excludeFromFees","inputs":[{"type":"address","name":"wallet_","internalType":"address"},{"type":"bool","name":"payNoFee_","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalStakeHolders","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"totalStakeCount","internalType":"uint256"}],"name":"getTotalStakes","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender_","internalType":"address"},{"type":"uint256","name":"addedValue_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lpPairs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"manager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"limit","internalType":"uint256"}],"name":"maxWalletTokenLimit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pauseContract","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"penaltyBasis","internalType":"uint256"}],"name":"penaltyIfUnstakedNow","inputs":[{"type":"address","name":"wallet_","internalType":"address"},{"type":"uint256","name":"stakeIndex_","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"reclaimETH","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"reclaimToken","inputs":[{"type":"address","name":"token_","internalType":"contract IERC20"},{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeLPPair","inputs":[{"type":"address","name":"lpPair_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardsAvailableToEarn","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"rewards","internalType":"uint256"},{"type":"uint256","name":"eligibleBasis","internalType":"uint256"}],"name":"rewardsOf","inputs":[{"type":"address","name":"stakeholder_","internalType":"address"},{"type":"uint256","name":"stakeIndex_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeAddresses","inputs":[{"type":"address","name":"feeAddr1_","internalType":"address"},{"type":"address","name":"feeAddr2_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stake","inputs":[{"type":"address","name":"lpPair_","internalType":"address"},{"type":"uint256","name":"stakeAmt_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"user","internalType":"address"}],"name":"stakeHolders","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"userStakes","internalType":"struct DWOJAK.Stake[]","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"}]}],"name":"stakesOf","inputs":[{"type":"address","name":"stakeholder_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStakedSupply","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from_","internalType":"address"},{"type":"address","name":"to_","internalType":"address"},{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferManagement","inputs":[{"type":"address","name":"newManager_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unPauseContract","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unstake","inputs":[{"type":"address","name":"lpPair_","internalType":"address"},{"type":"uint256","name":"unstakeAmt_","internalType":"uint256"},{"type":"uint256","name":"stakeIndex_","internalType":"uint256"}]},{"type":"event","name":"AntiWhaleExclusionChanged","inputs":[{"type":"address","name":"wallet","indexed":false},{"type":"bool","name":"excluded","indexed":false}],"anonymous":false},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","indexed":true},{"type":"address","name":"spender","indexed":true},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"ManagementTransferred","inputs":[{"type":"address","name":"previousManager","indexed":true},{"type":"address","name":"newManager","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"Paused","inputs":[{"type":"address","name":"account","indexed":false}],"anonymous":false},{"type":"event","name":"PaysNoFeesChanged","inputs":[{"type":"address","name":"wallet","indexed":false},{"type":"bool","name":"paysNoFee","indexed":false}],"anonymous":false},{"type":"event","name":"Staked","inputs":[{"type":"address","name":"user","indexed":true},{"type":"uint256","name":"stakeIndex","indexed":false},{"type":"uint256","name":"stakeAmt","indexed":false},{"type":"uint256","name":"rewardDebt","indexed":false},{"type":"uint256","name":"since","indexed":false}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","indexed":false}],"anonymous":false},{"type":"event","name":"Unstaked","inputs":[{"type":"address","name":"user","indexed":true},{"type":"uint256","name":"stakeAmt","indexed":false},{"type":"uint256","name":"rewardDebt","indexed":false},{"type":"uint256","name":"since","indexed":false},{"type":"uint256","name":"till","indexed":false}],"anonymous":false},{"type":"receive"},{"type":"fallback"}]
              

Contract Creation Code

0x60806040526005805460ff60a01b1916600160a01b17905534801562000023575f80fd5b5060405162004ad038038062004ad0833981016040819052620000469162000535565b5f80546001600160a01b0319163390811782556040519091907f80f15e9dbc60884fdb59fb8ed4fc48a9a689e028f055e893ed45ca5be67c5c85908290a36200008f336200040a565b6001805460ff60a01b19169055600d620000aa86826200065d565b50600e620000b985826200065d565b50335f908152600960208181526040808420805460ff199081166001908117909255600680855283872080548316841790556003805484019055600480546001600160a01b038b81166001600160a01b0319928316811790935591895287875285892080548516861790558287528589208054851686179055600580548b84169216821790558852868652848820805484168517905581865284882080548416851790558a1687529484528286208054821683179055939092528320805490921617905562000196600a6b033b2e3c9fd0803ce800000062000739565b9050600a620001b36b033b2e3c9fd0803ce8000000600962000759565b620001bf919062000739565b601355335f818152600b60209081526040808320859055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a342600f8190556010556002805460010181555f9081526040805163c45a015560e01b815290518692916001600160a01b0384169163c45a0155916004808201926020929091908290030181865afa15801562000263573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000289919062000779565b90505f816001600160a01b031663c9c6539630856001600160a01b031663ef8ef56f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620002ff919062000779565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526044016020604051808303815f875af11580156200034a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000370919062000779565b60028054600180820183555f8390527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180546001600160a01b0319166001600160a01b0385161790559054919250620003cc916200079c565b6001600160a01b039091165f908152600860209081526040808320939093556006905220805460ff1916600117905550620007b29650505050505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126200047f575f80fd5b81516001600160401b03808211156200049c576200049c6200045b565b604051601f8301601f19908116603f01168101908282118183101715620004c757620004c76200045b565b81604052838152602092508683858801011115620004e3575f80fd5b5f91505b83821015620005065785820183015181830184015290820190620004e7565b5f93810190920192909252949350505050565b80516001600160a01b038116811462000530575f80fd5b919050565b5f805f805f60a086880312156200054a575f80fd5b85516001600160401b038082111562000561575f80fd5b6200056f89838a016200046f565b9650602088015191508082111562000585575f80fd5b5062000594888289016200046f565b945050620005a56040870162000519565b9250620005b56060870162000519565b9150620005c56080870162000519565b90509295509295909350565b600181811c90821680620005e657607f821691505b6020821081036200060557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000658575f81815260208120601f850160051c81016020861015620006335750805b601f850160051c820191505b8181101562000654578281556001016200063f565b5050505b505050565b81516001600160401b038111156200067957620006796200045b565b62000691816200068a8454620005d1565b846200060b565b602080601f831160018114620006c7575f8415620006af5750858301515b5f19600386901b1c1916600185901b17855562000654565b5f85815260208120601f198616915b82811015620006f757888601518255948401946001909101908401620006d6565b50858210156200071557878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b5f826200075457634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141762000773576200077362000725565b92915050565b5f602082840312156200078a575f80fd5b620007958262000519565b9392505050565b8181038181111562000773576200077362000725565b61431080620007c05f395ff3fe60806040526004361061028e575f3560e01c806370a0823111610155578063adc9772e116100be578063c1acbaf211610078578063e4edf85211610060578063e4edf8521461077c578063f2fde38b1461079b578063ffbc91d9146107ba57005b8063c1acbaf21461070c578063dd62ed3e1461072b57005b8063bac15203116100a6578063bac15203146106c4578063bcdc3cfc146106d8578063c0246668146106ed57005b8063adc9772e14610686578063b34117ba146106a557005b8063a0db69ca1161010f578063a457c2d7116100f7578063a457c2d714610629578063a9059cbb14610648578063acad41a41461066757005b8063a0db69ca146105f5578063a2bc66be1461060a57005b80638da5cb5b1161013d5780638da5cb5b1461058657806395d89b41146105b05780639a2bfa65146105c457005b806370a0823114610531578063715018a61461057257005b806333b69c4c116101f7578063481c6a75116101b15780635c975abb116101995780635c975abb146104db57806361ce35291461050a57806368c336271461051d57005b8063481c6a751461049357806352e7c444146104bc57005b806339509351116101df578063395093511461044157806342966c6814610460578063439766ce1461047f57005b806333b69c4c146103e157806335941b1c1461040d57005b806318160ddd1161024857806323b872dd1161023057806323b872dd1461039357806325baa421146103b2578063313ce567146103c657005b806318160ddd14610357578063187fcb161461037f57005b8063095ea7b311610276578063095ea7b3146103015780630f144a481461033057806311c841201461033857005b80630526c60b1461029757806306fdde03146102e057005b3661029557005b005b3480156102a2575f80fd5b506102b66102b1366004613eb2565b6107d9565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156102eb575f80fd5b506102f461080e565b6040516102d79190613eeb565b34801561030c575f80fd5b5061032061031b366004613f5c565b61089e565b60405190151581526020016102d7565b6102956108b7565b348015610343575f80fd5b50610295610352366004613f86565b6109ef565b348015610362575f80fd5b506b033b2e3c9fd0803ce80000005b6040519081526020016102d7565b34801561038a575f80fd5b50610371610b26565b34801561039e575f80fd5b506103206103ad366004613fbd565b610b3c565b3480156103bd575f80fd5b50610371610c21565b3480156103d1575f80fd5b50604051601281526020016102d7565b3480156103ec575f80fd5b506104006103fb366004613ffb565b610ca4565b6040516102d79190614016565b348015610418575f80fd5b5061042c610427366004613f5c565b610d72565b604080519283526020830191909152016102d7565b34801561044c575f80fd5b5061032061045b366004613f5c565b610e1d565b34801561046b575f80fd5b5061029561047a366004613eb2565b610e68565b34801561048a575f80fd5b50610295610f09565b34801561049e575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156104c7575f80fd5b506102956104d6366004613ffb565b610f1b565b3480156104e6575f80fd5b5060015474010000000000000000000000000000000000000000900460ff16610320565b610295610518366004613f5c565b6111f4565b348015610528575f80fd5b506103716113c9565b34801561053c575f80fd5b5061037161054b366004613ffb565b73ffffffffffffffffffffffffffffffffffffffff165f908152600b602052604090205490565b34801561057d575f80fd5b5061029561141c565b348015610591575f80fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156105bb575f80fd5b506102f461142d565b3480156105cf575f80fd5b506005546103209074010000000000000000000000000000000000000000900460ff1681565b348015610600575f80fd5b5061037160135481565b348015610615575f80fd5b5061029561062436600461406e565b61143c565b348015610634575f80fd5b50610320610643366004613f5c565b61145c565b348015610653575f80fd5b50610320610662366004613f5c565b611511565b348015610672575f80fd5b506102b6610681366004613eb2565b61151e565b348015610691575f80fd5b506102956106a0366004613f5c565b611558565b3480156106b0575f80fd5b506102956106bf3660046140ad565b611662565b3480156106cf575f80fd5b506102956116f8565b3480156106e3575f80fd5b5061037160145481565b3480156106f8575f80fd5b506102956107073660046140ad565b611708565b348015610717575f80fd5b50610371610726366004613f5c565b611796565b348015610736575f80fd5b50610371610745366004613f86565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600a6020908152604080832093909416825291909152205490565b348015610787575f80fd5b50610295610796366004613ffb565b6117df565b3480156107a6575f80fd5b506102956107b5366004613ffb565b611872565b3480156107c5575f80fd5b506102956107d4366004613ffb565b611929565b600281815481106107e8575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6060600d805461081d906140d9565b80601f0160208091040260200160405190810160405280929190818152602001828054610849906140d9565b80156108945780601f1061086b57610100808354040283529160200191610894565b820191905f5260205f20905b81548152906001019060200180831161087757829003601f168201915b5050505050905090565b5f336108ab818585611a96565b60019150505b92915050565b4780610924576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a65726f2042616c616e6365000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f811461097b576040519150601f19603f3d011682016040523d82523d5f602084013e610980565b606091505b50509050806109eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f53656e64204661696c6564000000000000000000000000000000000000000000604482015260640161091b565b5050565b6109f7611b03565b73ffffffffffffffffffffffffffffffffffffffff821615610a8d57600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b73ffffffffffffffffffffffffffffffffffffffff8116156109eb57600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691821790555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b6003545f90610b3790600190614151565b905090565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600a602090815260408083203380855292528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c0a5783811015610bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e73756666696369656e7420616c6c6f77616e636500000000000000000000604482015260640161091b565b610c0a8683868403611a96565b610c15868686611b84565b50600195945050505050565b5f683635c9adc5dea0000060105442610c3a9190614151565b610c449190614164565b612710610c5e6b033b2e3c9fd0803ce8000000600f614164565b610c6891906141a8565b610c7291906141bb565b9050610c8b60646b033b2e3c9fd0803ce80000006141a8565b811115610ca157506b033b2e3c9fd0803ce80000005b90565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600c60205260409020546060908015610d6c5760038181548110610ce557610ce56141ce565b905f5260205f209060020201600101805480602002602001604051908101604052809291908181526020015f905b82821015610d60578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505081526020019060010190610d13565b50505050915050919050565b50919050565b5f805f80600f545f14610d8e57610d88426120ca565b90925090505b73ffffffffffffffffffffffffffffffffffffffff86165f908152600c602052604081205490610dbe82886121f0565b9050610dce81604001514261230e565b610dda90612710614151565b94508215610e12576020810151815164e8d4a5100090610dfb908690614164565b610e0591906141a8565b610e0f9190614151565b95505b505050509250929050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906108ab9082908690610e639087906141bb565b611a96565b335f908152600b602052604081208054839290610e86908490614151565b90915550506103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290610ec89084906141bb565b90915550506040518181526103699033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350565b610f11612368565b610f196123e8565b565b610f23612368565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600860205260408120549003610fb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742072656769737465726564210000000000000000000000000000000000604482015260640161091b565b60025473ffffffffffffffffffffffffffffffffffffffff82165f908152600860205260409020541061103f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420706169722100000000000000000000000000000000000000604482015260640161091b565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526008602052604090205460025461107390600190614151565b811015611160576002805461108a90600190614151565b8154811061109a5761109a6141ce565b5f918252602090912001546002805473ffffffffffffffffffffffffffffffffffffffff90921691839081106110d2576110d26141ce565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060085f6002848154811061112e5761112e6141ce565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020555b6002805480611171576111716141fb565b5f828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff9390931681526008909252506040812055565b6111fc612368565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015611266573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061128a9190614228565b9050808211156112f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365206c6f77000000000000000000000000000000000000000000604482015260640161091b565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6113305f5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303815f875af115801561139f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113c3919061423f565b50505050565b5f805b60035481101561141857600381815481106113e9576113e96141ce565b5f91825260209091206001600290920201015461140690836141bb565b91506114118161425a565b90506113cc565b5090565b611424611b03565b610f195f612481565b6060600e805461081d906140d9565b6114446124f7565b61144c61257c565b61145783838361261c565b505050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190838110156114f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4465637265617365732062656c6f772030000000000000000000000000000000604482015260640161091b565b6115068286868403611a96565b506001949350505050565b5f336108ab818585611b84565b6003818154811061152d575f80fd5b5f91825260209091206002909102015473ffffffffffffffffffffffffffffffffffffffff16905081565b6115606124f7565b805f036115c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f43616e6e6f74207374616b65205a65726f000000000000000000000000000000604482015260640161091b565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604081205490819003611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091b565b6114578383612c25565b61166a612368565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526006602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527f6967fd9beca531ca64fc6f897b579e9ea3e2e937cf55341df2151665ba43d5ef91015b60405180910390a15050565b611700612368565b610f19612e56565b611710612368565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526009602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527feb0184c59a430a1717ee5868decd2a492123fadbdb07af787cb52a263a0650b891016116ec565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600c6020526040812054816117c682856121f0565b90506117d681604001514261230e565b95945050505050565b6117e7612368565b5f805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f80f15e9dbc60884fdb59fb8ed4fc48a9a689e028f055e893ed45ca5be67c5c8591a35f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61187a611b03565b73ffffffffffffffffffffffffffffffffffffffff811661191d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161091b565b61192681612481565b50565b611931612368565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260086020526040902054156119bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920726567697374657265642100000000000000000000000000604482015260640161091b565b60028054600180820183555f8390527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790559054611a3a9190614151565b73ffffffffffffffffffffffffffffffffffffffff9091165f90815260086020908152604080832093909355600690522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8381165f818152600a602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161091b565b611b8c6124f7565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054811115611c1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365204c6f77000000000000000000000000000000000000000000604482015260640161091b565b60055474010000000000000000000000000000000000000000900460ff1615611cd957683635c9adc5dea0000060105442611c559190614151565b611c5f9190614164565b612710611c796b033b2e3c9fd0803ce8000000600f614164565b611c8391906141a8565b611c8d91906141bb565b601255611ca760646b033b2e3c9fd0803ce80000006141a8565b6012541115611cd957600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555b611ce38383612ead565b15611d835760125473ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054611d1b9083906141bb565b1115611d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5768616c65204e6f7420416c6c6f776564000000000000000000000000000000604482015260640161091b565b611d8c83612f53565b611d9582612f53565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460019060ff1680611def575073ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460ff165b15611df757505f5b73ffffffffffffffffffffffffffffffffffffffff84165f9081526007602052604090205460ff16158015611e51575073ffffffffffffffffffffffffffffffffffffffff83165f9081526007602052604090205460ff16155b15611e5957505f5b8015611fe9575f80611e6a8461305f565b73ffffffffffffffffffffffffffffffffffffffff88165f908152600b6020526040812080549395509193508692611ea3908490614151565b909155505073ffffffffffffffffffffffffffffffffffffffff85165f908152600b602052604081208054839290611edc9084906141bb565b925050819055508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611f4291815260200190565b60405180910390a38115611fe2576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054849290611f8d9084906141bb565b90915550506040518281526103699073ffffffffffffffffffffffffffffffffffffffff8816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b50506113c3565b73ffffffffffffffffffffffffffffffffffffffff84165f908152600b60205260408120805484929061201d908490614151565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040812080548492906120569084906141bb565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516120bc91815260200190565b60405180910390a350505050565b5f80600f545f03612137576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e666c6174696f6e206e6f7420737461727465642100000000000000000000604482015260640161091b565b5f600f54846121469190614151565b905080156121e4575f6121656b033b2e3c814887e4de2400008361308c565b90506b033b2e3c9fd0803ce80000006bffffffffffffffffffffffff16816013546121909190614164565b61219a91906141a8565b6013546121a79190614151565b93506014545f146121de576014546121c464e8d4a5100086614164565b6121ce91906141a8565b6011546121db91906141bb565b92505b506121ea565b60115491505b50915091565b61221160405180606001604052805f81526020015f81526020015f81525090565b60038381548110612224576122246141ce565b905f5260205f20906002020160010180549050821061229f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b6520696e64657820696e636f72726563742100000000000000000000604482015260640161091b565b600383815481106122b2576122b26141ce565b905f5260205f20906002020160010182815481106122d2576122d26141ce565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050905092915050565b5f8161231e846301dfe2006141bb565b11156108b1575f6224ea006123338585614151565b61233d91906141a8565b9050600d8110156123615761235381600d614151565b61235e906064614164565b91505b5092915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d3a43616c6c6572206e6f74206d616e61676572000000000000000000000000604482015260640161091b565b6123f06124f7565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586124573390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60015474010000000000000000000000000000000000000000900460ff1615610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161091b565b600f544290811115611926575f80612593836120ca565b91509150815f146114575782600f819055508160135f8282546125b69190614151565b9091555050305f908152600b6020526040812080548492906125d99084906141bb565b909155505060405182815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36011555050565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600860205260408120548082036126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091b565b5f6126b58486613103565b90505f61271090505f826020015164e8d4a51000601154855f01516126da9190614164565b6126e491906141a8565b6126ee9190614151565b335f90815260096020526040902054909150889060ff16156127b85761272b73ffffffffffffffffffffffffffffffffffffffff8216338a613614565b6001955081156127b357305f908152600b602052604081208054849290612753908490614151565b9091555050335f908152600b6020526040812080548492906127769084906141bb565b9091555050604051828152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b612b4d565b5f6127106127c760648b614164565b6127d191906141a8565b90505f816127df818c614151565b6127e99190614151565b90505f6127106127fa606487614164565b61280491906141a8565b90505f816128128188614151565b61281c9190614151565b905061282c88604001514261230e565b6128369088614151565b96505f6127106128468986614164565b61285091906141a8565b905061287373ffffffffffffffffffffffffffffffffffffffff87163383613614565b60045461289a9073ffffffffffffffffffffffffffffffffffffffff888116911687613614565b6005546128c19073ffffffffffffffffffffffffffffffffffffffff888116911687613614565b60019a505f6128d08286614151565b905080156128ff576004546128ff9073ffffffffffffffffffffffffffffffffffffffff898116911683613614565b5f61271061290d8b86614164565b61291791906141a8565b90508015612ab557305f908152600b6020526040812080548b929061293d908490614151565b9091555050335f908152600b6020526040812080548392906129609084906141bb565b909155505060045473ffffffffffffffffffffffffffffffffffffffff165f908152600b60205260408120805487929061299b9084906141bb565b909155505060055473ffffffffffffffffffffffffffffffffffffffff165f908152600b6020526040812080548792906129d69084906141bb565b9091555050604051818152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360045460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360055460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b5f612ac08286614151565b90508015612b44576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290612b059084906141bb565b90915550506040518181526103699030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b50505050505050505b8760145f828254612b5e9190614151565b909155505060208481015160408087015181518c81529384019290925282015242606082015233907fdcfd2b4017d03f7e541021db793b2f9b31e4acdee005f789e52853c390e3e9629060800160405180910390a285612c1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f556e7374616b65206661696c6564000000000000000000000000000000000000604482015260640161091b565b505050505050505050565b612c2d61257c565b335f90815260096020526040812054819060ff1615612c4d575081612c7f565b612710612c5b606485614164565b612c6591906141a8565b915081612c728185614151565b612c7c9190614151565b90505b83612ca273ffffffffffffffffffffffffffffffffffffffff82163330856136e8565b8215612cfa57600454612cd19073ffffffffffffffffffffffffffffffffffffffff83811691339116866136e8565b600554612cfa9073ffffffffffffffffffffffffffffffffffffffff83811691339116866136e8565b335f908152600c602052604081205490819003612d1d57612d1a33613746565b90505b5f64e8d4a5100084601154612d329190614164565b612d3c91906141a8565b905060038281548110612d5157612d516141ce565b5f91825260208083206040805160608101825289815280840187815242928201928352600160029687029094018401805480860182559088529487209151600390950290910193845551918301919091555191015560148054869290612db89084906141bb565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167f9cfd25589d1eb8ad71e342a86a8524e83522e3936c0803048c08f6d9ad974f40600160038581548110612e0c57612e0c6141ce565b905f5260205f20906002020160010180549050612e299190614151565b6040805191825260208201889052810184905242606082015260800160405180910390a250505050505050565b612e5e6137df565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612457565b6005545f9074010000000000000000000000000000000000000000900460ff168015612ef4575060015473ffffffffffffffffffffffffffffffffffffffff848116911614155b8015612f1b575060015473ffffffffffffffffffffffffffffffffffffffff838116911614155b8015612f4c575073ffffffffffffffffffffffffffffffffffffffff82165f9081526006602052604090205460ff16155b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f03612f745750565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604090205460ff16611926575f612faa82613863565b905073ffffffffffffffffffffffffffffffffffffffff8116612fcb575050565b5f612fd58361388e565b905073ffffffffffffffffffffffffffffffffffffffff8116612ff757505050565b505073ffffffffffffffffffffffffffffffffffffffff165f908152600760209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092556006909352922080549091169091179055565b5f8061271061306f602885614164565b61307991906141a8565b91506130858284614151565b9050915091565b5f613098600283614291565b5f036130b0576b033b2e3c9fd0803ce80000006130b2565b825b90506130bf6002836141a8565b91505b81156108b1576130d283846138b9565b92506130df600283614291565b156130f1576130ee81846138b9565b90505b6130fc6002836141a8565b91506130c2565b61312460405180606001604052805f81526020015f81526020015f81525090565b335f908152600c602052604090205461313d81856121f0565b915082825f015110156131ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e7374616b696e6720746f6f206d7563680000000000000000000000000000604482015260640161091b565b815183900361358d576001600382815481106131ca576131ca6141ce565b905f5260205f209060020201600101805490506131e79190614151565b8410156132b95760038181548110613201576132016141ce565b905f5260205f209060020201600101600160038381548110613225576132256141ce565b905f5260205f209060020201600101805490506132429190614151565b81548110613252576132526141ce565b905f5260205f20906003020160038281548110613271576132716141ce565b905f5260205f2090600202016001018581548110613291576132916141ce565b5f91825260209091208254600390920201908155600180830154908201556002918201549101555b600381815481106132cc576132cc6141ce565b905f5260205f2090600202016001018054806132ea576132ea6141fb565b5f8281526020812060037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093018381029091018281556001810183905560020191909155909155805482908110613344576133446141ce565b5f918252602082206001600290920201015490036135885760035461336b90600190614151565b8110156134fd576003805461338290600190614151565b81548110613392576133926141ce565b905f5260205f209060020201600382815481106133b1576133b16141ce565b5f9182526020909120825460029092020180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091178155600180830180546134189284019190613e15565b50905050600380548061342d5761342d6141fb565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155906134936001830182613e77565b50509055335f908152600c6020819052604082208290556003805484939190849081106134c2576134c26141ce565b5f918252602080832060029092029091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902055612361565b600380548061350e5761350e6141fb565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155906135746001830182613e77565b50509055335f908152600c60205260408120555b612361565b5f600382815481106135a1576135a16141ce565b905f5260205f20906002020160010185815481106135c1576135c16141ce565b5f91825260208220855160039092020192506135de908690614151565b80835560115490915064e8d4a51000906135f9908390614164565b61360391906141a8565b826001018190555050505092915050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114579084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526138f0565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526113c39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401613666565b6003805460019081018083555f928352829161376191614151565b90508260038281548110613777576137776141ce565b5f918252602080832060029290920290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055949091168152600c90935260409092208290555090565b60015474010000000000000000000000000000000000000000900460ff16610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161091b565b5f6108b1827f0dfe1681000000000000000000000000000000000000000000000000000000006139fd565b5f6108b1827fd21220a7000000000000000000000000000000000000000000000000000000006139fd565b5f6b033b2e3c9fd0803ce80000006138e66138d48585613b0c565b6b019d971e4fe8401e74000000613b95565b612f4c91906141a8565b5f613951826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613c0c9092919063ffffffff16565b905080515f1480613971575080806020019051810190613971919061423f565b611457576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161091b565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000851617905290515f918291829173ffffffffffffffffffffffffffffffffffffffff871691613a7f91906142a4565b5f60405180830381855afa9150503d805f8114613ab7576040519150601f19603f3d011682016040523d82523d5f602084013e613abc565b606091505b5091509150811580613acd57508051155b15613adc575f925050506108b1565b8051602003613b025780806020019051810190613af991906142bf565b925050506108b1565b505f949350505050565b5f811580613b2f57508282613b218183614164565b9250613b2d90836141a8565b145b6108b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015260640161091b565b5f82613ba183826141bb565b91508110156108b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015260640161091b565b6060613c1a84845f85613c22565b949350505050565b606082471015613cb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161091b565b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051613cdc91906142a4565b5f6040518083038185875af1925050503d805f8114613d16576040519150601f19603f3d011682016040523d82523d5f602084013e613d1b565b606091505b5091509150613d2c87838387613d37565b979650505050505050565b60608315613dcc5782515f03613dc55773ffffffffffffffffffffffffffffffffffffffff85163b613dc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161091b565b5081613c1a565b613c1a8383815115613de15781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091b9190613eeb565b828054828255905f5260205f20906003028101928215613e6b575f5260205f209160030282015b82811115613e6b5782548255600180840154908301556002808401549083015560039283019290910190613e3c565b50611418929150613e91565b5080545f8255600302905f5260205f209081019061192691905b5b80821115611418575f808255600182018190556002820155600301613e92565b5f60208284031215613ec2575f80fd5b5035919050565b5f5b83811015613ee3578181015183820152602001613ecb565b50505f910152565b602081525f8251806020840152613f09816040850160208701613ec9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff81168114611926575f80fd5b5f8060408385031215613f6d575f80fd5b8235613f7881613f3b565b946020939093013593505050565b5f8060408385031215613f97575f80fd5b8235613fa281613f3b565b91506020830135613fb281613f3b565b809150509250929050565b5f805f60608486031215613fcf575f80fd5b8335613fda81613f3b565b92506020840135613fea81613f3b565b929592945050506040919091013590565b5f6020828403121561400b575f80fd5b8135612f4c81613f3b565b602080825282518282018190525f919060409081850190868401855b828110156140615781518051855286810151878601528501518585015260609093019290850190600101614032565b5091979650505050505050565b5f805f60608486031215614080575f80fd5b833561408b81613f3b565b95602085013595506040909401359392505050565b8015158114611926575f80fd5b5f80604083850312156140be575f80fd5b82356140c981613f3b565b91506020830135613fb2816140a0565b600181811c908216806140ed57607f821691505b602082108103610d6c577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108b1576108b1614124565b80820281158282048414176108b1576108b1614124565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826141b6576141b661417b565b500490565b808201808211156108b1576108b1614124565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f60208284031215614238575f80fd5b5051919050565b5f6020828403121561424f575f80fd5b8151612f4c816140a0565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361428a5761428a614124565b5060010190565b5f8261429f5761429f61417b565b500690565b5f82516142b5818460208701613ec9565b9190910192915050565b5f602082840312156142cf575f80fd5b8151612f4c81613f3b56fea26469706673582212200fb43125b121149aa09c463008fe157f2de00f1603af49ffade3312c9973754b64736f6c6343000814003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9000000000000000000000000fb7103d7011dfa60c18c6961c5a38038d8048fe000000000000000000000000043f11890f3d8ee704595eba88f52ee7d983b6907000000000000000000000000000000000000000000000000000000000000001c446172746820576f6a616b3a2070756c73656c6f7269616e2e636f6d00000000000000000000000000000000000000000000000000000000000000000000000644574f4a414b0000000000000000000000000000000000000000000000000000

Deployed ByteCode

0x60806040526004361061028e575f3560e01c806370a0823111610155578063adc9772e116100be578063c1acbaf211610078578063e4edf85211610060578063e4edf8521461077c578063f2fde38b1461079b578063ffbc91d9146107ba57005b8063c1acbaf21461070c578063dd62ed3e1461072b57005b8063bac15203116100a6578063bac15203146106c4578063bcdc3cfc146106d8578063c0246668146106ed57005b8063adc9772e14610686578063b34117ba146106a557005b8063a0db69ca1161010f578063a457c2d7116100f7578063a457c2d714610629578063a9059cbb14610648578063acad41a41461066757005b8063a0db69ca146105f5578063a2bc66be1461060a57005b80638da5cb5b1161013d5780638da5cb5b1461058657806395d89b41146105b05780639a2bfa65146105c457005b806370a0823114610531578063715018a61461057257005b806333b69c4c116101f7578063481c6a75116101b15780635c975abb116101995780635c975abb146104db57806361ce35291461050a57806368c336271461051d57005b8063481c6a751461049357806352e7c444146104bc57005b806339509351116101df578063395093511461044157806342966c6814610460578063439766ce1461047f57005b806333b69c4c146103e157806335941b1c1461040d57005b806318160ddd1161024857806323b872dd1161023057806323b872dd1461039357806325baa421146103b2578063313ce567146103c657005b806318160ddd14610357578063187fcb161461037f57005b8063095ea7b311610276578063095ea7b3146103015780630f144a481461033057806311c841201461033857005b80630526c60b1461029757806306fdde03146102e057005b3661029557005b005b3480156102a2575f80fd5b506102b66102b1366004613eb2565b6107d9565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156102eb575f80fd5b506102f461080e565b6040516102d79190613eeb565b34801561030c575f80fd5b5061032061031b366004613f5c565b61089e565b60405190151581526020016102d7565b6102956108b7565b348015610343575f80fd5b50610295610352366004613f86565b6109ef565b348015610362575f80fd5b506b033b2e3c9fd0803ce80000005b6040519081526020016102d7565b34801561038a575f80fd5b50610371610b26565b34801561039e575f80fd5b506103206103ad366004613fbd565b610b3c565b3480156103bd575f80fd5b50610371610c21565b3480156103d1575f80fd5b50604051601281526020016102d7565b3480156103ec575f80fd5b506104006103fb366004613ffb565b610ca4565b6040516102d79190614016565b348015610418575f80fd5b5061042c610427366004613f5c565b610d72565b604080519283526020830191909152016102d7565b34801561044c575f80fd5b5061032061045b366004613f5c565b610e1d565b34801561046b575f80fd5b5061029561047a366004613eb2565b610e68565b34801561048a575f80fd5b50610295610f09565b34801561049e575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156104c7575f80fd5b506102956104d6366004613ffb565b610f1b565b3480156104e6575f80fd5b5060015474010000000000000000000000000000000000000000900460ff16610320565b610295610518366004613f5c565b6111f4565b348015610528575f80fd5b506103716113c9565b34801561053c575f80fd5b5061037161054b366004613ffb565b73ffffffffffffffffffffffffffffffffffffffff165f908152600b602052604090205490565b34801561057d575f80fd5b5061029561141c565b348015610591575f80fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156105bb575f80fd5b506102f461142d565b3480156105cf575f80fd5b506005546103209074010000000000000000000000000000000000000000900460ff1681565b348015610600575f80fd5b5061037160135481565b348015610615575f80fd5b5061029561062436600461406e565b61143c565b348015610634575f80fd5b50610320610643366004613f5c565b61145c565b348015610653575f80fd5b50610320610662366004613f5c565b611511565b348015610672575f80fd5b506102b6610681366004613eb2565b61151e565b348015610691575f80fd5b506102956106a0366004613f5c565b611558565b3480156106b0575f80fd5b506102956106bf3660046140ad565b611662565b3480156106cf575f80fd5b506102956116f8565b3480156106e3575f80fd5b5061037160145481565b3480156106f8575f80fd5b506102956107073660046140ad565b611708565b348015610717575f80fd5b50610371610726366004613f5c565b611796565b348015610736575f80fd5b50610371610745366004613f86565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600a6020908152604080832093909416825291909152205490565b348015610787575f80fd5b50610295610796366004613ffb565b6117df565b3480156107a6575f80fd5b506102956107b5366004613ffb565b611872565b3480156107c5575f80fd5b506102956107d4366004613ffb565b611929565b600281815481106107e8575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6060600d805461081d906140d9565b80601f0160208091040260200160405190810160405280929190818152602001828054610849906140d9565b80156108945780601f1061086b57610100808354040283529160200191610894565b820191905f5260205f20905b81548152906001019060200180831161087757829003601f168201915b5050505050905090565b5f336108ab818585611a96565b60019150505b92915050565b4780610924576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a65726f2042616c616e6365000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f811461097b576040519150601f19603f3d011682016040523d82523d5f602084013e610980565b606091505b50509050806109eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f53656e64204661696c6564000000000000000000000000000000000000000000604482015260640161091b565b5050565b6109f7611b03565b73ffffffffffffffffffffffffffffffffffffffff821615610a8d57600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b73ffffffffffffffffffffffffffffffffffffffff8116156109eb57600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691821790555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b6003545f90610b3790600190614151565b905090565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600a602090815260408083203380855292528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c0a5783811015610bfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e73756666696369656e7420616c6c6f77616e636500000000000000000000604482015260640161091b565b610c0a8683868403611a96565b610c15868686611b84565b50600195945050505050565b5f683635c9adc5dea0000060105442610c3a9190614151565b610c449190614164565b612710610c5e6b033b2e3c9fd0803ce8000000600f614164565b610c6891906141a8565b610c7291906141bb565b9050610c8b60646b033b2e3c9fd0803ce80000006141a8565b811115610ca157506b033b2e3c9fd0803ce80000005b90565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600c60205260409020546060908015610d6c5760038181548110610ce557610ce56141ce565b905f5260205f209060020201600101805480602002602001604051908101604052809291908181526020015f905b82821015610d60578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505081526020019060010190610d13565b50505050915050919050565b50919050565b5f805f80600f545f14610d8e57610d88426120ca565b90925090505b73ffffffffffffffffffffffffffffffffffffffff86165f908152600c602052604081205490610dbe82886121f0565b9050610dce81604001514261230e565b610dda90612710614151565b94508215610e12576020810151815164e8d4a5100090610dfb908690614164565b610e0591906141a8565b610e0f9190614151565b95505b505050509250929050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906108ab9082908690610e639087906141bb565b611a96565b335f908152600b602052604081208054839290610e86908490614151565b90915550506103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290610ec89084906141bb565b90915550506040518181526103699033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350565b610f11612368565b610f196123e8565b565b610f23612368565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600860205260408120549003610fb0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742072656769737465726564210000000000000000000000000000000000604482015260640161091b565b60025473ffffffffffffffffffffffffffffffffffffffff82165f908152600860205260409020541061103f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420706169722100000000000000000000000000000000000000604482015260640161091b565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526008602052604090205460025461107390600190614151565b811015611160576002805461108a90600190614151565b8154811061109a5761109a6141ce565b5f918252602090912001546002805473ffffffffffffffffffffffffffffffffffffffff90921691839081106110d2576110d26141ce565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060085f6002848154811061112e5761112e6141ce565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020555b6002805480611171576111716141fb565b5f828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff9390931681526008909252506040812055565b6111fc612368565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa158015611266573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061128a9190614228565b9050808211156112f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365206c6f77000000000000000000000000000000000000000000604482015260640161091b565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6113305f5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303815f875af115801561139f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113c3919061423f565b50505050565b5f805b60035481101561141857600381815481106113e9576113e96141ce565b5f91825260209091206001600290920201015461140690836141bb565b91506114118161425a565b90506113cc565b5090565b611424611b03565b610f195f612481565b6060600e805461081d906140d9565b6114446124f7565b61144c61257c565b61145783838361261c565b505050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190838110156114f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4465637265617365732062656c6f772030000000000000000000000000000000604482015260640161091b565b6115068286868403611a96565b506001949350505050565b5f336108ab818585611b84565b6003818154811061152d575f80fd5b5f91825260209091206002909102015473ffffffffffffffffffffffffffffffffffffffff16905081565b6115606124f7565b805f036115c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f43616e6e6f74207374616b65205a65726f000000000000000000000000000000604482015260640161091b565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604081205490819003611658576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091b565b6114578383612c25565b61166a612368565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526006602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527f6967fd9beca531ca64fc6f897b579e9ea3e2e937cf55341df2151665ba43d5ef91015b60405180910390a15050565b611700612368565b610f19612e56565b611710612368565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526009602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527feb0184c59a430a1717ee5868decd2a492123fadbdb07af787cb52a263a0650b891016116ec565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600c6020526040812054816117c682856121f0565b90506117d681604001514261230e565b95945050505050565b6117e7612368565b5f805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f80f15e9dbc60884fdb59fb8ed4fc48a9a689e028f055e893ed45ca5be67c5c8591a35f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61187a611b03565b73ffffffffffffffffffffffffffffffffffffffff811661191d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161091b565b61192681612481565b50565b611931612368565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260086020526040902054156119bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920726567697374657265642100000000000000000000000000604482015260640161091b565b60028054600180820183555f8390527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790559054611a3a9190614151565b73ffffffffffffffffffffffffffffffffffffffff9091165f90815260086020908152604080832093909355600690522080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b73ffffffffffffffffffffffffffffffffffffffff8381165f818152600a602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161091b565b611b8c6124f7565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054811115611c1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365204c6f77000000000000000000000000000000000000000000604482015260640161091b565b60055474010000000000000000000000000000000000000000900460ff1615611cd957683635c9adc5dea0000060105442611c559190614151565b611c5f9190614164565b612710611c796b033b2e3c9fd0803ce8000000600f614164565b611c8391906141a8565b611c8d91906141bb565b601255611ca760646b033b2e3c9fd0803ce80000006141a8565b6012541115611cd957600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555b611ce38383612ead565b15611d835760125473ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054611d1b9083906141bb565b1115611d83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5768616c65204e6f7420416c6c6f776564000000000000000000000000000000604482015260640161091b565b611d8c83612f53565b611d9582612f53565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460019060ff1680611def575073ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460ff165b15611df757505f5b73ffffffffffffffffffffffffffffffffffffffff84165f9081526007602052604090205460ff16158015611e51575073ffffffffffffffffffffffffffffffffffffffff83165f9081526007602052604090205460ff16155b15611e5957505f5b8015611fe9575f80611e6a8461305f565b73ffffffffffffffffffffffffffffffffffffffff88165f908152600b6020526040812080549395509193508692611ea3908490614151565b909155505073ffffffffffffffffffffffffffffffffffffffff85165f908152600b602052604081208054839290611edc9084906141bb565b925050819055508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611f4291815260200190565b60405180910390a38115611fe2576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054849290611f8d9084906141bb565b90915550506040518281526103699073ffffffffffffffffffffffffffffffffffffffff8816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b50506113c3565b73ffffffffffffffffffffffffffffffffffffffff84165f908152600b60205260408120805484929061201d908490614151565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040812080548492906120569084906141bb565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516120bc91815260200190565b60405180910390a350505050565b5f80600f545f03612137576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e666c6174696f6e206e6f7420737461727465642100000000000000000000604482015260640161091b565b5f600f54846121469190614151565b905080156121e4575f6121656b033b2e3c814887e4de2400008361308c565b90506b033b2e3c9fd0803ce80000006bffffffffffffffffffffffff16816013546121909190614164565b61219a91906141a8565b6013546121a79190614151565b93506014545f146121de576014546121c464e8d4a5100086614164565b6121ce91906141a8565b6011546121db91906141bb565b92505b506121ea565b60115491505b50915091565b61221160405180606001604052805f81526020015f81526020015f81525090565b60038381548110612224576122246141ce565b905f5260205f20906002020160010180549050821061229f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b6520696e64657820696e636f72726563742100000000000000000000604482015260640161091b565b600383815481106122b2576122b26141ce565b905f5260205f20906002020160010182815481106122d2576122d26141ce565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050905092915050565b5f8161231e846301dfe2006141bb565b11156108b1575f6224ea006123338585614151565b61233d91906141a8565b9050600d8110156123615761235381600d614151565b61235e906064614164565b91505b5092915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d3a43616c6c6572206e6f74206d616e61676572000000000000000000000000604482015260640161091b565b6123f06124f7565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586124573390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60015474010000000000000000000000000000000000000000900460ff1615610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161091b565b600f544290811115611926575f80612593836120ca565b91509150815f146114575782600f819055508160135f8282546125b69190614151565b9091555050305f908152600b6020526040812080548492906125d99084906141bb565b909155505060405182815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36011555050565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600860205260408120548082036126aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091b565b5f6126b58486613103565b90505f61271090505f826020015164e8d4a51000601154855f01516126da9190614164565b6126e491906141a8565b6126ee9190614151565b335f90815260096020526040902054909150889060ff16156127b85761272b73ffffffffffffffffffffffffffffffffffffffff8216338a613614565b6001955081156127b357305f908152600b602052604081208054849290612753908490614151565b9091555050335f908152600b6020526040812080548492906127769084906141bb565b9091555050604051828152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b612b4d565b5f6127106127c760648b614164565b6127d191906141a8565b90505f816127df818c614151565b6127e99190614151565b90505f6127106127fa606487614164565b61280491906141a8565b90505f816128128188614151565b61281c9190614151565b905061282c88604001514261230e565b6128369088614151565b96505f6127106128468986614164565b61285091906141a8565b905061287373ffffffffffffffffffffffffffffffffffffffff87163383613614565b60045461289a9073ffffffffffffffffffffffffffffffffffffffff888116911687613614565b6005546128c19073ffffffffffffffffffffffffffffffffffffffff888116911687613614565b60019a505f6128d08286614151565b905080156128ff576004546128ff9073ffffffffffffffffffffffffffffffffffffffff898116911683613614565b5f61271061290d8b86614164565b61291791906141a8565b90508015612ab557305f908152600b6020526040812080548b929061293d908490614151565b9091555050335f908152600b6020526040812080548392906129609084906141bb565b909155505060045473ffffffffffffffffffffffffffffffffffffffff165f908152600b60205260408120805487929061299b9084906141bb565b909155505060055473ffffffffffffffffffffffffffffffffffffffff165f908152600b6020526040812080548792906129d69084906141bb565b9091555050604051818152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360045460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360055460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b5f612ac08286614151565b90508015612b44576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290612b059084906141bb565b90915550506040518181526103699030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b50505050505050505b8760145f828254612b5e9190614151565b909155505060208481015160408087015181518c81529384019290925282015242606082015233907fdcfd2b4017d03f7e541021db793b2f9b31e4acdee005f789e52853c390e3e9629060800160405180910390a285612c1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f556e7374616b65206661696c6564000000000000000000000000000000000000604482015260640161091b565b505050505050505050565b612c2d61257c565b335f90815260096020526040812054819060ff1615612c4d575081612c7f565b612710612c5b606485614164565b612c6591906141a8565b915081612c728185614151565b612c7c9190614151565b90505b83612ca273ffffffffffffffffffffffffffffffffffffffff82163330856136e8565b8215612cfa57600454612cd19073ffffffffffffffffffffffffffffffffffffffff83811691339116866136e8565b600554612cfa9073ffffffffffffffffffffffffffffffffffffffff83811691339116866136e8565b335f908152600c602052604081205490819003612d1d57612d1a33613746565b90505b5f64e8d4a5100084601154612d329190614164565b612d3c91906141a8565b905060038281548110612d5157612d516141ce565b5f91825260208083206040805160608101825289815280840187815242928201928352600160029687029094018401805480860182559088529487209151600390950290910193845551918301919091555191015560148054869290612db89084906141bb565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167f9cfd25589d1eb8ad71e342a86a8524e83522e3936c0803048c08f6d9ad974f40600160038581548110612e0c57612e0c6141ce565b905f5260205f20906002020160010180549050612e299190614151565b6040805191825260208201889052810184905242606082015260800160405180910390a250505050505050565b612e5e6137df565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612457565b6005545f9074010000000000000000000000000000000000000000900460ff168015612ef4575060015473ffffffffffffffffffffffffffffffffffffffff848116911614155b8015612f1b575060015473ffffffffffffffffffffffffffffffffffffffff838116911614155b8015612f4c575073ffffffffffffffffffffffffffffffffffffffff82165f9081526006602052604090205460ff16155b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f03612f745750565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604090205460ff16611926575f612faa82613863565b905073ffffffffffffffffffffffffffffffffffffffff8116612fcb575050565b5f612fd58361388e565b905073ffffffffffffffffffffffffffffffffffffffff8116612ff757505050565b505073ffffffffffffffffffffffffffffffffffffffff165f908152600760209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092556006909352922080549091169091179055565b5f8061271061306f602885614164565b61307991906141a8565b91506130858284614151565b9050915091565b5f613098600283614291565b5f036130b0576b033b2e3c9fd0803ce80000006130b2565b825b90506130bf6002836141a8565b91505b81156108b1576130d283846138b9565b92506130df600283614291565b156130f1576130ee81846138b9565b90505b6130fc6002836141a8565b91506130c2565b61312460405180606001604052805f81526020015f81526020015f81525090565b335f908152600c602052604090205461313d81856121f0565b915082825f015110156131ac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e7374616b696e6720746f6f206d7563680000000000000000000000000000604482015260640161091b565b815183900361358d576001600382815481106131ca576131ca6141ce565b905f5260205f209060020201600101805490506131e79190614151565b8410156132b95760038181548110613201576132016141ce565b905f5260205f209060020201600101600160038381548110613225576132256141ce565b905f5260205f209060020201600101805490506132429190614151565b81548110613252576132526141ce565b905f5260205f20906003020160038281548110613271576132716141ce565b905f5260205f2090600202016001018581548110613291576132916141ce565b5f91825260209091208254600390920201908155600180830154908201556002918201549101555b600381815481106132cc576132cc6141ce565b905f5260205f2090600202016001018054806132ea576132ea6141fb565b5f8281526020812060037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093018381029091018281556001810183905560020191909155909155805482908110613344576133446141ce565b5f918252602082206001600290920201015490036135885760035461336b90600190614151565b8110156134fd576003805461338290600190614151565b81548110613392576133926141ce565b905f5260205f209060020201600382815481106133b1576133b16141ce565b5f9182526020909120825460029092020180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091178155600180830180546134189284019190613e15565b50905050600380548061342d5761342d6141fb565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155906134936001830182613e77565b50509055335f908152600c6020819052604082208290556003805484939190849081106134c2576134c26141ce565b5f918252602080832060029092029091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902055612361565b600380548061350e5761350e6141fb565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155906135746001830182613e77565b50509055335f908152600c60205260408120555b612361565b5f600382815481106135a1576135a16141ce565b905f5260205f20906002020160010185815481106135c1576135c16141ce565b5f91825260208220855160039092020192506135de908690614151565b80835560115490915064e8d4a51000906135f9908390614164565b61360391906141a8565b826001018190555050505092915050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114579084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526138f0565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526113c39085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401613666565b6003805460019081018083555f928352829161376191614151565b90508260038281548110613777576137776141ce565b5f918252602080832060029290920290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055949091168152600c90935260409092208290555090565b60015474010000000000000000000000000000000000000000900460ff16610f19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161091b565b5f6108b1827f0dfe1681000000000000000000000000000000000000000000000000000000006139fd565b5f6108b1827fd21220a7000000000000000000000000000000000000000000000000000000006139fd565b5f6b033b2e3c9fd0803ce80000006138e66138d48585613b0c565b6b019d971e4fe8401e74000000613b95565b612f4c91906141a8565b5f613951826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613c0c9092919063ffffffff16565b905080515f1480613971575080806020019051810190613971919061423f565b611457576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161091b565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000851617905290515f918291829173ffffffffffffffffffffffffffffffffffffffff871691613a7f91906142a4565b5f60405180830381855afa9150503d805f8114613ab7576040519150601f19603f3d011682016040523d82523d5f602084013e613abc565b606091505b5091509150811580613acd57508051155b15613adc575f925050506108b1565b8051602003613b025780806020019051810190613af991906142bf565b925050506108b1565b505f949350505050565b5f811580613b2f57508282613b218183614164565b9250613b2d90836141a8565b145b6108b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015260640161091b565b5f82613ba183826141bb565b91508110156108b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015260640161091b565b6060613c1a84845f85613c22565b949350505050565b606082471015613cb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161091b565b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051613cdc91906142a4565b5f6040518083038185875af1925050503d805f8114613d16576040519150601f19603f3d011682016040523d82523d5f602084013e613d1b565b606091505b5091509150613d2c87838387613d37565b979650505050505050565b60608315613dcc5782515f03613dc55773ffffffffffffffffffffffffffffffffffffffff85163b613dc5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161091b565b5081613c1a565b613c1a8383815115613de15781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091b9190613eeb565b828054828255905f5260205f20906003028101928215613e6b575f5260205f209160030282015b82811115613e6b5782548255600180840154908301556002808401549083015560039283019290910190613e3c565b50611418929150613e91565b5080545f8255600302905f5260205f209081019061192691905b5b80821115611418575f808255600182018190556002820155600301613e92565b5f60208284031215613ec2575f80fd5b5035919050565b5f5b83811015613ee3578181015183820152602001613ecb565b50505f910152565b602081525f8251806020840152613f09816040850160208701613ec9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff81168114611926575f80fd5b5f8060408385031215613f6d575f80fd5b8235613f7881613f3b565b946020939093013593505050565b5f8060408385031215613f97575f80fd5b8235613fa281613f3b565b91506020830135613fb281613f3b565b809150509250929050565b5f805f60608486031215613fcf575f80fd5b8335613fda81613f3b565b92506020840135613fea81613f3b565b929592945050506040919091013590565b5f6020828403121561400b575f80fd5b8135612f4c81613f3b565b602080825282518282018190525f919060409081850190868401855b828110156140615781518051855286810151878601528501518585015260609093019290850190600101614032565b5091979650505050505050565b5f805f60608486031215614080575f80fd5b833561408b81613f3b565b95602085013595506040909401359392505050565b8015158114611926575f80fd5b5f80604083850312156140be575f80fd5b82356140c981613f3b565b91506020830135613fb2816140a0565b600181811c908216806140ed57607f821691505b602082108103610d6c577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108b1576108b1614124565b80820281158282048414176108b1576108b1614124565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826141b6576141b661417b565b500490565b808201808211156108b1576108b1614124565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f60208284031215614238575f80fd5b5051919050565b5f6020828403121561424f575f80fd5b8151612f4c816140a0565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361428a5761428a614124565b5060010190565b5f8261429f5761429f61417b565b500690565b5f82516142b5818460208701613ec9565b9190910192915050565b5f602082840312156142cf575f80fd5b8151612f4c81613f3b56fea26469706673582212200fb43125b121149aa09c463008fe157f2de00f1603af49ffade3312c9973754b64736f6c63430008140033