false
true
0

Contract Address Details

0xA9D4230b4899e6aaC0D84e540941B3832ABA3ba0

Token
www.fluffyslippers.life (FLUFFY)
Creator
0xb0c2b1–982523 at 0x1dee0b–a8bf4b
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
11,962 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
27557491
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
FLUFFY




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




Optimization runs
1000000
EVM Version
default




Verified at
2023-06-25T23:00:59.738432Z

Constructor Arguments

0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9000000000000000000000000fb7103d7011dfa60c18c6961c5a38038d8048fe0000000000000000000000000fc51c335f8be70d0541944da5d5cd0638bbcc63d00000000000000000000000000000000000000000000000000000000000000177777772e666c75666679736c6970706572732e6c6966650000000000000000000000000000000000000000000000000000000000000000000000000000000006464c554646590000000000000000000000000000000000000000000000000000

Arg [0] (string) : www.fluffyslippers.life
Arg [1] (string) : FLUFFY
Arg [2] (address) : 0x165c3410fc91ef562c50559f7d2289febed552d9
Arg [3] (address) : 0xfb7103d7011dfa60c18c6961c5a38038d8048fe0
Arg [4] (address) : 0xfc51c335f8be70d0541944da5d5cd0638bbcc63d

              

contracts/FLUFFY.sol

/*
 * @title FLUFFY - FLUFFY SLIPPERS - LP staking
 * @notice https://www.fluffyslippers.life/
 *
 * FLUFFY 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 FLUFFY 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 = 25;
    uint256 private constant _TOTAL_SUPPLY = 1e30; // 100 billion + 18 decimals
    uint256 private constant _TRADE_BURN_BIPS = 20;

    uint256 public 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;

        _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 = 1e27 + (block.timestamp - _deployedTS) * 1e23;

            if (maxWalletTokenLimit > 1e28) {
                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;
    }

    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 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/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/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/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/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/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/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":"","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 FLUFFY.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

0x60806040526005805460ff60a01b1916600160a01b17905534801562000023575f80fd5b50604051620049eb380380620049eb833981016040819052620000469162000529565b5f80546001600160a01b0319163390811782556040519091907f80f15e9dbc60884fdb59fb8ed4fc48a9a689e028f055e893ed45ca5be67c5c85908290a36200008f33620003fe565b6001805460ff60a01b19169055600d620000aa868262000651565b50600e620000b9858262000651565b50335f908152600960208181526040808420805460ff199081166001908117909255600680855283872080548316841790556003805484019055600480546001600160a01b038b81166001600160a01b0319928316811790935591895287875285892080548516861790558287528589208054851686179055600580548b84169216821790558852868652848820805484168517905581865284882080548416851790558a1687529484528286208054821683179055939092528320805490921617905562000197600a6c0c9f2c9cd04674edea400000006200072d565b9050620001b36c0c9f2c9cd04674edea4000000060096200074d565b601355335f818152600b60209081526040808320859055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a342600f8190556010556002805460010181555f9081526040805163c45a015560e01b815290518692916001600160a01b0384169163c45a0155916004808201926020929091908290030181865afa15801562000257573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200027d91906200076d565b90505f816001600160a01b031663c9c6539630856001600160a01b031663ef8ef56f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002cd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620002f391906200076d565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526044016020604051808303815f875af11580156200033e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200036491906200076d565b60028054600180820183555f8390527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180546001600160a01b0319166001600160a01b0385161790559054919250620003c09162000790565b6001600160a01b039091165f908152600860209081526040808320939093556006905220805460ff1916600117905550620007a69650505050505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f83011262000473575f80fd5b81516001600160401b03808211156200049057620004906200044f565b604051601f8301601f19908116603f01168101908282118183101715620004bb57620004bb6200044f565b81604052838152602092508683858801011115620004d7575f80fd5b5f91505b83821015620004fa5785820183015181830184015290820190620004db565b5f93810190920192909252949350505050565b80516001600160a01b038116811462000524575f80fd5b919050565b5f805f805f60a086880312156200053e575f80fd5b85516001600160401b038082111562000555575f80fd5b6200056389838a0162000463565b9650602088015191508082111562000579575f80fd5b50620005888882890162000463565b94505062000599604087016200050d565b9250620005a9606087016200050d565b9150620005b9608087016200050d565b90509295509295909350565b600181811c90821680620005da57607f821691505b602082108103620005f957634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200064c575f81815260208120601f850160051c81016020861015620006275750805b601f850160051c820191505b81811015620006485782815560010162000633565b5050505b505050565b81516001600160401b038111156200066d576200066d6200044f565b62000685816200067e8454620005c5565b84620005ff565b602080601f831160018114620006bb575f8415620006a35750858301515b5f19600386901b1c1916600185901b17855562000648565b5f85815260208120601f198616915b82811015620006eb57888601518255948401946001909101908401620006ca565b50858210156200070957878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b5f826200074857634e487b7160e01b5f52601260045260245ffd5b500490565b808202811582820484141762000767576200076762000719565b92915050565b5f602082840312156200077e575f80fd5b62000789826200050d565b9392505050565b8181038181111562000767576200076762000719565b61423780620007b45f395ff3fe60806040526004361061028e575f3560e01c806370a0823111610155578063adc9772e116100be578063c1acbaf211610078578063e4edf85211610060578063e4edf8521461077e578063f2fde38b1461079d578063ffbc91d9146107bc57005b8063c1acbaf21461070e578063dd62ed3e1461072d57005b8063bac15203116100a6578063bac15203146106c6578063bcdc3cfc146106da578063c0246668146106ef57005b8063adc9772e14610688578063b34117ba146106a757005b8063a0db69ca1161010f578063a457c2d7116100f7578063a457c2d71461062b578063a9059cbb1461064a578063acad41a41461066957005b8063a0db69ca146105f7578063a2bc66be1461060c57005b80638da5cb5b1161013d5780638da5cb5b1461058857806395d89b41146105b25780639a2bfa65146105c657005b806370a0823114610533578063715018a61461057457005b806333b69c4c116101f7578063481c6a75116101b15780635c975abb116101995780635c975abb146104dd57806361ce35291461050c57806368c336271461051f57005b8063481c6a751461049557806352e7c444146104be57005b806339509351116101df578063395093511461044357806342966c6814610462578063439766ce1461048157005b806333b69c4c146103e357806335941b1c1461040f57005b806318160ddd1161024857806323b872dd1161023057806323b872dd1461039457806325baa421146103b3578063313ce567146103c857005b806318160ddd14610357578063187fcb161461038057005b8063095ea7b311610276578063095ea7b3146103015780630f144a481461033057806311c841201461033857005b80630526c60b1461029757806306fdde03146102e057005b3661029557005b005b3480156102a2575f80fd5b506102b66102b1366004613dd9565b6107db565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156102eb575f80fd5b506102f4610810565b6040516102d79190613e12565b34801561030c575f80fd5b5061032061031b366004613e83565b6108a0565b60405190151581526020016102d7565b6102956108b9565b348015610343575f80fd5b50610295610352366004613ead565b6109f1565b348015610362575f80fd5b506c0c9f2c9cd04674edea400000005b6040519081526020016102d7565b34801561038b575f80fd5b50610372610b28565b34801561039f575f80fd5b506103206103ae366004613ee4565b610b3e565b3480156103be575f80fd5b5061037260125481565b3480156103d3575f80fd5b50604051601281526020016102d7565b3480156103ee575f80fd5b506104026103fd366004613f22565b610c23565b6040516102d79190613f3d565b34801561041a575f80fd5b5061042e610429366004613e83565b610cf1565b604080519283526020830191909152016102d7565b34801561044e575f80fd5b5061032061045d366004613e83565b610d9c565b34801561046d575f80fd5b5061029561047c366004613dd9565b610de7565b34801561048c575f80fd5b50610295610e88565b3480156104a0575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156104c9575f80fd5b506102956104d8366004613f22565b610e9a565b3480156104e8575f80fd5b5060015474010000000000000000000000000000000000000000900460ff16610320565b61029561051a366004613e83565b611173565b34801561052a575f80fd5b50610372611348565b34801561053e575f80fd5b5061037261054d366004613f22565b73ffffffffffffffffffffffffffffffffffffffff165f908152600b602052604090205490565b34801561057f575f80fd5b5061029561139b565b348015610593575f80fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156105bd575f80fd5b506102f46113ac565b3480156105d1575f80fd5b506005546103209074010000000000000000000000000000000000000000900460ff1681565b348015610602575f80fd5b5061037260135481565b348015610617575f80fd5b50610295610626366004613f95565b6113bb565b348015610636575f80fd5b50610320610645366004613e83565b6113db565b348015610655575f80fd5b50610320610664366004613e83565b611490565b348015610674575f80fd5b506102b6610683366004613dd9565b61149d565b348015610693575f80fd5b506102956106a2366004613e83565b6114d7565b3480156106b2575f80fd5b506102956106c1366004613fd4565b6115e1565b3480156106d1575f80fd5b50610295611677565b3480156106e5575f80fd5b5061037260145481565b3480156106fa575f80fd5b50610295610709366004613fd4565b611687565b348015610719575f80fd5b50610372610728366004613e83565b611715565b348015610738575f80fd5b50610372610747366004613ead565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600a6020908152604080832093909416825291909152205490565b348015610789575f80fd5b50610295610798366004613f22565b61175e565b3480156107a8575f80fd5b506102956107b7366004613f22565b6117f1565b3480156107c7575f80fd5b506102956107d6366004613f22565b6118a8565b600281815481106107ea575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6060600d805461081f90614000565b80601f016020809104026020016040519081016040528092919081815260200182805461084b90614000565b80156108965780601f1061086d57610100808354040283529160200191610896565b820191905f5260205f20905b81548152906001019060200180831161087957829003601f168201915b5050505050905090565b5f336108ad8185856119e1565b60019150505b92915050565b4780610926576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a65726f2042616c616e6365000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f811461097d576040519150601f19603f3d011682016040523d82523d5f602084013e610982565b606091505b50509050806109ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f53656e64204661696c6564000000000000000000000000000000000000000000604482015260640161091d565b5050565b6109f9611a4e565b73ffffffffffffffffffffffffffffffffffffffff821615610a8f57600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b73ffffffffffffffffffffffffffffffffffffffff8116156109ed57600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691821790555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b6003545f90610b3990600190614078565b905090565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600a602090815260408083203380855292528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c0c5783811015610bff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e73756666696369656e7420616c6c6f77616e636500000000000000000000604482015260640161091d565b610c0c86838684036119e1565b610c17868686611acf565b50600195945050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600c60205260409020546060908015610ceb5760038181548110610c6457610c6461408b565b905f5260205f209060020201600101805480602002602001604051908101604052809291908181526020015f905b82821015610cdf578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505081526020019060010190610c92565b50505050915050919050565b50919050565b5f805f80600f545f14610d0d57610d0742611ff1565b90925090505b73ffffffffffffffffffffffffffffffffffffffff86165f908152600c602052604081205490610d3d8288612117565b9050610d4d816040015142612235565b610d5990612710614078565b94508215610d91576020810151815164e8d4a5100090610d7a9086906140b8565b610d8491906140fc565b610d8e9190614078565b95505b505050509250929050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906108ad9082908690610de290879061410f565b6119e1565b335f908152600b602052604081208054839290610e05908490614078565b90915550506103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290610e4790849061410f565b90915550506040518181526103699033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350565b610e9061228f565b610e9861230f565b565b610ea261228f565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600860205260408120549003610f2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742072656769737465726564210000000000000000000000000000000000604482015260640161091d565b60025473ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604090205410610fbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420706169722100000000000000000000000000000000000000604482015260640161091d565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260086020526040902054600254610ff290600190614078565b8110156110df576002805461100990600190614078565b815481106110195761101961408b565b5f918252602090912001546002805473ffffffffffffffffffffffffffffffffffffffff90921691839081106110515761105161408b565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060085f600284815481106110ad576110ad61408b565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020555b60028054806110f0576110f0614122565b5f828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff9390931681526008909252506040812055565b61117b61228f565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156111e5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611209919061414f565b905080821115611275576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365206c6f77000000000000000000000000000000000000000000604482015260640161091d565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6112af5f5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303815f875af115801561131e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113429190614166565b50505050565b5f805b60035481101561139757600381815481106113685761136861408b565b5f918252602090912060016002909202010154611385908361410f565b915061139081614181565b905061134b565b5090565b6113a3611a4e565b610e985f6123a8565b6060600e805461081f90614000565b6113c361241e565b6113cb6124a3565b6113d6838383612543565b505050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015611478576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4465637265617365732062656c6f772030000000000000000000000000000000604482015260640161091d565b61148582868684036119e1565b506001949350505050565b5f336108ad818585611acf565b600381815481106114ac575f80fd5b5f91825260209091206002909102015473ffffffffffffffffffffffffffffffffffffffff16905081565b6114df61241e565b805f03611548576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f43616e6e6f74207374616b65205a65726f000000000000000000000000000000604482015260640161091d565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260086020526040812054908190036115d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091d565b6113d68383612b4c565b6115e961228f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526006602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527f6967fd9beca531ca64fc6f897b579e9ea3e2e937cf55341df2151665ba43d5ef91015b60405180910390a15050565b61167f61228f565b610e98612d7d565b61168f61228f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526009602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527feb0184c59a430a1717ee5868decd2a492123fadbdb07af787cb52a263a0650b8910161166b565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600c6020526040812054816117458285612117565b9050611755816040015142612235565b95945050505050565b61176661228f565b5f805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f80f15e9dbc60884fdb59fb8ed4fc48a9a689e028f055e893ed45ca5be67c5c8591a35f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6117f9611a4e565b73ffffffffffffffffffffffffffffffffffffffff811661189c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161091d565b6118a5816123a8565b50565b6118b061228f565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600860205260409020541561193c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920726567697374657265642100000000000000000000000000604482015260640161091d565b60028054600180820183555f8390527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851617905590546119b99190614078565b73ffffffffffffffffffffffffffffffffffffffff9091165f90815260086020526040902055565b73ffffffffffffffffffffffffffffffffffffffff8381165f818152600a602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161091d565b611ad761241e565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054811115611b65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365204c6f77000000000000000000000000000000000000000000604482015260640161091d565b60055474010000000000000000000000000000000000000000900460ff1615611c0057601054611b959042614078565b611ba99069152d02c7e14af68000006140b8565b611bbf906b033b2e3c9fd0803ce800000061410f565b60128190556b204fce5e3e250261100000001015611c0057600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555b611c0a8383612dd4565b15611caa5760125473ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054611c4290839061410f565b1115611caa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5768616c65204e6f7420416c6c6f776564000000000000000000000000000000604482015260640161091d565b611cb383612e7a565b611cbc82612e7a565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460019060ff1680611d16575073ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460ff165b15611d1e57505f5b73ffffffffffffffffffffffffffffffffffffffff84165f9081526007602052604090205460ff16158015611d78575073ffffffffffffffffffffffffffffffffffffffff83165f9081526007602052604090205460ff16155b15611d8057505f5b8015611f10575f80611d9184612f86565b73ffffffffffffffffffffffffffffffffffffffff88165f908152600b6020526040812080549395509193508692611dca908490614078565b909155505073ffffffffffffffffffffffffffffffffffffffff85165f908152600b602052604081208054839290611e0390849061410f565b925050819055508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611e6991815260200190565b60405180910390a38115611f09576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054849290611eb490849061410f565b90915550506040518281526103699073ffffffffffffffffffffffffffffffffffffffff8816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b5050611342565b73ffffffffffffffffffffffffffffffffffffffff84165f908152600b602052604081208054849290611f44908490614078565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152600b602052604081208054849290611f7d90849061410f565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611fe391815260200190565b60405180910390a350505050565b5f80600f545f0361205e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e666c6174696f6e206e6f7420737461727465642100000000000000000000604482015260640161091d565b5f600f548461206d9190614078565b9050801561210b575f61208c6b033b2e3c814887e4de24000083612fb3565b90506b033b2e3c9fd0803ce80000006bffffffffffffffffffffffff16816013546120b791906140b8565b6120c191906140fc565b6013546120ce9190614078565b93506014545f14612105576014546120eb64e8d4a51000866140b8565b6120f591906140fc565b601154612102919061410f565b92505b50612111565b60115491505b50915091565b61213860405180606001604052805f81526020015f81526020015f81525090565b6003838154811061214b5761214b61408b565b905f5260205f2090600202016001018054905082106121c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b6520696e64657820696e636f72726563742100000000000000000000604482015260640161091d565b600383815481106121d9576121d961408b565b905f5260205f20906002020160010182815481106121f9576121f961408b565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050905092915050565b5f81612245846301dfe20061410f565b11156108b3575f6224ea0061225a8585614078565b61226491906140fc565b9050600d8110156122885761227a81600d614078565b6122859060646140b8565b91505b5092915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d3a43616c6c6572206e6f74206d616e61676572000000000000000000000000604482015260640161091d565b61231761241e565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861237e3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60015474010000000000000000000000000000000000000000900460ff1615610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161091d565b600f5442908111156118a5575f806124ba83611ff1565b91509150815f146113d65782600f819055508160135f8282546124dd9190614078565b9091555050305f908152600b60205260408120805484929061250090849061410f565b909155505060405182815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36011555050565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600860205260408120548082036125d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091d565b5f6125dc848661302a565b90505f61271090505f826020015164e8d4a51000601154855f015161260191906140b8565b61260b91906140fc565b6126159190614078565b335f90815260096020526040902054909150889060ff16156126df5761265273ffffffffffffffffffffffffffffffffffffffff8216338a61353b565b6001955081156126da57305f908152600b60205260408120805484929061267a908490614078565b9091555050335f908152600b60205260408120805484929061269d90849061410f565b9091555050604051828152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b612a74565b5f6127106126ee60198b6140b8565b6126f891906140fc565b90505f81612706818c614078565b6127109190614078565b90505f6127106127216019876140b8565b61272b91906140fc565b90505f816127398188614078565b6127439190614078565b9050612753886040015142612235565b61275d9088614078565b96505f61271061276d89866140b8565b61277791906140fc565b905061279a73ffffffffffffffffffffffffffffffffffffffff8716338361353b565b6004546127c19073ffffffffffffffffffffffffffffffffffffffff88811691168761353b565b6005546127e89073ffffffffffffffffffffffffffffffffffffffff88811691168761353b565b60019a505f6127f78286614078565b90508015612826576004546128269073ffffffffffffffffffffffffffffffffffffffff89811691168361353b565b5f6127106128348b866140b8565b61283e91906140fc565b905080156129dc57305f908152600b6020526040812080548b9290612864908490614078565b9091555050335f908152600b60205260408120805483929061288790849061410f565b909155505060045473ffffffffffffffffffffffffffffffffffffffff165f908152600b6020526040812080548792906128c290849061410f565b909155505060055473ffffffffffffffffffffffffffffffffffffffff165f908152600b6020526040812080548792906128fd90849061410f565b9091555050604051818152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360045460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360055460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b5f6129e78286614078565b90508015612a6b576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290612a2c90849061410f565b90915550506040518181526103699030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b50505050505050505b8760145f828254612a859190614078565b909155505060208481015160408087015181518c81529384019290925282015242606082015233907fdcfd2b4017d03f7e541021db793b2f9b31e4acdee005f789e52853c390e3e9629060800160405180910390a285612b41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f556e7374616b65206661696c6564000000000000000000000000000000000000604482015260640161091d565b505050505050505050565b612b546124a3565b335f90815260096020526040812054819060ff1615612b74575081612ba6565b612710612b826019856140b8565b612b8c91906140fc565b915081612b998185614078565b612ba39190614078565b90505b83612bc973ffffffffffffffffffffffffffffffffffffffff821633308561360f565b8215612c2157600454612bf89073ffffffffffffffffffffffffffffffffffffffff838116913391168661360f565b600554612c219073ffffffffffffffffffffffffffffffffffffffff838116913391168661360f565b335f908152600c602052604081205490819003612c4457612c413361366d565b90505b5f64e8d4a5100084601154612c5991906140b8565b612c6391906140fc565b905060038281548110612c7857612c7861408b565b5f91825260208083206040805160608101825289815280840187815242928201928352600160029687029094018401805480860182559088529487209151600390950290910193845551918301919091555191015560148054869290612cdf90849061410f565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167f9cfd25589d1eb8ad71e342a86a8524e83522e3936c0803048c08f6d9ad974f40600160038581548110612d3357612d3361408b565b905f5260205f20906002020160010180549050612d509190614078565b6040805191825260208201889052810184905242606082015260800160405180910390a250505050505050565b612d85613706565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa3361237e565b6005545f9074010000000000000000000000000000000000000000900460ff168015612e1b575060015473ffffffffffffffffffffffffffffffffffffffff848116911614155b8015612e42575060015473ffffffffffffffffffffffffffffffffffffffff838116911614155b8015612e73575073ffffffffffffffffffffffffffffffffffffffff82165f9081526006602052604090205460ff16155b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f03612e9b5750565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604090205460ff166118a5575f612ed18261378a565b905073ffffffffffffffffffffffffffffffffffffffff8116612ef2575050565b5f612efc836137b5565b905073ffffffffffffffffffffffffffffffffffffffff8116612f1e57505050565b505073ffffffffffffffffffffffffffffffffffffffff165f908152600760209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092556006909352922080549091169091179055565b5f80612710612f966014856140b8565b612fa091906140fc565b9150612fac8284614078565b9050915091565b5f612fbf6002836141b8565b5f03612fd7576b033b2e3c9fd0803ce8000000612fd9565b825b9050612fe66002836140fc565b91505b81156108b357612ff983846137e0565b92506130066002836141b8565b156130185761301581846137e0565b90505b6130236002836140fc565b9150612fe9565b61304b60405180606001604052805f81526020015f81526020015f81525090565b335f908152600c60205260409020546130648185612117565b915082825f015110156130d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e7374616b696e6720746f6f206d7563680000000000000000000000000000604482015260640161091d565b81518390036134b4576001600382815481106130f1576130f161408b565b905f5260205f2090600202016001018054905061310e9190614078565b8410156131e057600381815481106131285761312861408b565b905f5260205f20906002020160010160016003838154811061314c5761314c61408b565b905f5260205f209060020201600101805490506131699190614078565b815481106131795761317961408b565b905f5260205f209060030201600382815481106131985761319861408b565b905f5260205f20906002020160010185815481106131b8576131b861408b565b5f91825260209091208254600390920201908155600180830154908201556002918201549101555b600381815481106131f3576131f361408b565b905f5260205f20906002020160010180548061321157613211614122565b5f8281526020812060037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909301838102909101828155600181018390556002019190915590915580548290811061326b5761326b61408b565b5f918252602082206001600290920201015490036134af5760035461329290600190614078565b81101561342457600380546132a990600190614078565b815481106132b9576132b961408b565b905f5260205f209060020201600382815481106132d8576132d861408b565b5f9182526020909120825460029092020180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911781556001808301805461333f9284019190613d3c565b50905050600380548061335457613354614122565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155906133ba6001830182613d9e565b50509055335f908152600c6020819052604082208290556003805484939190849081106133e9576133e961408b565b5f918252602080832060029092029091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902055612288565b600380548061343557613435614122565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff00000000000000000000000000000000000000001681559061349b6001830182613d9e565b50509055335f908152600c60205260408120555b612288565b5f600382815481106134c8576134c861408b565b905f5260205f20906002020160010185815481106134e8576134e861408b565b5f9182526020822085516003909202019250613505908690614078565b80835560115490915064e8d4a51000906135209083906140b8565b61352a91906140fc565b826001018190555050505092915050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526113d69084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613817565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526113429085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161358d565b6003805460019081018083555f928352829161368891614078565b9050826003828154811061369e5761369e61408b565b5f918252602080832060029290920290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055949091168152600c90935260409092208290555090565b60015474010000000000000000000000000000000000000000900460ff16610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161091d565b5f6108b3827f0dfe168100000000000000000000000000000000000000000000000000000000613924565b5f6108b3827fd21220a700000000000000000000000000000000000000000000000000000000613924565b5f6b033b2e3c9fd0803ce800000061380d6137fb8585613a33565b6b019d971e4fe8401e74000000613abc565b612e7391906140fc565b5f613878826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613b339092919063ffffffff16565b905080515f14806138985750808060200190518101906138989190614166565b6113d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161091d565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000851617905290515f918291829173ffffffffffffffffffffffffffffffffffffffff8716916139a691906141cb565b5f60405180830381855afa9150503d805f81146139de576040519150601f19603f3d011682016040523d82523d5f602084013e6139e3565b606091505b50915091508115806139f457508051155b15613a03575f925050506108b3565b8051602003613a295780806020019051810190613a2091906141e6565b925050506108b3565b505f949350505050565b5f811580613a5657508282613a4881836140b8565b9250613a5490836140fc565b145b6108b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015260640161091d565b5f82613ac8838261410f565b91508110156108b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015260640161091d565b6060613b4184845f85613b49565b949350505050565b606082471015613bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161091d565b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051613c0391906141cb565b5f6040518083038185875af1925050503d805f8114613c3d576040519150601f19603f3d011682016040523d82523d5f602084013e613c42565b606091505b5091509150613c5387838387613c5e565b979650505050505050565b60608315613cf35782515f03613cec5773ffffffffffffffffffffffffffffffffffffffff85163b613cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161091d565b5081613b41565b613b418383815115613d085781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091d9190613e12565b828054828255905f5260205f20906003028101928215613d92575f5260205f209160030282015b82811115613d925782548255600180840154908301556002808401549083015560039283019290910190613d63565b50611397929150613db8565b5080545f8255600302905f5260205f20908101906118a591905b5b80821115611397575f808255600182018190556002820155600301613db9565b5f60208284031215613de9575f80fd5b5035919050565b5f5b83811015613e0a578181015183820152602001613df2565b50505f910152565b602081525f8251806020840152613e30816040850160208701613df0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146118a5575f80fd5b5f8060408385031215613e94575f80fd5b8235613e9f81613e62565b946020939093013593505050565b5f8060408385031215613ebe575f80fd5b8235613ec981613e62565b91506020830135613ed981613e62565b809150509250929050565b5f805f60608486031215613ef6575f80fd5b8335613f0181613e62565b92506020840135613f1181613e62565b929592945050506040919091013590565b5f60208284031215613f32575f80fd5b8135612e7381613e62565b602080825282518282018190525f919060409081850190868401855b82811015613f885781518051855286810151878601528501518585015260609093019290850190600101613f59565b5091979650505050505050565b5f805f60608486031215613fa7575f80fd5b8335613fb281613e62565b95602085013595506040909401359392505050565b80151581146118a5575f80fd5b5f8060408385031215613fe5575f80fd5b8235613ff081613e62565b91506020830135613ed981613fc7565b600181811c9082168061401457607f821691505b602082108103610ceb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108b3576108b361404b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80820281158282048414176108b3576108b361404b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261410a5761410a6140cf565b500490565b808201808211156108b3576108b361404b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f6020828403121561415f575f80fd5b5051919050565b5f60208284031215614176575f80fd5b8151612e7381613fc7565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141b1576141b161404b565b5060010190565b5f826141c6576141c66140cf565b500690565b5f82516141dc818460208701613df0565b9190910192915050565b5f602082840312156141f6575f80fd5b8151612e7381613e6256fea2646970667358221220ac2148ef9cede5ba11e1b93957a6cb39f717d37a02b7b7b080ab690a5fdca15064736f6c6343000814003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d9000000000000000000000000fb7103d7011dfa60c18c6961c5a38038d8048fe0000000000000000000000000fc51c335f8be70d0541944da5d5cd0638bbcc63d00000000000000000000000000000000000000000000000000000000000000177777772e666c75666679736c6970706572732e6c6966650000000000000000000000000000000000000000000000000000000000000000000000000000000006464c554646590000000000000000000000000000000000000000000000000000

Deployed ByteCode

0x60806040526004361061028e575f3560e01c806370a0823111610155578063adc9772e116100be578063c1acbaf211610078578063e4edf85211610060578063e4edf8521461077e578063f2fde38b1461079d578063ffbc91d9146107bc57005b8063c1acbaf21461070e578063dd62ed3e1461072d57005b8063bac15203116100a6578063bac15203146106c6578063bcdc3cfc146106da578063c0246668146106ef57005b8063adc9772e14610688578063b34117ba146106a757005b8063a0db69ca1161010f578063a457c2d7116100f7578063a457c2d71461062b578063a9059cbb1461064a578063acad41a41461066957005b8063a0db69ca146105f7578063a2bc66be1461060c57005b80638da5cb5b1161013d5780638da5cb5b1461058857806395d89b41146105b25780639a2bfa65146105c657005b806370a0823114610533578063715018a61461057457005b806333b69c4c116101f7578063481c6a75116101b15780635c975abb116101995780635c975abb146104dd57806361ce35291461050c57806368c336271461051f57005b8063481c6a751461049557806352e7c444146104be57005b806339509351116101df578063395093511461044357806342966c6814610462578063439766ce1461048157005b806333b69c4c146103e357806335941b1c1461040f57005b806318160ddd1161024857806323b872dd1161023057806323b872dd1461039457806325baa421146103b3578063313ce567146103c857005b806318160ddd14610357578063187fcb161461038057005b8063095ea7b311610276578063095ea7b3146103015780630f144a481461033057806311c841201461033857005b80630526c60b1461029757806306fdde03146102e057005b3661029557005b005b3480156102a2575f80fd5b506102b66102b1366004613dd9565b6107db565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156102eb575f80fd5b506102f4610810565b6040516102d79190613e12565b34801561030c575f80fd5b5061032061031b366004613e83565b6108a0565b60405190151581526020016102d7565b6102956108b9565b348015610343575f80fd5b50610295610352366004613ead565b6109f1565b348015610362575f80fd5b506c0c9f2c9cd04674edea400000005b6040519081526020016102d7565b34801561038b575f80fd5b50610372610b28565b34801561039f575f80fd5b506103206103ae366004613ee4565b610b3e565b3480156103be575f80fd5b5061037260125481565b3480156103d3575f80fd5b50604051601281526020016102d7565b3480156103ee575f80fd5b506104026103fd366004613f22565b610c23565b6040516102d79190613f3d565b34801561041a575f80fd5b5061042e610429366004613e83565b610cf1565b604080519283526020830191909152016102d7565b34801561044e575f80fd5b5061032061045d366004613e83565b610d9c565b34801561046d575f80fd5b5061029561047c366004613dd9565b610de7565b34801561048c575f80fd5b50610295610e88565b3480156104a0575f80fd5b505f5473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156104c9575f80fd5b506102956104d8366004613f22565b610e9a565b3480156104e8575f80fd5b5060015474010000000000000000000000000000000000000000900460ff16610320565b61029561051a366004613e83565b611173565b34801561052a575f80fd5b50610372611348565b34801561053e575f80fd5b5061037261054d366004613f22565b73ffffffffffffffffffffffffffffffffffffffff165f908152600b602052604090205490565b34801561057f575f80fd5b5061029561139b565b348015610593575f80fd5b5060015473ffffffffffffffffffffffffffffffffffffffff166102b6565b3480156105bd575f80fd5b506102f46113ac565b3480156105d1575f80fd5b506005546103209074010000000000000000000000000000000000000000900460ff1681565b348015610602575f80fd5b5061037260135481565b348015610617575f80fd5b50610295610626366004613f95565b6113bb565b348015610636575f80fd5b50610320610645366004613e83565b6113db565b348015610655575f80fd5b50610320610664366004613e83565b611490565b348015610674575f80fd5b506102b6610683366004613dd9565b61149d565b348015610693575f80fd5b506102956106a2366004613e83565b6114d7565b3480156106b2575f80fd5b506102956106c1366004613fd4565b6115e1565b3480156106d1575f80fd5b50610295611677565b3480156106e5575f80fd5b5061037260145481565b3480156106fa575f80fd5b50610295610709366004613fd4565b611687565b348015610719575f80fd5b50610372610728366004613e83565b611715565b348015610738575f80fd5b50610372610747366004613ead565b73ffffffffffffffffffffffffffffffffffffffff9182165f908152600a6020908152604080832093909416825291909152205490565b348015610789575f80fd5b50610295610798366004613f22565b61175e565b3480156107a8575f80fd5b506102956107b7366004613f22565b6117f1565b3480156107c7575f80fd5b506102956107d6366004613f22565b6118a8565b600281815481106107ea575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b6060600d805461081f90614000565b80601f016020809104026020016040519081016040528092919081815260200182805461084b90614000565b80156108965780601f1061086d57610100808354040283529160200191610896565b820191905f5260205f20905b81548152906001019060200180831161087957829003601f168201915b5050505050905090565b5f336108ad8185856119e1565b60019150505b92915050565b4780610926576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a65726f2042616c616e6365000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f811461097d576040519150601f19603f3d011682016040523d82523d5f602084013e610982565b606091505b50509050806109ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f53656e64204661696c6564000000000000000000000000000000000000000000604482015260640161091d565b5050565b6109f9611a4e565b73ffffffffffffffffffffffffffffffffffffffff821615610a8f57600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b73ffffffffffffffffffffffffffffffffffffffff8116156109ed57600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691821790555f90815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b6003545f90610b3990600190614078565b905090565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600a602090815260408083203380855292528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610c0c5783811015610bff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e73756666696369656e7420616c6c6f77616e636500000000000000000000604482015260640161091d565b610c0c86838684036119e1565b610c17868686611acf565b50600195945050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600c60205260409020546060908015610ceb5760038181548110610c6457610c6461408b565b905f5260205f209060020201600101805480602002602001604051908101604052809291908181526020015f905b82821015610cdf578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505081526020019060010190610c92565b50505050915050919050565b50919050565b5f805f80600f545f14610d0d57610d0742611ff1565b90925090505b73ffffffffffffffffffffffffffffffffffffffff86165f908152600c602052604081205490610d3d8288612117565b9050610d4d816040015142612235565b610d5990612710614078565b94508215610d91576020810151815164e8d4a5100090610d7a9086906140b8565b610d8491906140fc565b610d8e9190614078565b95505b505050509250929050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906108ad9082908690610de290879061410f565b6119e1565b335f908152600b602052604081208054839290610e05908490614078565b90915550506103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290610e4790849061410f565b90915550506040518181526103699033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350565b610e9061228f565b610e9861230f565b565b610ea261228f565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600860205260408120549003610f2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742072656769737465726564210000000000000000000000000000000000604482015260640161091d565b60025473ffffffffffffffffffffffffffffffffffffffff82165f9081526008602052604090205410610fbe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c696420706169722100000000000000000000000000000000000000604482015260640161091d565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260086020526040902054600254610ff290600190614078565b8110156110df576002805461100990600190614078565b815481106110195761101961408b565b5f918252602090912001546002805473ffffffffffffffffffffffffffffffffffffffff90921691839081106110515761105161408b565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060085f600284815481106110ad576110ad61408b565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020555b60028054806110f0576110f0614122565b5f828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff9390931681526008909252506040812055565b61117b61228f565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156111e5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611209919061414f565b905080821115611275576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365206c6f77000000000000000000000000000000000000000000604482015260640161091d565b8273ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6112af5f5473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303815f875af115801561131e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113429190614166565b50505050565b5f805b60035481101561139757600381815481106113685761136861408b565b5f918252602090912060016002909202010154611385908361410f565b915061139081614181565b905061134b565b5090565b6113a3611a4e565b610e985f6123a8565b6060600e805461081f90614000565b6113c361241e565b6113cb6124a3565b6113d6838383612543565b505050565b335f818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015611478576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4465637265617365732062656c6f772030000000000000000000000000000000604482015260640161091d565b61148582868684036119e1565b506001949350505050565b5f336108ad818585611acf565b600381815481106114ac575f80fd5b5f91825260209091206002909102015473ffffffffffffffffffffffffffffffffffffffff16905081565b6114df61241e565b805f03611548576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f43616e6e6f74207374616b65205a65726f000000000000000000000000000000604482015260640161091d565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260086020526040812054908190036115d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091d565b6113d68383612b4c565b6115e961228f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526006602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527f6967fd9beca531ca64fc6f897b579e9ea3e2e937cf55341df2151665ba43d5ef91015b60405180910390a15050565b61167f61228f565b610e98612d7d565b61168f61228f565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526009602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527feb0184c59a430a1717ee5868decd2a492123fadbdb07af787cb52a263a0650b8910161166b565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600c6020526040812054816117458285612117565b9050611755816040015142612235565b95945050505050565b61176661228f565b5f805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f80f15e9dbc60884fdb59fb8ed4fc48a9a689e028f055e893ed45ca5be67c5c8591a35f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6117f9611a4e565b73ffffffffffffffffffffffffffffffffffffffff811661189c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161091d565b6118a5816123a8565b50565b6118b061228f565b73ffffffffffffffffffffffffffffffffffffffff81165f908152600860205260409020541561193c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920726567697374657265642100000000000000000000000000604482015260640161091d565b60028054600180820183555f8390527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851617905590546119b99190614078565b73ffffffffffffffffffffffffffffffffffffffff9091165f90815260086020526040902055565b73ffffffffffffffffffffffffffffffffffffffff8381165f818152600a602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161091d565b611ad761241e565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054811115611b65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f42616c616e6365204c6f77000000000000000000000000000000000000000000604482015260640161091d565b60055474010000000000000000000000000000000000000000900460ff1615611c0057601054611b959042614078565b611ba99069152d02c7e14af68000006140b8565b611bbf906b033b2e3c9fd0803ce800000061410f565b60128190556b204fce5e3e250261100000001015611c0057600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690555b611c0a8383612dd4565b15611caa5760125473ffffffffffffffffffffffffffffffffffffffff83165f908152600b6020526040902054611c4290839061410f565b1115611caa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5768616c65204e6f7420416c6c6f776564000000000000000000000000000000604482015260640161091d565b611cb383612e7a565b611cbc82612e7a565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460019060ff1680611d16575073ffffffffffffffffffffffffffffffffffffffff83165f9081526009602052604090205460ff165b15611d1e57505f5b73ffffffffffffffffffffffffffffffffffffffff84165f9081526007602052604090205460ff16158015611d78575073ffffffffffffffffffffffffffffffffffffffff83165f9081526007602052604090205460ff16155b15611d8057505f5b8015611f10575f80611d9184612f86565b73ffffffffffffffffffffffffffffffffffffffff88165f908152600b6020526040812080549395509193508692611dca908490614078565b909155505073ffffffffffffffffffffffffffffffffffffffff85165f908152600b602052604081208054839290611e0390849061410f565b925050819055508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611e6991815260200190565b60405180910390a38115611f09576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054849290611eb490849061410f565b90915550506040518281526103699073ffffffffffffffffffffffffffffffffffffffff8816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b5050611342565b73ffffffffffffffffffffffffffffffffffffffff84165f908152600b602052604081208054849290611f44908490614078565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f908152600b602052604081208054849290611f7d90849061410f565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611fe391815260200190565b60405180910390a350505050565b5f80600f545f0361205e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e666c6174696f6e206e6f7420737461727465642100000000000000000000604482015260640161091d565b5f600f548461206d9190614078565b9050801561210b575f61208c6b033b2e3c814887e4de24000083612fb3565b90506b033b2e3c9fd0803ce80000006bffffffffffffffffffffffff16816013546120b791906140b8565b6120c191906140fc565b6013546120ce9190614078565b93506014545f14612105576014546120eb64e8d4a51000866140b8565b6120f591906140fc565b601154612102919061410f565b92505b50612111565b60115491505b50915091565b61213860405180606001604052805f81526020015f81526020015f81525090565b6003838154811061214b5761214b61408b565b905f5260205f2090600202016001018054905082106121c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5374616b6520696e64657820696e636f72726563742100000000000000000000604482015260640161091d565b600383815481106121d9576121d961408b565b905f5260205f20906002020160010182815481106121f9576121f961408b565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050905092915050565b5f81612245846301dfe20061410f565b11156108b3575f6224ea0061225a8585614078565b61226491906140fc565b9050600d8110156122885761227a81600d614078565b6122859060646140b8565b91505b5092915050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d3a43616c6c6572206e6f74206d616e61676572000000000000000000000000604482015260640161091d565b61231761241e565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861237e3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60015474010000000000000000000000000000000000000000900460ff1615610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161091d565b600f5442908111156118a5575f806124ba83611ff1565b91509150815f146113d65782600f819055508160135f8282546124dd9190614078565b9091555050305f908152600b60205260408120805484929061250090849061410f565b909155505060405182815230905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36011555050565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600860205260408120548082036125d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f496e76616c6964204c5020706169720000000000000000000000000000000000604482015260640161091d565b5f6125dc848661302a565b90505f61271090505f826020015164e8d4a51000601154855f015161260191906140b8565b61260b91906140fc565b6126159190614078565b335f90815260096020526040902054909150889060ff16156126df5761265273ffffffffffffffffffffffffffffffffffffffff8216338a61353b565b6001955081156126da57305f908152600b60205260408120805484929061267a908490614078565b9091555050335f908152600b60205260408120805484929061269d90849061410f565b9091555050604051828152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b612a74565b5f6127106126ee60198b6140b8565b6126f891906140fc565b90505f81612706818c614078565b6127109190614078565b90505f6127106127216019876140b8565b61272b91906140fc565b90505f816127398188614078565b6127439190614078565b9050612753886040015142612235565b61275d9088614078565b96505f61271061276d89866140b8565b61277791906140fc565b905061279a73ffffffffffffffffffffffffffffffffffffffff8716338361353b565b6004546127c19073ffffffffffffffffffffffffffffffffffffffff88811691168761353b565b6005546127e89073ffffffffffffffffffffffffffffffffffffffff88811691168761353b565b60019a505f6127f78286614078565b90508015612826576004546128269073ffffffffffffffffffffffffffffffffffffffff89811691168361353b565b5f6127106128348b866140b8565b61283e91906140fc565b905080156129dc57305f908152600b6020526040812080548b9290612864908490614078565b9091555050335f908152600b60205260408120805483929061288790849061410f565b909155505060045473ffffffffffffffffffffffffffffffffffffffff165f908152600b6020526040812080548792906128c290849061410f565b909155505060055473ffffffffffffffffffffffffffffffffffffffff165f908152600b6020526040812080548792906128fd90849061410f565b9091555050604051818152339030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360045460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a360055460405186815273ffffffffffffffffffffffffffffffffffffffff9091169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b5f6129e78286614078565b90508015612a6b576103695f908152600b6020527fd449456666b62074477eaada1585caa6c0a54044c1284df25f4150e8ac9ad1958054839290612a2c90849061410f565b90915550506040518181526103699030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35b50505050505050505b8760145f828254612a859190614078565b909155505060208481015160408087015181518c81529384019290925282015242606082015233907fdcfd2b4017d03f7e541021db793b2f9b31e4acdee005f789e52853c390e3e9629060800160405180910390a285612b41576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f556e7374616b65206661696c6564000000000000000000000000000000000000604482015260640161091d565b505050505050505050565b612b546124a3565b335f90815260096020526040812054819060ff1615612b74575081612ba6565b612710612b826019856140b8565b612b8c91906140fc565b915081612b998185614078565b612ba39190614078565b90505b83612bc973ffffffffffffffffffffffffffffffffffffffff821633308561360f565b8215612c2157600454612bf89073ffffffffffffffffffffffffffffffffffffffff838116913391168661360f565b600554612c219073ffffffffffffffffffffffffffffffffffffffff838116913391168661360f565b335f908152600c602052604081205490819003612c4457612c413361366d565b90505b5f64e8d4a5100084601154612c5991906140b8565b612c6391906140fc565b905060038281548110612c7857612c7861408b565b5f91825260208083206040805160608101825289815280840187815242928201928352600160029687029094018401805480860182559088529487209151600390950290910193845551918301919091555191015560148054869290612cdf90849061410f565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167f9cfd25589d1eb8ad71e342a86a8524e83522e3936c0803048c08f6d9ad974f40600160038581548110612d3357612d3361408b565b905f5260205f20906002020160010180549050612d509190614078565b6040805191825260208201889052810184905242606082015260800160405180910390a250505050505050565b612d85613706565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa3361237e565b6005545f9074010000000000000000000000000000000000000000900460ff168015612e1b575060015473ffffffffffffffffffffffffffffffffffffffff848116911614155b8015612e42575060015473ffffffffffffffffffffffffffffffffffffffff838116911614155b8015612e73575073ffffffffffffffffffffffffffffffffffffffff82165f9081526006602052604090205460ff16155b9392505050565b8073ffffffffffffffffffffffffffffffffffffffff163b5f03612e9b5750565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604090205460ff166118a5575f612ed18261378a565b905073ffffffffffffffffffffffffffffffffffffffff8116612ef2575050565b5f612efc836137b5565b905073ffffffffffffffffffffffffffffffffffffffff8116612f1e57505050565b505073ffffffffffffffffffffffffffffffffffffffff165f908152600760209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0091821681179092556006909352922080549091169091179055565b5f80612710612f966014856140b8565b612fa091906140fc565b9150612fac8284614078565b9050915091565b5f612fbf6002836141b8565b5f03612fd7576b033b2e3c9fd0803ce8000000612fd9565b825b9050612fe66002836140fc565b91505b81156108b357612ff983846137e0565b92506130066002836141b8565b156130185761301581846137e0565b90505b6130236002836140fc565b9150612fe9565b61304b60405180606001604052805f81526020015f81526020015f81525090565b335f908152600c60205260409020546130648185612117565b915082825f015110156130d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f556e7374616b696e6720746f6f206d7563680000000000000000000000000000604482015260640161091d565b81518390036134b4576001600382815481106130f1576130f161408b565b905f5260205f2090600202016001018054905061310e9190614078565b8410156131e057600381815481106131285761312861408b565b905f5260205f20906002020160010160016003838154811061314c5761314c61408b565b905f5260205f209060020201600101805490506131699190614078565b815481106131795761317961408b565b905f5260205f209060030201600382815481106131985761319861408b565b905f5260205f20906002020160010185815481106131b8576131b861408b565b5f91825260209091208254600390920201908155600180830154908201556002918201549101555b600381815481106131f3576131f361408b565b905f5260205f20906002020160010180548061321157613211614122565b5f8281526020812060037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909301838102909101828155600181018390556002019190915590915580548290811061326b5761326b61408b565b5f918252602082206001600290920201015490036134af5760035461329290600190614078565b81101561342457600380546132a990600190614078565b815481106132b9576132b961408b565b905f5260205f209060020201600382815481106132d8576132d861408b565b5f9182526020909120825460029092020180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911781556001808301805461333f9284019190613d3c565b50905050600380548061335457613354614122565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168155906133ba6001830182613d9e565b50509055335f908152600c6020819052604082208290556003805484939190849081106133e9576133e961408b565b5f918252602080832060029092029091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902055612288565b600380548061343557613435614122565b5f8281526020812060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019283020180547fffffffffffffffffffffffff00000000000000000000000000000000000000001681559061349b6001830182613d9e565b50509055335f908152600c60205260408120555b612288565b5f600382815481106134c8576134c861408b565b905f5260205f20906002020160010185815481106134e8576134e861408b565b5f9182526020822085516003909202019250613505908690614078565b80835560115490915064e8d4a51000906135209083906140b8565b61352a91906140fc565b826001018190555050505092915050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526113d69084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613817565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526113429085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161358d565b6003805460019081018083555f928352829161368891614078565b9050826003828154811061369e5761369e61408b565b5f918252602080832060029290920290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055949091168152600c90935260409092208290555090565b60015474010000000000000000000000000000000000000000900460ff16610e98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161091d565b5f6108b3827f0dfe168100000000000000000000000000000000000000000000000000000000613924565b5f6108b3827fd21220a700000000000000000000000000000000000000000000000000000000613924565b5f6b033b2e3c9fd0803ce800000061380d6137fb8585613a33565b6b019d971e4fe8401e74000000613abc565b612e7391906140fc565b5f613878826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16613b339092919063ffffffff16565b905080515f14806138985750808060200190518101906138989190614166565b6113d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161091d565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000851617905290515f918291829173ffffffffffffffffffffffffffffffffffffffff8716916139a691906141cb565b5f60405180830381855afa9150503d805f81146139de576040519150601f19603f3d011682016040523d82523d5f602084013e6139e3565b606091505b50915091508115806139f457508051155b15613a03575f925050506108b3565b8051602003613a295780806020019051810190613a2091906141e6565b925050506108b3565b505f949350505050565b5f811580613a5657508282613a4881836140b8565b9250613a5490836140fc565b145b6108b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6d756c2d6f766572666c6f77000000000000000000000000604482015260640161091d565b5f82613ac8838261410f565b91508110156108b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f64732d6d6174682d6164642d6f766572666c6f77000000000000000000000000604482015260640161091d565b6060613b4184845f85613b49565b949350505050565b606082471015613bdb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161091d565b5f808673ffffffffffffffffffffffffffffffffffffffff168587604051613c0391906141cb565b5f6040518083038185875af1925050503d805f8114613c3d576040519150601f19603f3d011682016040523d82523d5f602084013e613c42565b606091505b5091509150613c5387838387613c5e565b979650505050505050565b60608315613cf35782515f03613cec5773ffffffffffffffffffffffffffffffffffffffff85163b613cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161091d565b5081613b41565b613b418383815115613d085781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091d9190613e12565b828054828255905f5260205f20906003028101928215613d92575f5260205f209160030282015b82811115613d925782548255600180840154908301556002808401549083015560039283019290910190613d63565b50611397929150613db8565b5080545f8255600302905f5260205f20908101906118a591905b5b80821115611397575f808255600182018190556002820155600301613db9565b5f60208284031215613de9575f80fd5b5035919050565b5f5b83811015613e0a578181015183820152602001613df2565b50505f910152565b602081525f8251806020840152613e30816040850160208701613df0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b73ffffffffffffffffffffffffffffffffffffffff811681146118a5575f80fd5b5f8060408385031215613e94575f80fd5b8235613e9f81613e62565b946020939093013593505050565b5f8060408385031215613ebe575f80fd5b8235613ec981613e62565b91506020830135613ed981613e62565b809150509250929050565b5f805f60608486031215613ef6575f80fd5b8335613f0181613e62565b92506020840135613f1181613e62565b929592945050506040919091013590565b5f60208284031215613f32575f80fd5b8135612e7381613e62565b602080825282518282018190525f919060409081850190868401855b82811015613f885781518051855286810151878601528501518585015260609093019290850190600101613f59565b5091979650505050505050565b5f805f60608486031215613fa7575f80fd5b8335613fb281613e62565b95602085013595506040909401359392505050565b80151581146118a5575f80fd5b5f8060408385031215613fe5575f80fd5b8235613ff081613e62565b91506020830135613ed981613fc7565b600181811c9082168061401457607f821691505b602082108103610ceb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108b3576108b361404b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b80820281158282048414176108b3576108b361404b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261410a5761410a6140cf565b500490565b808201808211156108b3576108b361404b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f6020828403121561415f575f80fd5b5051919050565b5f60208284031215614176575f80fd5b8151612e7381613fc7565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141b1576141b161404b565b5060010190565b5f826141c6576141c66140cf565b500690565b5f82516141dc818460208701613df0565b9190910192915050565b5f602082840312156141f6575f80fd5b8151612e7381613e6256fea2646970667358221220ac2148ef9cede5ba11e1b93957a6cb39f717d37a02b7b7b080ab690a5fdca15064736f6c63430008140033