ETH Price: $2,543.65 (+2.35%)

Token

Shezmu Guardian ()
 

Overview

Max Total Supply

0

Holders

0

Total Transfers

-

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Guardian

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 38 : Guardian.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import {Address} from '@openzeppelin/contracts/utils/Address.sol';
import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import {ERC1155} from '@openzeppelin/contracts/token/ERC1155/ERC1155.sol';
import {ERC1155PausableUpgradeable} from '@openzeppelin/contracts-upgradeable/token/ERC1155/extensions/ERC1155PausableUpgradeable.sol';
import {OwnableUpgradeable} from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import {Strings} from '@openzeppelin/contracts/utils/Strings.sol';

import {IAddressProvider} from '../interfaces/IAddressProvider.sol';
import {IRewardRecipient} from '../interfaces/IRewardRecipient.sol';
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
import {IERC20MintableBurnable} from '../interfaces/IERC20MintableBurnable.sol';
import {IPriceOracleAggregator} from '../interfaces/IPriceOracleAggregator.sol';
import {IObelisk} from '../interfaces/IObelisk.sol';
import '../interfaces/IZap.sol';

error INVALID_ADDRESS();
error INVALID_AMOUNT();
error INVALID_PARAM();
error INVALID_FEE_TOKEN();
error ONLY_BOND();
error ONLY_OBELISK();
error NOT_WHITELISTED();

contract Guardian is
    ERC1155PausableUpgradeable,
    OwnableUpgradeable,
    IRewardRecipient
{
    using SafeERC20 for IERC20;
    using EnumerableSet for EnumerableSet.AddressSet;
    using Strings for uint256;

    /* ======== STORAGE ======== */
    struct RewardRate {
        uint256 rewardPerSec;
        uint256 numberOfGuardians;
    }

    struct RewardInfo {
        uint256 debt;
        uint256 pending;
    }

    /// @dev BASE URI
    string private constant BASE_URI = 'https://metadata.shezmu.io/guardian/';

    /// @notice name
    string public constant name = 'Shezmu Guardian';

    /// @notice percent multiplier (100%)
    uint256 public constant PRECISION = 10000;

    /// @notice SHEZMU
    IERC20MintableBurnable public constant SHEZMU =
        IERC20MintableBurnable(0x5fE72ed557d8a02FFf49B3B826792c765d5cE162);

    /// @notice Fee Token (USDC)
    IERC20 public constant USDC =
        IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);

    /// @notice Uniswap Router
    IUniswapV2Router02 public constant ROUTER =
        IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

    /// @notice price per guardian
    uint256 public pricePerGuardian;

    /// @notice treasury wallet
    address public treasury;

    /// @notice txn fee (price)
    uint256 public txnFee;

    /// @notice claim fee (percentage)
    uint256 public claimFee;

    /// @notice mint limit in one txn
    uint256 public mintLimit;

    /// @notice mapping account => total balance
    mapping(address => uint256) public totalBalanceOf;

    /// @notice total supply
    uint256 public totalSupply;

    /// @notice reward rate
    RewardRate public rewardRate;

    /// @dev feeToken tokens (stable coin for txn fee payment)
    EnumerableSet.AddressSet private feeTokens;

    /// @dev TYPE
    uint8 private constant TYPE = 6;

    /// @dev SIZE for each TYPE
    uint8[6] private SIZES;

    /// @dev reward accTokenPerShare
    uint256 private accTokenPerShare;

    /// @dev reward lastUpdate
    uint256 private lastUpdate;

    /// @dev mapping account => reward info
    mapping(address => RewardInfo) private rewardInfoOf;

    /// @dev USDC dividendsPerShare
    uint256 private dividendsPerShare;

    /// @dev mapping account => dividends info
    mapping(address => RewardInfo) private dividendsInfoOf;

    /// @dev dividends multiplier
    uint256 private constant MULTIPLIER = 1e18;

    /// @notice address provider
    IAddressProvider public addressProvider;

    /// @notice tributeFee for Shezmu (percentage)
    uint256 public tributeFeeForShezmu;

    /// @notice tributeFee for ETH (percentage)
    uint256 public tributeFeeForETH;

    address public lpFeeReceiver;
    IZap public zap;

    mapping(address => bool) public isWhitelisted;

    /* ======== EVENTS ======== */

    event MintLimit(uint256 limit);
    event Treasury(address treasury);
    event SetFee(
        uint256 txnFee,
        uint256 claimFee,
        uint256 tributeFeeForShezmu,
        uint256 tributeFeeForETH
    );
    event AddFeeTokens(address[] tokens);
    event RemoveFeeTokens(address[] tokens);
    event Mint(address indexed from, address indexed to, uint256 amount);
    event Compound(address indexed from, address indexed to, uint256 amount);
    event Split(address indexed from, address indexed to, uint256 amount);
    event Claim(address indexed from, uint256 reward, uint256 dividends);
    event Bond(address indexed to, uint256 amount);

    /* ======== INITIALIZATION ======== */

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    function initialize(address treasury_) external initializer {
        if (treasury_ == address(0)) revert INVALID_ADDRESS();
        treasury = treasury_;

        // 1 Guardian: Craftsman
        // 5 Guardian: Scribe
        // 10 Guardian: High Priest
        // 25 Guardian: Nobles
        // 50 Guardians: Viziers
        // 100 Guardian: Pharaoh
        SIZES = [1, 5, 10, 25, 50, 100];

        // 12 Shezmu per Guardian
        pricePerGuardian = 12 ether;

        // txn fee $15
        txnFee = 15 ether;
        feeTokens.add(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); // USDC
        feeTokens.add(0xdAC17F958D2ee523a2206206994597C13D831ec7); // USDT
        feeTokens.add(0x6B175474E89094C44Da98b954EedeAC495271d0F); // DAI

        // claim fee 20%
        claimFee = 2000;

        // option how many can mint in one txn
        mintLimit = 100;

        // 0.1 Shezmu per day for first 250,000 guardians
        rewardRate.rewardPerSec = uint256(0.1 ether) / uint256(1 days);
        rewardRate.numberOfGuardians = 250000;

        // init
        __ERC1155Pausable_init();
        __ERC1155_init(BASE_URI);
        __Ownable_init();
    }

    /* ======== MODIFIERS ======== */

    modifier onlyBond() {
        if (msg.sender != _bond()) revert ONLY_BOND();
        _;
    }

    modifier onlyObelisk() {
        if (msg.sender != _obelisk()) revert ONLY_OBELISK();
        _;
    }

    modifier update() {
        if (totalSupply > 0) {
            accTokenPerShare +=
                rewardRate.rewardPerSec *
                (block.timestamp - lastUpdate);
        }
        lastUpdate = block.timestamp;

        _;
    }

    /* ======== POLICY FUNCTIONS ======== */

    function setAddressProvider(address _addressProvider) external onlyOwner {
        if (_addressProvider == address(0)) revert INVALID_ADDRESS();
        addressProvider = IAddressProvider(_addressProvider);
    }

    function setMintLimit(uint256 limit) external onlyOwner {
        if (limit == 0) revert INVALID_AMOUNT();

        mintLimit = limit;

        emit MintLimit(limit);
    }

    function setTreasury(address treasury_) external onlyOwner {
        if (treasury_ == address(0)) revert INVALID_ADDRESS();

        treasury = treasury_;

        emit Treasury(treasury_);
    }

    function setFee(
        uint256 _txnFee,
        uint256 _claimFee,
        uint256 _feeForShezmu,
        uint256 _feeForETH
    ) external onlyOwner {
        txnFee = _txnFee;
        claimFee = _claimFee;
        tributeFeeForShezmu = _feeForShezmu;
        tributeFeeForETH = _feeForETH;

        emit SetFee(_txnFee, _claimFee, _feeForShezmu, _feeForETH);
    }

    function setZap(address zap_) external onlyOwner {
        zap = IZap(zap_);
    }

    function setLpFeeReceiver(address receiver) external onlyOwner {
        lpFeeReceiver = receiver;
    }

    function setPricePerGuardian(uint price) external onlyOwner {
        pricePerGuardian = price;
    }

    function setWhitelist(address vault, bool whitelist) external onlyOwner {
        isWhitelisted[vault] = whitelist;
    }

    function setRewardRate(
        RewardRate memory _rewardRate
    ) external onlyOwner update {
        rewardRate = _rewardRate;
    }

    function addFeeTokens(address[] calldata tokens) external onlyOwner {
        uint256 length = tokens.length;

        for (uint256 i = 0; i < length; ) {
            feeTokens.add(tokens[i]);
            unchecked {
                ++i;
            }
        }

        emit AddFeeTokens(tokens);
    }

    function removeFeeTokens(address[] calldata tokens) external onlyOwner {
        uint256 length = tokens.length;

        for (uint256 i = 0; i < length; ) {
            feeTokens.remove(tokens[i]);
            unchecked {
                ++i;
            }
        }

        emit RemoveFeeTokens(tokens);
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    function recoverERC20(IERC20 token) external onlyOwner {
        token.safeTransfer(_msgSender(), token.balanceOf(address(this)));
    }

    function airdrop(
        address[] calldata tos,
        uint256[] calldata amounts
    ) external onlyOwner update {
        uint256 length = tos.length;
        if (length != amounts.length) revert INVALID_PARAM();

        for (uint256 i = 0; i < length; ) {
            _simpleMint(tos[i], amounts[i]);

            unchecked {
                ++i;
            }
        }
    }

    /* ======== INTERNAL FUNCTIONS ======== */

    function _shezmu() internal view returns (address) {
        return addressProvider.getShezmu();
    }

    function _bond() internal view returns (address) {
        return addressProvider.getBond();
    }

    function _obelisk() internal view returns (address) {
        return addressProvider.getObelisk();
    }

    function _treasury() internal view returns (address) {
        return addressProvider.getTreasury();
    }

    function _viewPriceInUSD(address token) internal view returns (uint256) {
        return
            IPriceOracleAggregator(addressProvider.getPriceOracleAggregator())
                .viewPriceInUSD(token);
    }

    function _getMultiplierOf(
        address account
    ) internal view returns (uint256, uint256) {
        return IObelisk(addressProvider.getObelisk()).getMultiplierOf(account);
    }

    function _min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    function _sync(address account) internal {
        uint256 totalBalance = totalBalanceOf[account];

        unchecked {
            for (uint256 i = 0; i < TYPE; i++) {
                uint256 index = TYPE - i - 1;
                uint256 newBalance = totalBalance / SIZES[index];
                uint256 oldBalance = balanceOf(account, index);

                if (newBalance > oldBalance) {
                    super._mint(account, index, newBalance - oldBalance, '');
                } else if (newBalance < oldBalance) {
                    super._burn(account, index, oldBalance - newBalance);
                }

                totalBalance = totalBalance % SIZES[index];
            }
        }
    }

    function _updateReward(
        address account
    )
        internal
        returns (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        )
    {
        uint256 totalBalance = totalBalanceOf[account];

        // Shezmu
        rewardInfo = rewardInfoOf[account];
        (uint256 multiplier, uint256 precision) = _getMultiplierOf(account);
        uint256 reward = ((accTokenPerShare * totalBalance - rewardInfo.debt) *
            (precision + multiplier)) / precision;
        uint256 fee = (reward * claimFee) / PRECISION;
        rewardInfo.pending += reward - fee;
        if (fee > 0) {
            SHEZMU.mint(treasury, fee);
        }

        // USDC
        dividendsInfo = dividendsInfoOf[account];
        dividendsInfo.pending +=
            (dividendsPerShare * totalBalance) /
            MULTIPLIER -
            dividendsInfo.debt;
    }

    function _mint(address to, address feeToken, uint256 amount) internal {
        if (to == address(0)) revert INVALID_ADDRESS();
        if (amount == 0 || amount > mintLimit) revert INVALID_AMOUNT();
        if (!feeTokens.contains(feeToken)) revert INVALID_FEE_TOKEN();

        // pay txn fee
        RewardInfo storage dividendsInfo = dividendsInfoOf[to];
        uint256 usdcFee = (txnFee *
            10 ** IERC20Metadata(address(USDC)).decimals()) / MULTIPLIER;

        if (dividendsInfo.pending >= usdcFee) {
            dividendsInfo.pending -= usdcFee;

            USDC.approve(address(zap), usdcFee);
            zap.zapInToken(address(USDC), usdcFee, lpFeeReceiver);
        } else {
            uint fee = (txnFee * 10 ** IERC20Metadata(feeToken).decimals()) /
                MULTIPLIER;
            IERC20(feeToken).safeTransferFrom(_msgSender(), address(this), fee);
            IERC20(feeToken).approve(address(zap), fee);
            zap.zapInToken(feeToken, fee, lpFeeReceiver);
        }

        _simpleMint(to, amount);
    }

    function _simpleMint(address to, uint256 amount) internal {
        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(to);

        // mint Guardian
        unchecked {
            totalBalanceOf[to] += amount;
            totalSupply += amount;
        }

        // update reward rate if exceeds the Guardians number
        if (totalSupply > rewardRate.numberOfGuardians) {
            rewardRate.rewardPerSec /= 2;
            rewardRate.numberOfGuardians *= 2;
        }

        // update reward debt
        rewardInfo.debt = accTokenPerShare * totalBalanceOf[to];
        dividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[to]) /
            MULTIPLIER;

        // sync Guardians
        _sync(to);
    }

    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual override update {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);

        if (Address.isContract(operator)) {
            if (!isWhitelisted[operator]) {
                revert NOT_WHITELISTED();
            }
        } else {
            if (Address.isContract(to) && !isWhitelisted[to]) {
                revert NOT_WHITELISTED();
            }
        }

        if (from == address(0) || to == address(0)) {
            return;
        }

        // update reward
        (
            RewardInfo storage fromRewardInfo,
            RewardInfo storage fromDividendsInfo
        ) = _updateReward(from);
        (
            RewardInfo storage toRewardInfo,
            RewardInfo storage toDividendsInfo
        ) = _updateReward(to);

        // calculate number of Guardians
        uint256 amount;
        unchecked {
            for (uint256 i = 0; i < ids.length; ++i) {
                amount += SIZES[ids[i]] * amounts[i];
            }
        }

        // update total balance
        unchecked {
            totalBalanceOf[from] -= amount;
            totalBalanceOf[to] += amount;
        }

        // update reward debt
        fromRewardInfo.debt = accTokenPerShare * totalBalanceOf[from];
        fromDividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[from]) /
            MULTIPLIER;
        toRewardInfo.debt = accTokenPerShare * totalBalanceOf[to];
        toDividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[to]) /
            MULTIPLIER;
    }

    /* ======== PUBLIC FUNCTIONS ======== */

    function mint(
        address to,
        address feeToken,
        uint256 amount
    ) external update {
        address account = _msgSender();

        // burn Shezmu
        SHEZMU.burnFrom(account, amount * pricePerGuardian);

        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(account);
        rewardInfo.debt = accTokenPerShare * totalBalanceOf[account];
        dividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[account]) /
            MULTIPLIER;

        // mint Guardian
        _mint(to, feeToken, amount);

        emit Mint(account, to, amount);
    }

    function compound(
        address to,
        address feeToken,
        uint256 amount
    ) external update {
        address account = _msgSender();

        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(account);
        rewardInfo.debt = accTokenPerShare * totalBalanceOf[account];
        dividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[account]) /
            MULTIPLIER;

        // burn Shezmu out of rewards
        if (amount > 0) {
            if (rewardInfo.pending < amount * pricePerGuardian)
                revert INVALID_AMOUNT();
            unchecked {
                rewardInfo.pending -= amount * pricePerGuardian;
            }
        } else {
            amount = rewardInfo.pending / pricePerGuardian;
            rewardInfo.pending %= pricePerGuardian;
        }

        // mint Guardian
        _mint(to, feeToken, amount);

        emit Compound(account, to, amount);
    }

    function split(address to, uint256 amount) external update {
        if (to == address(0)) revert INVALID_ADDRESS();
        address from = _msgSender();
        if (totalBalanceOf[from] < amount) revert INVALID_AMOUNT();

        // from
        {
            // update reward
            (
                RewardInfo storage rewardInfo,
                RewardInfo storage dividendsInfo
            ) = _updateReward(from);

            unchecked {
                totalBalanceOf[from] -= amount;
            }

            // update reward debt
            rewardInfo.debt = accTokenPerShare * totalBalanceOf[from];
            dividendsInfo.debt =
                (dividendsPerShare * totalBalanceOf[from]) /
                MULTIPLIER;

            // sync Guardians
            _sync(from);
        }

        // to
        {
            // update reward
            (
                RewardInfo storage rewardInfo,
                RewardInfo storage dividendsInfo
            ) = _updateReward(to);

            unchecked {
                totalBalanceOf[to] += amount;
            }

            // update reward debt
            rewardInfo.debt = accTokenPerShare * totalBalanceOf[to];
            dividendsInfo.debt =
                (dividendsPerShare * totalBalanceOf[to]) /
                MULTIPLIER;

            // sync Guardians
            _sync(to);
        }

        emit Split(from, to, amount);
    }

    function claim() external payable update {
        address account = _msgSender();
        uint256 totalBalance = totalBalanceOf[account];

        if (totalBalance == 0) return;

        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(account);

        rewardInfo.debt = accTokenPerShare * totalBalance;
        dividendsInfo.debt = (dividendsPerShare * totalBalance) / MULTIPLIER;

        // tribute fee & claim percentage
        uint256 claimPercentage;

        if (msg.sender != _bond()) {
            uint256 shezmuPriceInUSD = _viewPriceInUSD(_shezmu());
            uint256 ethPriceInUSD = _viewPriceInUSD(ROUTER.WETH());
            uint256 ethAmountForFee = (rewardInfo.pending *
                tributeFeeForETH *
                shezmuPriceInUSD) / (ethPriceInUSD * PRECISION);

            if (ethAmountForFee == 0 || ethAmountForFee <= msg.value) {
                claimPercentage = PRECISION;
            } else {
                claimPercentage = (msg.value * PRECISION) / ethAmountForFee;

                if (claimPercentage <= 2400) revert INVALID_AMOUNT();
            }
        } else {
            claimPercentage = PRECISION;
        }

        if (msg.value > 0) {
            (bool success, ) = payable(_treasury()).call{value: msg.value}('');
            require(success);
        }

        // transfer pending (Shezmu)
        uint256 reward = (rewardInfo.pending * claimPercentage) / PRECISION;
        if (reward > 0) {
            unchecked {
                rewardInfo.pending -= reward;
            }
            SHEZMU.mint(account, reward);
        }

        // transfer pending (USDC)
        uint256 dividends = _min(
            (dividendsInfo.pending * claimPercentage) / PRECISION,
            USDC.balanceOf(address(this))
        );
        if (dividends > 0) {
            unchecked {
                dividendsInfo.pending -= dividends;
            }
            USDC.safeTransfer(account, dividends);
        }

        emit Claim(account, reward, dividends);
    }

    function receiveReward() external payable override {
        if (msg.value == 0) return;

        address[] memory path = new address[](2);
        path[0] = ROUTER.WETH();
        path[1] = address(USDC);

        uint256 balanceBefore = USDC.balanceOf(address(this));
        ROUTER.swapExactETHForTokensSupportingFeeOnTransferTokens{
            value: msg.value
        }(0, path, address(this), block.timestamp);

        uint256 rewardAmount = USDC.balanceOf(address(this)) - balanceBefore;

        if (totalSupply > 0 && rewardAmount > 0) {
            dividendsPerShare += (rewardAmount * MULTIPLIER) / totalSupply;
        }
    }

    /* ======== BOND FUNCTIONS ======== */

    function bond(
        address account,
        address feeToken,
        uint256 amount
    ) external onlyBond update {
        if (account == address(0)) revert INVALID_ADDRESS();
        if (amount == 0 || amount > mintLimit) revert INVALID_AMOUNT();
        if (!feeTokens.contains(feeToken)) revert INVALID_FEE_TOKEN();

        // burn Shezmu from bond
        SHEZMU.burnFrom(_msgSender(), amount * pricePerGuardian);

        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(account);
        rewardInfo.debt = accTokenPerShare * totalBalanceOf[account];
        dividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[account]) /
            MULTIPLIER;

        // pay txn fee
        uint256 usdcFee = (txnFee *
            10 ** IERC20Metadata(address(USDC)).decimals()) / MULTIPLIER;

        if (dividendsInfo.pending >= usdcFee) {
            dividendsInfo.pending -= usdcFee;

            USDC.approve(address(zap), usdcFee);
            zap.zapInToken(address(USDC), usdcFee, lpFeeReceiver);
        } else {
            uint fee = (txnFee * 10 ** IERC20Metadata(feeToken).decimals()) /
                MULTIPLIER;
            IERC20(feeToken).safeTransferFrom(_msgSender(), address(this), fee);
            IERC20(feeToken).approve(address(zap), fee);
            zap.zapInToken(feeToken, fee, lpFeeReceiver);
        }

        // mint Guardian
        _simpleMint(_msgSender(), amount);

        emit Bond(account, amount);
    }

    function sellRewardForBond(
        address account,
        uint256 dividends
    ) external onlyBond update {
        if (account == address(0)) revert INVALID_ADDRESS();
        if (dividends == 0) revert INVALID_AMOUNT();

        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(account);
        rewardInfo.debt = accTokenPerShare * totalBalanceOf[account];
        dividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[account]) /
            MULTIPLIER;

        // usdc to treasury
        dividendsInfo.pending -= dividends;

        USDC.approve(address(zap), dividends);
        zap.zapInToken(address(USDC), dividends, lpFeeReceiver);
    }

    /* ======== OBELISK FUNCTIONS ======== */

    function updateRewardForObelisk(
        address account
    ) external onlyObelisk update {
        if (account == address(0)) revert INVALID_ADDRESS();

        // update reward
        (
            RewardInfo storage rewardInfo,
            RewardInfo storage dividendsInfo
        ) = _updateReward(account);
        rewardInfo.debt = accTokenPerShare * totalBalanceOf[account];
        dividendsInfo.debt =
            (dividendsPerShare * totalBalanceOf[account]) /
            MULTIPLIER;
    }

    /* ======== VIEW FUNCTIONS ======== */

    function uri(
        uint256 tokenId
    ) public view virtual override returns (string memory) {
        return
            tokenId < TYPE
                ? string(
                    abi.encodePacked(BASE_URI, tokenId.toString(), '.json')
                )
                : super.uri(tokenId);
    }

    function allFeeTokens() external view returns (address[] memory) {
        return feeTokens.values();
    }

    function pendingReward(
        address account
    )
        external
        view
        returns (
            uint256 reward,
            uint256 dividends,
            uint256 feeInUSD,
            uint256 shezmuAmountForFee,
            uint256 ethAmountForFee
        )
    {
        uint256 totalBalance = totalBalanceOf[account];

        if (totalBalance > 0) {
            // Shezmu reward
            {
                RewardInfo memory rewardInfo = rewardInfoOf[account];
                uint256 newAccTokenPerShare = accTokenPerShare +
                    rewardRate.rewardPerSec *
                    (block.timestamp - lastUpdate);
                (uint256 multiplier, uint256 precision) = _getMultiplierOf(
                    account
                );
                uint256 newReward = ((newAccTokenPerShare *
                    totalBalance -
                    rewardInfoOf[account].debt) * (precision + multiplier)) /
                    precision;
                reward =
                    rewardInfo.pending +
                    newReward -
                    (newReward * claimFee) /
                    PRECISION;
            }

            // USDC reward
            {
                RewardInfo memory dividendsInfo = dividendsInfoOf[account];
                dividends =
                    dividendsInfo.pending +
                    (dividendsPerShare * totalBalance) /
                    MULTIPLIER -
                    dividendsInfo.debt;
            }

            // Tribute Fee
            {
                uint256 shezmuPriceInUSD = _viewPriceInUSD(_shezmu());
                uint256 ethPriceInUSD = _viewPriceInUSD(ROUTER.WETH());

                feeInUSD =
                    (reward *
                        (tributeFeeForShezmu + tributeFeeForETH) *
                        shezmuPriceInUSD) /
                    PRECISION;
                shezmuAmountForFee = (reward * tributeFeeForShezmu) / PRECISION;
                ethAmountForFee =
                    (reward * tributeFeeForETH * shezmuPriceInUSD) /
                    (ethPriceInUSD * PRECISION);
            }
        }
    }

    function getTributeFee()
        external
        view
        returns (
            uint256 tributeFeeForShezmu_,
            uint256 tributeFeeForETH_,
            uint256 shezmuPriceInUSD,
            uint256 ethPriceInUSD
        )
    {
        tributeFeeForShezmu_ = tributeFeeForShezmu;
        tributeFeeForETH_ = tributeFeeForETH;
        shezmuPriceInUSD = _viewPriceInUSD(_shezmu());
        ethPriceInUSD = _viewPriceInUSD(ROUTER.WETH());
    }

    uint256[49] private __gap;
}

File 2 of 38 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

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

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

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

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

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

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 3 of 38 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 4 of 38 : PausableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

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

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

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

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

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

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

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

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

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

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 5 of 38 : ERC1155Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.0;

import "./IERC1155Upgradeable.sol";
import "./IERC1155ReceiverUpgradeable.sol";
import "./extensions/IERC1155MetadataURIUpgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../utils/introspection/ERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 *
 * _Available since v3.1._
 */
contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155Upgradeable, IERC1155MetadataURIUpgradeable {
    using AddressUpgradeable for address;

    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

    // Mapping from account to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    /**
     * @dev See {_setURI}.
     */
    function __ERC1155_init(string memory uri_) internal onlyInitializing {
        __ERC1155_init_unchained(uri_);
    }

    function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
        _setURI(uri_);
    }

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

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256) public view virtual override returns (string memory) {
        return _uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        require(account != address(0), "ERC1155: address zero is not a valid owner");
        return _balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) public view virtual override returns (uint256[] memory) {
        require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not token owner or approved"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not token owner or approved"
        );
        _safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

        emit TransferSingle(operator, from, to, id, amount);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
            _balances[id][to] += amount;
        }

        emit TransferBatch(operator, from, to, ids, amounts);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the amounts in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

    /**
     * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        _balances[id][to] += amount;
        emit TransferSingle(operator, address(0), to, id, amount);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; i++) {
            _balances[ids[i]][to] += amounts[i];
        }

        emit TransferBatch(operator, address(0), to, ids, amounts);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
    }

    /**
     * @dev Destroys `amount` tokens of token type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `amount` tokens of token type `id`.
     */
    function _burn(address from, uint256 id, uint256 amount) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }

        emit TransferSingle(operator, from, address(0), id, amount);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     */
    function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        for (uint256 i = 0; i < ids.length; i++) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
        }

        emit TransferBatch(operator, from, address(0), ids, amounts);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        require(owner != operator, "ERC1155: setting approval status for self");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `ids` and `amounts` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `id` and `amount` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155ReceiverUpgradeable(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                if (response != IERC1155ReceiverUpgradeable.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155ReceiverUpgradeable(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155ReceiverUpgradeable.onERC1155BatchReceived.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
        uint256[] memory array = new uint256[](1);
        array[0] = element;

        return array;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[47] private __gap;
}

File 6 of 38 : ERC1155PausableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC1155/extensions/ERC1155Pausable.sol)

pragma solidity ^0.8.0;

import "../ERC1155Upgradeable.sol";
import "../../../security/PausableUpgradeable.sol";
import "../../../proxy/utils/Initializable.sol";

/**
 * @dev ERC1155 token with pausable token transfers, minting and burning.
 *
 * Useful for scenarios such as preventing trades until the end of an evaluation
 * period, or having an emergency switch for freezing all token transfers in the
 * event of a large bug.
 *
 * IMPORTANT: This contract does not include public pause and unpause functions. In
 * addition to inheriting this contract, you must define both functions, invoking the
 * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
 * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
 * make the contract unpausable.
 *
 * _Available since v3.1._
 */
abstract contract ERC1155PausableUpgradeable is Initializable, ERC1155Upgradeable, PausableUpgradeable {
    function __ERC1155Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __ERC1155Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {ERC1155-_beforeTokenTransfer}.
     *
     * Requirements:
     *
     * - the contract must not be paused.
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual override {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);

        require(!paused(), "ERC1155Pausable: token transfer while paused");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 7 of 38 : IERC1155MetadataURIUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.0;

import "../IERC1155Upgradeable.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155MetadataURIUpgradeable is IERC1155Upgradeable {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

File 8 of 38 : IERC1155ReceiverUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155ReceiverUpgradeable is IERC165Upgradeable {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 9 of 38 : IERC1155Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165Upgradeable.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155Upgradeable is IERC165Upgradeable {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

File 11 of 38 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 12 of 38 : ERC165Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.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 ERC165Upgradeable is Initializable, IERC165Upgradeable {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165Upgradeable).interfaceId;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 13 of 38 : IERC165Upgradeable.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 IERC165Upgradeable {
    /**
     * @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);
}

File 14 of 38 : ERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.0;

import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 *
 * _Available since v3.1._
 */
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
    using Address for address;

    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

    // Mapping from account to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory uri_) {
        _setURI(uri_);
    }

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

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256) public view virtual override returns (string memory) {
        return _uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        require(account != address(0), "ERC1155: address zero is not a valid owner");
        return _balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] memory accounts,
        uint256[] memory ids
    ) public view virtual override returns (uint256[] memory) {
        require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not token owner or approved"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not token owner or approved"
        );
        _safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

        emit TransferSingle(operator, from, to, id, amount);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
            _balances[id][to] += amount;
        }

        emit TransferBatch(operator, from, to, ids, amounts);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the amounts in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

    /**
     * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        _balances[id][to] += amount;
        emit TransferSingle(operator, address(0), to, id, amount);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; i++) {
            _balances[ids[i]][to] += amounts[i];
        }

        emit TransferBatch(operator, address(0), to, ids, amounts);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
    }

    /**
     * @dev Destroys `amount` tokens of token type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `amount` tokens of token type `id`.
     */
    function _burn(address from, uint256 id, uint256 amount) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }

        emit TransferSingle(operator, from, address(0), id, amount);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     */
    function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        for (uint256 i = 0; i < ids.length; i++) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
        }

        emit TransferBatch(operator, from, address(0), ids, amounts);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
        require(owner != operator, "ERC1155: setting approval status for self");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `ids` and `amounts` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `id` and `amount` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
        uint256[] memory array = new uint256[](1);
        array[0] = element;

        return array;
    }
}

File 15 of 38 : IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.0;

import "../IERC1155.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

File 16 of 38 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 17 of 38 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 18 of 38 : 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);
}

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

pragma solidity ^0.8.0;

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

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

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

File 20 of 38 : 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);
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

File 24 of 38 : 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;
    }
}

File 25 of 38 : 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);
}

File 26 of 38 : 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, "Math: mulDiv overflow");

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

File 27 of 38 : 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);
        }
    }
}

File 28 of 38 : 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, "Strings: hex length insufficient");
        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));
    }
}

File 29 of 38 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 30 of 38 : IAddressProvider.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IAddressProvider {
    function getTreasury() external view returns (address);

    function getShezmu() external view returns (address);

    function getGuardian() external view returns (address);

    function getPriceOracleAggregator() external view returns (address);

    function getBond() external view returns (address);

    function getObelisk() external view returns (address);

    function getOptionShezmu() external view returns (address);

    function getFarming() external view returns (address);
}

File 31 of 38 : IERC20MintableBurnable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IERC20MintableBurnable {
    function mint(address to, uint256 amount) external;

    function burn(uint256 amount) external;

    function burnFrom(address account, uint256 amount) external;
}

File 32 of 38 : IObelisk.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IObelisk {
    function getMultiplierOf(
        address account
    ) external view returns (uint256 multiplier, uint256 precision);
}

File 33 of 38 : IOracle.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IOracle {
    function viewPriceInUSD() external view returns (uint256);
}

File 34 of 38 : IPriceOracleAggregator.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import {IOracle} from './IOracle.sol';

interface IPriceOracleAggregator {
    event UpdateOracle(address token, IOracle oracle);

    function updateOracleForAsset(address _asset, IOracle _oracle) external;

    function viewPriceInUSD(address _token) external view returns (uint256);
}

File 35 of 38 : IRewardRecipient.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IRewardRecipient {
    function receiveReward() external payable;
}

File 36 of 38 : IUniswapV2Router01.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);

    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);

    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    )
        external
        payable
        returns (uint amountToken, uint amountETH, uint liquidity);

    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);

    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountA, uint amountB);

    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint amountToken, uint amountETH);

    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapExactETHForTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable returns (uint[] memory amounts);

    function swapTokensForExactETH(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapExactTokensForETH(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);

    function swapETHForExactTokens(
        uint amountOut,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable returns (uint[] memory amounts);

    function quote(
        uint amountA,
        uint reserveA,
        uint reserveB
    ) external pure returns (uint amountB);

    function getAmountOut(
        uint amountIn,
        uint reserveIn,
        uint reserveOut
    ) external pure returns (uint amountOut);

    function getAmountIn(
        uint amountOut,
        uint reserveIn,
        uint reserveOut
    ) external pure returns (uint amountIn);

    function getAmountsOut(
        uint amountIn,
        address[] calldata path
    ) external view returns (uint[] memory amounts);

    function getAmountsIn(
        uint amountOut,
        address[] calldata path
    ) external view returns (uint[] memory amounts);
}

File 37 of 38 : IUniswapV2Router02.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

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

File 38 of 38 : IZap.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IZap {
    function zapInToken(
        address token,
        uint amount,
        address receiver
    )
        external
        returns (uint256 amountShezmu, uint256 amountETH, uint256 liquidity);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"INVALID_ADDRESS","type":"error"},{"inputs":[],"name":"INVALID_AMOUNT","type":"error"},{"inputs":[],"name":"INVALID_FEE_TOKEN","type":"error"},{"inputs":[],"name":"INVALID_PARAM","type":"error"},{"inputs":[],"name":"NOT_WHITELISTED","type":"error"},{"inputs":[],"name":"ONLY_BOND","type":"error"},{"inputs":[],"name":"ONLY_OBELISK","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"AddFeeTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Bond","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dividends","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Compound","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"MintLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"RemoveFeeTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"txnFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tributeFeeForShezmu","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tributeFeeForETH","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Split","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"Treasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTER","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHEZMU","outputs":[{"internalType":"contract IERC20MintableBurnable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"addFeeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"addressProvider","outputs":[{"internalType":"contract IAddressProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allFeeTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"bond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getTributeFee","outputs":[{"internalType":"uint256","name":"tributeFeeForShezmu_","type":"uint256"},{"internalType":"uint256","name":"tributeFeeForETH_","type":"uint256"},{"internalType":"uint256","name":"shezmuPriceInUSD","type":"uint256"},{"internalType":"uint256","name":"ethPriceInUSD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"treasury_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpFeeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"dividends","type":"uint256"},{"internalType":"uint256","name":"feeInUSD","type":"uint256"},{"internalType":"uint256","name":"shezmuAmountForFee","type":"uint256"},{"internalType":"uint256","name":"ethAmountForFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiveReward","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"removeFeeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"rewardPerSec","type":"uint256"},{"internalType":"uint256","name":"numberOfGuardians","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"dividends","type":"uint256"}],"name":"sellRewardForBond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addressProvider","type":"address"}],"name":"setAddressProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_txnFee","type":"uint256"},{"internalType":"uint256","name":"_claimFee","type":"uint256"},{"internalType":"uint256","name":"_feeForShezmu","type":"uint256"},{"internalType":"uint256","name":"_feeForETH","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"setLpFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setMintLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setPricePerGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rewardPerSec","type":"uint256"},{"internalType":"uint256","name":"numberOfGuardians","type":"uint256"}],"internalType":"struct Guardian.RewardRate","name":"_rewardRate","type":"tuple"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"treasury_","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"whitelist","type":"bool"}],"name":"setWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zap_","type":"address"}],"name":"setZap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"split","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tributeFeeForETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tributeFeeForShezmu","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"txnFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"updateRewardForObelisk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zap","outputs":[{"internalType":"contract IZap","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615f9680620000f36000396000f3fe6080604052600436106103805760003560e01c8063715018a6116101d1578063a2ea14ba11610102578063debfb961116100a0578063f2fde38b1161006f578063f2fde38b14610a9d578063f40f0f5214610abd578063f74948ab14610b05578063ff3d9e4f14610b3a57600080fd5b8063debfb961146109f4578063e985e9c514610a14578063f0f4426014610a5d578063f242432a14610a7d57600080fd5b8063c444d064116100dc578063c444d06414610974578063c4d66de814610994578063c6c3bbe6146109b4578063d0d8bf7a146109d457600080fd5b8063a2ea14ba1461091c578063aaf5eb681461093c578063c2c2fd471461095257600080fd5b8063996517cf1161016f5780639e8c708e116101495780639e8c708e146108a55780639ec4066c146108c5578063a22cb465146108dc578063a2a957bb146108fc57600080fd5b8063996517cf1461085757806399d32fc41461086e5780639e6a1d7d1461088557600080fd5b80638456cb59116101ab5780638456cb59146107da57806389a30271146107ef5780638da5cb5b146108115780638de43c1f1461082f57600080fd5b8063715018a6146107735780637b0a47ee146107885780637b984e18146107ba57600080fd5b80632eb2c2d6116102b65780634e71d92d116102545780635d1e2d1b116102235780635d1e2d1b146106f257806361d027b3146107125780636593c2c914610733578063672434821461075357600080fd5b80634e71d92d1461069b5780634f6cb1cd146106a357806353d6fd59146106ba5780635c975abb146106da57600080fd5b80633e232dcf116102905780633e232dcf1461060b5780633f4ba83a1461062b5780634b0ee02a146106405780634e1273f41461066e57600080fd5b80632eb2c2d61461059257806332fe7b26146105b25780633af32abf146105da57600080fd5b806315d1c29211610323578063262d6152116102fd578063262d6152146105195780632954018c1461053a5780632a2befd91461055b5780632b166a211461057b57600080fd5b806315d1c292146104cb57806318160ddd146104e25780631a5fa2e3146104f957600080fd5b8063080d711a1161035f578063080d711a1461043057806309d2d0bc146104525780630e89341c1461048b57806315865eae146104ab57600080fd5b8062fdd58e1461038557806301ffc9a7146103b857806306fdde03146103e8575b600080fd5b34801561039157600080fd5b506103a56103a036600461505c565b610b42565b6040519081526020015b60405180910390f35b3480156103c457600080fd5b506103d86103d336600461509e565b610bdd565b60405190151581526020016103af565b3480156103f457600080fd5b506104236040518060400160405280600f81526020016e29b432bd36ba9023bab0b93234b0b760891b81525081565b6040516103af919061510b565b34801561043c57600080fd5b5061045061044b366004615169565b610c2d565b005b34801561045e57600080fd5b5061014154610473906001600160a01b031681565b6040516001600160a01b0390911681526020016103af565b34801561049757600080fd5b506104236104a63660046151aa565b610cbc565b3480156104b757600080fd5b506104506104c63660046151c3565b610d1c565b3480156104d757600080fd5b506103a56101405481565b3480156104ee57600080fd5b506103a56101335481565b34801561050557600080fd5b506104506105143660046151c3565b610e3a565b34801561052557600080fd5b5061014254610473906001600160a01b031681565b34801561054657600080fd5b5061013e54610473906001600160a01b031681565b34801561056757600080fd5b506104506105763660046151c3565b610e8c565b34801561058757600080fd5b506103a561012d5481565b34801561059e57600080fd5b506104506105ad366004615329565b610eb7565b3480156105be57600080fd5b50610473737a250d5630b4cf539739df2c5dacb4c659f2488d81565b3480156105e657600080fd5b506103d86105f53660046151c3565b6101436020526000908152604090205460ff1681565b34801561061757600080fd5b506104506106263660046153d6565b610f03565b34801561063757600080fd5b5061045061109f565b34801561064c57600080fd5b506103a561065b3660046151c3565b6101326020526000908152604090205481565b34801561067a57600080fd5b5061068e610689366004615417565b6110b1565b6040516103af919061551e565b6104506111da565b3480156106af57600080fd5b506103a561012f5481565b3480156106c657600080fd5b506104506106d536600461553f565b6115e8565b3480156106e657600080fd5b5060975460ff166103d8565b3480156106fe57600080fd5b5061045061070d36600461505c565b61161c565b34801561071e57600080fd5b5061012e54610473906001600160a01b031681565b34801561073f57600080fd5b5061045061074e3660046151c3565b61181d565b34801561075f57600080fd5b5061045061076e366004615578565b611848565b34801561077f57600080fd5b50610450611916565b34801561079457600080fd5b5061013454610135546107a5919082565b604080519283526020830191909152016103af565b3480156107c657600080fd5b506104506107d5366004615169565b611928565b3480156107e657600080fd5b506104506119aa565b3480156107fb57600080fd5b50610473600080516020615f1d83398151915281565b34801561081d57600080fd5b5060fb546001600160a01b0316610473565b34801561083b57600080fd5b50610473735fe72ed557d8a02fff49b3b826792c765d5ce16281565b34801561086357600080fd5b506103a56101315481565b34801561087a57600080fd5b506103a56101305481565b34801561089157600080fd5b506104506108a03660046151aa565b6119ba565b3480156108b157600080fd5b506104506108c03660046151c3565b611a20565b3480156108d157600080fd5b506103a561013f5481565b3480156108e857600080fd5b506104506108f736600461553f565b611aa8565b34801561090857600080fd5b506104506109173660046155e3565b611ab7565b34801561092857600080fd5b5061045061093736600461505c565b611b25565b34801561094857600080fd5b506103a561271081565b34801561095e57600080fd5b50610967611d92565b6040516103af919061564e565b34801561098057600080fd5b5061045061098f3660046153d6565b611da4565b3480156109a057600080fd5b506104506109af3660046151c3565b612361565b3480156109c057600080fd5b506104506109cf3660046153d6565b6125c6565b3480156109e057600080fd5b506104506109ef3660046151aa565b61274d565b348015610a0057600080fd5b50610450610a0f366004615661565b61275b565b348015610a2057600080fd5b506103d8610a2f3660046156af565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205460ff1690565b348015610a6957600080fd5b50610450610a783660046151c3565b6127b5565b348015610a8957600080fd5b50610450610a983660046156dd565b612833565b348015610aa957600080fd5b50610450610ab83660046151c3565b612878565b348015610ac957600080fd5b50610add610ad83660046151c3565b6128ee565b604080519586526020860194909452928401919091526060830152608082015260a0016103af565b348015610b1157600080fd5b50610b1a612b8c565b6040805194855260208501939093529183015260608201526080016103af565b610450612c01565b60006001600160a01b038316610bb25760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b5060008181526065602090815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b1480610c0e57506001600160e01b031982166303a24d0760e21b145b80610bd757506301ffc9a760e01b6001600160e01b0319831614610bd7565b610c35612ec8565b8060005b81811015610c7d57610c74848483818110610c5657610c56615745565b9050602002016020810190610c6b91906151c3565b61013690612f22565b50600101610c39565b507f2af8e725041af05e7616f64607221994cf28b2614abd44dc19aec098366692698383604051610caf92919061575b565b60405180910390a1505050565b606060068210610cd457610ccf82612f3e565b610bd7565b604051806060016040528060248152602001615f3d60249139610cf683612fd2565b604051602001610d0792919061579e565b60405160208183030381529060405292915050565b610d24613064565b6001600160a01b0316336001600160a01b031614610d555760405163bf63613560e01b815260040160405180910390fd5b6101335415610d925761013a54610d6c90426157f3565b61013454610d7a9190615806565b6101396000828254610d8c919061581d565b90915550505b4261013a556001600160a01b038116610dbe57604051635963709b60e01b815260040160405180910390fd5b600080610dca836130d3565b6001600160a01b0385166000908152610132602052604090205461013954929450909250610df791615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a764000091610e2a91615806565b610e349190615846565b90555050565b610e42612ec8565b6001600160a01b038116610e6957604051635963709b60e01b815260040160405180910390fd5b61013e80546001600160a01b0319166001600160a01b0392909216919091179055565b610e94612ec8565b61014180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038516331480610ed35750610ed38533610a2f565b610eef5760405162461bcd60e51b8152600401610ba99061585a565b610efc8585858585613278565b5050505050565b6101335415610f405761013a54610f1a90426157f3565b61013454610f289190615806565b6101396000828254610f3a919061581d565b90915550505b4261013a5533600080610f52836130d3565b6001600160a01b0385166000908152610132602052604090205461013954929450909250610f7f91615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a764000091610fb291615806565b610fbc9190615846565b8155831561100d5761012d54610fd29085615806565b82600101541015610ff65760405163fae8279160e01b815260040160405180910390fd5b61012d54600183018054918602909103905561103f565b61012d5482600101546110209190615846565b935061012d5482600101600082825461103991906158a8565b90915550505b61104a86868661345e565b856001600160a01b0316836001600160a01b03167f6c7e7d4cb83a668aef31739dd35dc3fc3d5f31d62b69e438b7b24d35b40dcc638660405161108f91815260200190565b60405180910390a3505050505050565b6110a7612ec8565b6110af613889565b565b606081518351146111165760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610ba9565b600083516001600160401b03811115611131576111316151e0565b60405190808252806020026020018201604052801561115a578160200160208202803683370190505b50905060005b84518110156111d2576111a585828151811061117e5761117e615745565b602002602001015185838151811061119857611198615745565b6020026020010151610b42565b8282815181106111b7576111b7615745565b60209081029190910101526111cb816158bc565b9050611160565b509392505050565b61013354156112175761013a546111f190426157f3565b610134546111ff9190615806565b6101396000828254611211919061581d565b90915550505b4261013a55336000818152610132602052604081205490819003611239575050565b600080611245846130d3565b9150915082610139546112589190615806565b825561013c54670de0b6b3a764000090611273908590615806565b61127d9190615846565b815560006112896138db565b6001600160a01b0316336001600160a01b0316146113c95760006112b36112ae613926565b613971565b90506000611330737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ae91906158d5565b9050600061134061271083615806565b836101405488600101546113549190615806565b61135e9190615806565b6113689190615846565b90508015806113775750348111155b156113865761271093506113c1565b8061139361271034615806565b61139d9190615846565b935061096084116113c15760405163fae8279160e01b815260040160405180910390fd5b5050506113ce565b506127105b341561143d5760006113de613a4c565b6001600160a01b03163460405160006040518083038185875af1925050503d8060008114611428576040519150601f19603f3d011682016040523d82523d6000602084013e61142d565b606091505b505090508061143b57600080fd5b505b60006127108285600101546114529190615806565b61145c9190615846565b905080156114db5760018401805482900390556040516340c10f1960e01b8152735fe72ed557d8a02fff49b3b826792c765d5ce162906340c10f19906114a890899085906004016158f2565b600060405180830381600087803b1580156114c257600080fd5b505af11580156114d6573d6000803e3d6000fd5b505050505b600061156f6127108486600101546114f39190615806565b6114fd9190615846565b6040516370a0823160e01b8152306004820152600080516020615f1d833981519152906370a0823190602401602060405180830381865afa158015611546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156a919061590b565b613a97565b9050801561159b57600184018054829003905561159b600080516020615f1d8339815191528883613aad565b60408051838152602081018390526001600160a01b038916917f34fcbac0073d7c3d388e51312faf357774904998eeb8fca628b9e6f65ee1cbf7910160405180910390a250505050505050565b6115f0612ec8565b6001600160a01b0391909116600090815261014360205260409020805460ff1916911515919091179055565b61013354156116595761013a5461163390426157f3565b610134546116419190615806565b6101396000828254611653919061581d565b90915550505b4261013a556001600160a01b03821661168557604051635963709b60e01b815260040160405180910390fd5b33600081815261013260205260409020548211156116b65760405163fae8279160e01b815260040160405180910390fd5b6000806116c2836130d3565b6001600160a01b038516600090815261013260205260409020805487900390819055610139549294509092506116f791615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a76400009161172a91615806565b6117349190615846565b815561173f83613b03565b505060008061174d856130d3565b6001600160a01b03871660009081526101326020526040902080548701908190556101395492945090925061178191615806565b82556001600160a01b0385166000908152610132602052604090205461013c54670de0b6b3a7640000916117b491615806565b6117be9190615846565b81556117c985613b03565b5050826001600160a01b0316816001600160a01b03167f56b138798bd325f6cc79f626c4644aa2fd6703ecb0ab0fb168f883caed75bf328460405161181091815260200190565b60405180910390a3505050565b611825612ec8565b61014280546001600160a01b0319166001600160a01b0392909216919091179055565b611850612ec8565b610133541561188d5761013a5461186790426157f3565b610134546118759190615806565b6101396000828254611887919061581d565b90915550505b4261013a55828181146118b3576040516322ee6ae760e01b815260040160405180910390fd5b60005b8181101561190e576119068686838181106118d3576118d3615745565b90506020020160208101906118e891906151c3565b8585848181106118fa576118fa615745565b90506020020135613c0a565b6001016118b6565b505050505050565b61191e612ec8565b6110af6000613cff565b611930612ec8565b8060005b818110156119785761196f84848381811061195157611951615745565b905060200201602081019061196691906151c3565b61013690613d51565b50600101611934565b507fccb0a951adeec2b600e22533ea11a7aed53b518d6b6633101ad5a4a78065831c8383604051610caf92919061575b565b6119b2612ec8565b6110af613d66565b6119c2612ec8565b806000036119e35760405163fae8279160e01b815260040160405180910390fd5b6101318190556040518181527f03bbcf0896b4f83d0039a26c11ebb96733a8e027d9aa71d95753b6168dbb10ab906020015b60405180910390a150565b611a28612ec8565b611aa5336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a94919061590b565b6001600160a01b0384169190613aad565b50565b611ab3338383613da3565b5050565b611abf612ec8565b61012f84905561013083905561013f8290556101408190556040805185815260208101859052908101839052606081018290527f2c40e30353ae48a032fd20f1fece20031c1b80a2bc8512a2c172ff4de2e595199060800160405180910390a150505050565b611b2d6138db565b6001600160a01b0316336001600160a01b031614611b5e5760405163aedd0c1d60e01b815260040160405180910390fd5b6101335415611b9b5761013a54611b7590426157f3565b61013454611b839190615806565b6101396000828254611b95919061581d565b90915550505b4261013a556001600160a01b038216611bc757604051635963709b60e01b815260040160405180910390fd5b80600003611be85760405163fae8279160e01b815260040160405180910390fd5b600080611bf4846130d3565b6001600160a01b0386166000908152610132602052604090205461013954929450909250611c2191615806565b82556001600160a01b0384166000908152610132602052604090205461013c54670de0b6b3a764000091611c5491615806565b611c5e9190615846565b8155600181018054849190600090611c779084906157f3565b90915550506101425460405163095ea7b360e01b8152600080516020615f1d8339815191529163095ea7b391611cbb916001600160a01b03169087906004016158f2565b6020604051808303816000875af1158015611cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfe9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f992611d4692600080516020615f1d8339815191529289921690600401615941565b6060604051808303816000875af1158015611d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d899190615964565b50505050505050565b6060611d9f610136613e7b565b905090565b611dac6138db565b6001600160a01b0316336001600160a01b031614611ddd5760405163aedd0c1d60e01b815260040160405180910390fd5b6101335415611e1a5761013a54611df490426157f3565b61013454611e029190615806565b6101396000828254611e14919061581d565b90915550505b4261013a556001600160a01b038316611e4657604051635963709b60e01b815260040160405180910390fd5b801580611e5557506101315481115b15611e735760405163fae8279160e01b815260040160405180910390fd5b611e7f61013683613e88565b611e9c5760405163bc7fd0cf60e01b815260040160405180910390fd5b735fe72ed557d8a02fff49b3b826792c765d5ce1626379cc67903361012d54611ec59085615806565b6040518363ffffffff1660e01b8152600401611ee29291906158f2565b600060405180830381600087803b158015611efc57600080fd5b505af1158015611f10573d6000803e3d6000fd5b50505050600080611f20856130d3565b6001600160a01b0387166000908152610132602052604090205461013954929450909250611f4d91615806565b82556001600160a01b0385166000908152610132602052604090205461013c54670de0b6b3a764000091611f8091615806565b611f8a9190615846565b81600001819055506000670de0b6b3a7640000600080516020615f1d8339815191526001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200d9190615992565b61201890600a615a99565b61012f546120269190615806565b6120309190615846565b90508082600101541061216b578082600101600082825461205191906157f3565b90915550506101425460405163095ea7b360e01b8152600080516020615f1d8339815191529163095ea7b391612095916001600160a01b03169085906004016158f2565b6020604051808303816000875af11580156120b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d89190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f99261212092600080516020615f1d8339815191529287921690600401615941565b6060604051808303816000875af115801561213f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121639190615964565b50505061230c565b6000670de0b6b3a7640000866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d89190615992565b6121e390600a615a99565b61012f546121f19190615806565b6121fb9190615846565b90506122126001600160a01b038716333084613eaa565b6101425460405163095ea7b360e01b81526001600160a01b038881169263095ea7b392612247929091169085906004016158f2565b6020604051808303816000875af1158015612266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228a9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f9926122c4928b9287921690600401615941565b6060604051808303816000875af11580156122e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123079190615964565b505050505b6123163385613c0a565b856001600160a01b03167f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d8560405161235191815260200190565b60405180910390a2505050505050565b600054610100900460ff16158080156123815750600054600160ff909116105b8061239b5750303b15801561239b575060005460ff166001145b6123fe5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610ba9565b6000805460ff191660011790558015612421576000805461ff0019166101001790555b6001600160a01b03821661244857604051635963709b60e01b815260040160405180910390fd5b61012e80546001600160a01b0319166001600160a01b0384161790556040805160c0810182526001815260056020820152600a918101919091526019606082015260326080820152606460a08201526124a690610138906006614f9f565b5067a688906bd8b0000061012d5567d02ab486cedc000061012f556124db610136600080516020615f1d833981519152613d51565b506124fc61013673dac17f958d2ee523a2206206994597c13d831ec7613d51565b5061251d610136736b175474e89094c44da98b954eedeac495271d0f613d51565b506107d0610130556064610131556125406201518067016345785d8a0000615846565b610134556203d09061013555612554613ee2565b612575604051806060016040528060248152602001615f3d60249139613f11565b61257d613f41565b8015611ab3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b61013354156126035761013a546125dd90426157f3565b610134546125eb9190615806565b61013960008282546125fd919061581d565b90915550505b4261013a5561012d543390735fe72ed557d8a02fff49b3b826792c765d5ce162906379cc67909083906126369086615806565b6040518363ffffffff1660e01b81526004016126539291906158f2565b600060405180830381600087803b15801561266d57600080fd5b505af1158015612681573d6000803e3d6000fd5b50505050600080612691836130d3565b6001600160a01b03851660009081526101326020526040902054610139549294509092506126be91615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a7640000916126f191615806565b6126fb9190615846565b815561270886868661345e565b856001600160a01b0316836001600160a01b03167fab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f88660405161108f91815260200190565b612755612ec8565b61012d55565b612763612ec8565b61013354156127a05761013a5461277a90426157f3565b610134546127889190615806565b610139600082825461279a919061581d565b90915550505b4261013a558051610134556020015161013555565b6127bd612ec8565b6001600160a01b0381166127e457604051635963709b60e01b815260040160405180910390fd5b61012e80546001600160a01b0319166001600160a01b0383169081179091556040519081527ffb26c00f7d7dba814173c8a2db3466cb26ee25fdcec8867af7da3aa1f296addd90602001611a15565b6001600160a01b03851633148061284f575061284f8533610a2f565b61286b5760405162461bcd60e51b8152600401610ba99061585a565b610efc8585858585613f70565b612880612ec8565b6001600160a01b0381166128e55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ba9565b611aa581613cff565b6001600160a01b0381166000908152610132602052604081205481908190819081908015612b82576001600160a01b038716600090815261013b60209081526040808320815180830190925280548252600101549181019190915261013a5490919061295a90426157f3565b610134546129689190615806565b61013954612976919061581d565b90506000806129848b6140ac565b9092509050600081612996848261581d565b6001600160a01b038e16600090815261013b60205260409020546129ba8988615806565b6129c491906157f3565b6129ce9190615806565b6129d89190615846565b905061271061013054826129ec9190615806565b6129f69190615846565b818660200151612a06919061581d565b612a1091906157f3565b6001600160a01b038d16600090815261013d6020908152604091829020825180840190935280548084526001909101549183019190915261013c54929d509096509450670de0b6b3a76400009350612a6b9250869150615806565b612a759190615846565b8260200151612a84919061581d565b612a8e91906157f3565b9550506000612a9e6112ae613926565b90506000612af7737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b9050612710826101405461013f54612b0f919061581d565b612b19908b615806565b612b239190615806565b612b2d9190615846565b955061271061013f5489612b419190615806565b612b4b9190615846565b9450612b5961271082615806565b82610140548a612b699190615806565b612b739190615806565b612b7d9190615846565b935050505b5091939590929450565b61013f5461014054600080612ba26112ae613926565b9150612bf9737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b905090919293565b34600003612c0b57565b604080516002808252606082018352600092602083019080368337019050509050737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca291906158d5565b81600081518110612cb557612cb5615745565b60200260200101906001600160a01b031690816001600160a01b031681525050600080516020615f1d83398151915281600181518110612cf757612cf7615745565b6001600160a01b0392909216602092830291909101909101526040516370a0823160e01b8152306004820152600090600080516020615f1d833981519152906370a0823190602401602060405180830381865afa158015612d5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d80919061590b565b60405163b6f9de9560e01b8152909150737a250d5630b4cf539739df2c5dacb4c659f2488d9063b6f9de95903490612dc390600090879030904290600401615aa8565b6000604051808303818588803b158015612ddc57600080fd5b505af1158015612df0573d6000803e3d6000fd5b50506040516370a0823160e01b815230600482015260009350849250600080516020615f1d83398151915291506370a0823190602401602060405180830381865afa158015612e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e67919061590b565b612e7191906157f3565b9050600061013354118015612e865750600081115b15612ec35761013354612ea1670de0b6b3a764000083615806565b612eab9190615846565b61013c6000828254612ebd919061581d565b90915550505b505050565b60fb546001600160a01b031633146110af5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ba9565b6000612f37836001600160a01b03841661419b565b9392505050565b606060678054612f4d90615add565b80601f0160208091040260200160405190810160405280929190818152602001828054612f7990615add565b8015612fc65780601f10612f9b57610100808354040283529160200191612fc6565b820191906000526020600020905b815481529060010190602001808311612fa957829003601f168201915b50505050509050919050565b60606000612fdf8361428e565b60010190506000816001600160401b03811115612ffe57612ffe6151e0565b6040519080825280601f01601f191660200182016040528015613028576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461303257509392505050565b61013e54604080516369576d8960e01b815290516000926001600160a01b0316916369576d899160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9f91906158d5565b6001600160a01b0381166000908152610132602090815260408083205461013b909252822091908180613105866140ac565b9092509050600081613117848261581d565b875461013954613128908890615806565b61313291906157f3565b61313c9190615806565b6131469190615846565b90506000612710610130548361315c9190615806565b6131669190615846565b905061317281836157f3565b876001016000828254613185919061581d565b909155505080156132085761012e546040516340c10f1960e01b8152735fe72ed557d8a02fff49b3b826792c765d5ce162916340c10f19916131d5916001600160a01b03169085906004016158f2565b600060405180830381600087803b1580156131ef57600080fd5b505af1158015613203573d6000803e3d6000fd5b505050505b6001600160a01b038816600090815261013d60205260409020805461013c5491975090670de0b6b3a764000090613240908890615806565b61324a9190615846565b61325491906157f3565b866001016000828254613267919061581d565b925050819055505050505050915091565b81518351146132da5760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610ba9565b6001600160a01b0384166133005760405162461bcd60e51b8152600401610ba990615b17565b3361330f818787878787614366565b60005b84518110156133f857600085828151811061332f5761332f615745565b60200260200101519050600085838151811061334d5761334d615745565b60209081029190910181015160008481526065835260408082206001600160a01b038e16835290935291909120549091508181101561339e5760405162461bcd60e51b8152600401610ba990615b5c565b60008381526065602090815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906133dd90849061581d565b92505081905550505050806133f1906158bc565b9050613312565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051613448929190615ba6565b60405180910390a461190e818787878787614603565b6001600160a01b03831661348557604051635963709b60e01b815260040160405180910390fd5b80158061349457506101315481115b156134b25760405163fae8279160e01b815260040160405180910390fd5b6134be61013683613e88565b6134db5760405163bc7fd0cf60e01b815260040160405180910390fd5b600061013d6000856001600160a01b03166001600160a01b0316815260200190815260200160002090506000670de0b6b3a7640000600080516020615f1d8339815191526001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135809190615992565b61358b90600a615a99565b61012f546135999190615806565b6135a39190615846565b9050808260010154106136de57808260010160008282546135c491906157f3565b90915550506101425460405163095ea7b360e01b8152600080516020615f1d8339815191529163095ea7b391613608916001600160a01b03169085906004016158f2565b6020604051808303816000875af1158015613627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364b9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f99261369392600080516020615f1d8339815191529287921690600401615941565b6060604051808303816000875af11580156136b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d69190615964565b50505061387f565b6000670de0b6b3a7640000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374b9190615992565b61375690600a615a99565b61012f546137649190615806565b61376e9190615846565b90506137856001600160a01b038616333084613eaa565b6101425460405163095ea7b360e01b81526001600160a01b038781169263095ea7b3926137ba929091169085906004016158f2565b6020604051808303816000875af11580156137d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137fd9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f992613837928a9287921690600401615941565b6060604051808303816000875af1158015613856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387a9190615964565b505050505b610efc8584613c0a565b61389161475e565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b61013e546040805163564c123960e11b815290516000926001600160a01b03169163ac9824729160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b61013e5460408051630ef7063b60e41b815290516000926001600160a01b03169163ef7063b09160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b61013e546040805163175228df60e11b815290516000926001600160a01b031691632ea451be9160048083019260209291908290030181865afa1580156139bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139e091906158d5565b60405163eb9d14a960e01b81526001600160a01b038481166004830152919091169063eb9d14a990602401602060405180830381865afa158015613a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd7919061590b565b61013e5460408051631d8cf42560e11b815290516000926001600160a01b031691633b19e84a9160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b6000818310613aa65781612f37565b5090919050565b612ec38363a9059cbb60e01b8484604051602401613acc9291906158f2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526147a7565b6001600160a01b03811660009081526101326020526040812054905b6006811015612ec3576000600182600660ff160303905060006101388260068110613b4c57613b4c615745565b602081049091015460ff601f9092166101000a9004168481613b7057613b70615830565b0490506000613b7f8684610b42565b905080821115613bab57613ba686848385036040518060200160405280600081525061487c565b613bc0565b80821015613bc057613bc08684848403614998565b6101388360068110613bd457613bd4615745565b602081049091015460ff601f9092166101000a9004168581613bf857613bf8615830565b0694505060019092019150613b1f9050565b600080613c16846130d3565b6001600160a01b0386166000908152610132602052604090208054860190556101338054860190819055610135549294509092501115613c895760026101346000016000828254613c679190615846565b9091555050610135805460029190600090613c83908490615806565b90915550505b6001600160a01b0384166000908152610132602052604090205461013954613cb19190615806565b82556001600160a01b0384166000908152610132602052604090205461013c54670de0b6b3a764000091613ce491615806565b613cee9190615846565b8155613cf984613b03565b50505050565b60fb80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612f37836001600160a01b038416614b2c565b613d6e614b7b565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586138be3390565b816001600160a01b0316836001600160a01b031603613e165760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610ba9565b6001600160a01b03838116600081815260666020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101611810565b60606000612f3783614bc1565b6001600160a01b03811660009081526001830160205260408120541515612f37565b6040516001600160a01b0380851660248301528316604482015260648101829052613cf99085906323b872dd60e01b90608401613acc565b600054610100900460ff16613f095760405162461bcd60e51b8152600401610ba990615bd4565b6110af614c1c565b600054610100900460ff16613f385760405162461bcd60e51b8152600401610ba990615bd4565b611aa581614c4f565b600054610100900460ff16613f685760405162461bcd60e51b8152600401610ba990615bd4565b6110af614c7f565b6001600160a01b038416613f965760405162461bcd60e51b8152600401610ba990615b17565b336000613fa285614caf565b90506000613faf85614caf565b9050613fbf838989858589614366565b60008681526065602090815260408083206001600160a01b038c168452909152902054858110156140025760405162461bcd60e51b8152600401610ba990615b5c565b60008781526065602090815260408083206001600160a01b038d8116855292528083208985039055908a1682528120805488929061404190849061581d565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46140a1848a8a8a8a8a614cfa565b505050505050505050565b60008061013e60009054906101000a90046001600160a01b03166001600160a01b03166369576d896040518163ffffffff1660e01b8152600401602060405180830381865afa158015614103573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061412791906158d5565b60405163359a2fed60e01b81526001600160a01b038581166004830152919091169063359a2fed906024016040805180830381865afa15801561416e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141929190615c1f565b91509150915091565b600081815260018301602052604081205480156142845760006141bf6001836157f3565b85549091506000906141d3906001906157f3565b90508181146142385760008660000182815481106141f3576141f3615745565b906000526020600020015490508087600001848154811061421657614216615745565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061424957614249615c43565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610bd7565b6000915050610bd7565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106142cd5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106142f9576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061431757662386f26fc10000830492506010015b6305f5e100831061432f576305f5e100830492506008015b612710831061434357612710830492506004015b60648310614355576064830492506002015b600a8310610bd75760010192915050565b61013354156143a35761013a5461437d90426157f3565b6101345461438b9190615806565b610139600082825461439d919061581d565b90915550505b4261013a556143b6868686868686614db5565b6001600160a01b0386163b15614405576001600160a01b0386166000908152610143602052604090205460ff1661440057604051635ffde35f60e11b815260040160405180910390fd5b614456565b6001600160a01b0384163b1515801561443857506001600160a01b0384166000908152610143602052604090205460ff16155b1561445657604051635ffde35f60e11b815260040160405180910390fd5b6001600160a01b038516158061447357506001600160a01b038416155b61190e57600080614483876130d3565b91509150600080614493886130d3565b90925090506000805b8851811015614510578781815181106144b7576144b7615745565b60200260200101516101388a83815181106144d4576144d4615745565b6020026020010151600681106144ec576144ec615745565b602081049091015460ff601f9092166101000a90041602919091019060010161449c565b506001600160a01b03808b166000818152610132602052604080822080548690038155938d16825281208054850190555254610139546145509190615806565b85556001600160a01b038a166000908152610132602052604090205461013c54670de0b6b3a76400009161458391615806565b61458d9190615846565b84556001600160a01b03891660009081526101326020526040902054610139546145b79190615806565b83556001600160a01b0389166000908152610132602052604090205461013c54670de0b6b3a7640000916145ea91615806565b6145f49190615846565b90915550505050505050505050565b6001600160a01b0384163b1561190e5760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906146479089908990889088908890600401615c59565b6020604051808303816000875af1925050508015614682575060408051601f3d908101601f1916820190925261467f91810190615cb7565b60015b61472e5761468e615cd4565b806308c379a0036146c757506146a2615cf0565b806146ad57506146c9565b8060405162461bcd60e51b8152600401610ba9919061510b565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610ba9565b6001600160e01b0319811663bc197c8160e01b14611d895760405162461bcd60e51b8152600401610ba990615d79565b60975460ff166110af5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ba9565b60006147fc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e1d9092919063ffffffff16565b905080516000148061481d57508080602001905181019061481d9190615924565b612ec35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ba9565b6001600160a01b0384166148dc5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610ba9565b3360006148e885614caf565b905060006148f585614caf565b905061490683600089858589614366565b60008681526065602090815260408083206001600160a01b038b1684529091528120805487929061493890849061581d565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4611d8983600089898989614cfa565b6001600160a01b0383166149fa5760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610ba9565b336000614a0684614caf565b90506000614a1384614caf565b9050614a3383876000858560405180602001604052806000815250614366565b60008581526065602090815260408083206001600160a01b038a16845290915290205484811015614ab25760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610ba9565b60008681526065602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4604080516020810190915260009052611d89565b6000818152600183016020526040812054614b7357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610bd7565b506000610bd7565b60975460ff16156110af5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610ba9565b606081600001805480602002602001604051908101604052809291908181526020018280548015612fc657602002820191906000526020600020905b815481526020019060010190808311614bfd5750505050509050919050565b600054610100900460ff16614c435760405162461bcd60e51b8152600401610ba990615bd4565b6097805460ff19169055565b600054610100900460ff16614c765760405162461bcd60e51b8152600401610ba990615bd4565b611aa581614e34565b600054610100900460ff16614ca65760405162461bcd60e51b8152600401610ba990615bd4565b6110af33613cff565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110614ce957614ce9615745565b602090810291909101015292915050565b6001600160a01b0384163b1561190e5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190614d3e9089908990889088908890600401615dc1565b6020604051808303816000875af1925050508015614d79575060408051601f3d908101601f19168201909252614d7691810190615cb7565b60015b614d855761468e615cd4565b6001600160e01b0319811663f23a6e6160e01b14611d895760405162461bcd60e51b8152600401610ba990615d79565b60975460ff161561190e5760405162461bcd60e51b815260206004820152602c60248201527f455243313135355061757361626c653a20746f6b656e207472616e736665722060448201526b1dda1a5b19481c185d5cd95960a21b6064820152608401610ba9565b6060614e2c8484600085614e40565b949350505050565b6067611ab38282615e41565b606082471015614ea15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610ba9565b600080866001600160a01b03168587604051614ebd9190615f00565b60006040518083038185875af1925050503d8060008114614efa576040519150601f19603f3d011682016040523d82523d6000602084013e614eff565b606091505b5091509150614f1087838387614f1b565b979650505050505050565b60608315614f8a578251600003614f83576001600160a01b0385163b614f835760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ba9565b5081614e2c565b614e2c83838151156146ad5781518083602001fd5b6001830191839082156150225791602002820160005b83821115614ff357835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302614fb5565b80156150205782816101000a81549060ff0219169055600101602081600001049283019260010302614ff3565b505b5061502e929150615032565b5090565b5b8082111561502e5760008155600101615033565b6001600160a01b0381168114611aa557600080fd5b6000806040838503121561506f57600080fd5b823561507a81615047565b946020939093013593505050565b6001600160e01b031981168114611aa557600080fd5b6000602082840312156150b057600080fd5b8135612f3781615088565b60005b838110156150d65781810151838201526020016150be565b50506000910152565b600081518084526150f78160208601602086016150bb565b601f01601f19169290920160200192915050565b602081526000612f3760208301846150df565b60008083601f84011261513057600080fd5b5081356001600160401b0381111561514757600080fd5b6020830191508360208260051b850101111561516257600080fd5b9250929050565b6000806020838503121561517c57600080fd5b82356001600160401b0381111561519257600080fd5b61519e8582860161511e565b90969095509350505050565b6000602082840312156151bc57600080fd5b5035919050565b6000602082840312156151d557600080fd5b8135612f3781615047565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b038111828210171561521b5761521b6151e0565b6040525050565b60006001600160401b0382111561523b5761523b6151e0565b5060051b60200190565b600082601f83011261525657600080fd5b8135602061526382615222565b60405161527082826151f6565b83815260059390931b850182019282810191508684111561529057600080fd5b8286015b848110156152ab5780358352918301918301615294565b509695505050505050565b600082601f8301126152c757600080fd5b81356001600160401b038111156152e0576152e06151e0565b6040516152f7601f8301601f1916602001826151f6565b81815284602083860101111561530c57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561534157600080fd5b853561534c81615047565b9450602086013561535c81615047565b935060408601356001600160401b038082111561537857600080fd5b61538489838a01615245565b9450606088013591508082111561539a57600080fd5b6153a689838a01615245565b935060808801359150808211156153bc57600080fd5b506153c9888289016152b6565b9150509295509295909350565b6000806000606084860312156153eb57600080fd5b83356153f681615047565b9250602084013561540681615047565b929592945050506040919091013590565b6000806040838503121561542a57600080fd5b82356001600160401b038082111561544157600080fd5b818501915085601f83011261545557600080fd5b8135602061546282615222565b60405161546f82826151f6565b83815260059390931b850182019282810191508984111561548f57600080fd5b948201945b838610156154b65785356154a781615047565b82529482019490820190615494565b965050860135925050808211156154cc57600080fd5b506154d985828601615245565b9150509250929050565b600081518084526020808501945080840160005b83811015615513578151875295820195908201906001016154f7565b509495945050505050565b602081526000612f3760208301846154e3565b8015158114611aa557600080fd5b6000806040838503121561555257600080fd5b823561555d81615047565b9150602083013561556d81615531565b809150509250929050565b6000806000806040858703121561558e57600080fd5b84356001600160401b03808211156155a557600080fd5b6155b18883890161511e565b909650945060208701359150808211156155ca57600080fd5b506155d78782880161511e565b95989497509550505050565b600080600080608085870312156155f957600080fd5b5050823594602084013594506040840135936060013592509050565b600081518084526020808501945080840160005b838110156155135781516001600160a01b031687529582019590820190600101615629565b602081526000612f376020830184615615565b60006040828403121561567357600080fd5b604051604081018181106001600160401b0382111715615695576156956151e0565b604052823581526020928301359281019290925250919050565b600080604083850312156156c257600080fd5b82356156cd81615047565b9150602083013561556d81615047565b600080600080600060a086880312156156f557600080fd5b853561570081615047565b9450602086013561571081615047565b9350604086013592506060860135915060808601356001600160401b0381111561573957600080fd5b6153c9888289016152b6565b634e487b7160e01b600052603260045260246000fd5b60208082528181018390526000908460408401835b868110156152ab57823561578381615047565b6001600160a01b031682529183019190830190600101615770565b600083516157b08184602088016150bb565b8351908301906157c48183602088016150bb565b64173539b7b760d91b9101908152600501949350505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bd757610bd76157dd565b8082028115828204841417610bd757610bd76157dd565b80820180821115610bd757610bd76157dd565b634e487b7160e01b600052601260045260246000fd5b60008261585557615855615830565b500490565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b6000826158b7576158b7615830565b500690565b6000600182016158ce576158ce6157dd565b5060010190565b6000602082840312156158e757600080fd5b8151612f3781615047565b6001600160a01b03929092168252602082015260400190565b60006020828403121561591d57600080fd5b5051919050565b60006020828403121561593657600080fd5b8151612f3781615531565b6001600160a01b0393841681526020810192909252909116604082015260600190565b60008060006060848603121561597957600080fd5b8351925060208401519150604084015190509250925092565b6000602082840312156159a457600080fd5b815160ff81168114612f3757600080fd5b600181815b808511156159f05781600019048211156159d6576159d66157dd565b808516156159e357918102915b93841c93908002906159ba565b509250929050565b600082615a0757506001610bd7565b81615a1457506000610bd7565b8160018114615a2a5760028114615a3457615a50565b6001915050610bd7565b60ff841115615a4557615a456157dd565b50506001821b610bd7565b5060208310610133831016604e8410600b8410161715615a73575081810a610bd7565b615a7d83836159b5565b8060001904821115615a9157615a916157dd565b029392505050565b6000612f3760ff8416836159f8565b848152608060208201526000615ac16080830186615615565b6001600160a01b03949094166040830152506060015292915050565b600181811c90821680615af157607f821691505b602082108103615b1157634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081526000615bb960408301856154e3565b8281036020840152615bcb81856154e3565b95945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008060408385031215615c3257600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b0386811682528516602082015260a060408201819052600090615c85908301866154e3565b8281036060840152615c9781866154e3565b90508281036080840152615cab81856150df565b98975050505050505050565b600060208284031215615cc957600080fd5b8151612f3781615088565b600060033d1115615ced5760046000803e5060005160e01c5b90565b600060443d1015615cfe5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615d2d57505050505090565b8285019150815181811115615d455750505050505090565b843d8701016020828501011115615d5f5750505050505090565b615d6e602082860101876151f6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090614f10908301846150df565b601f821115612ec357600081815260208120601f850160051c81016020861015615e225750805b601f850160051c820191505b8181101561190e57828155600101615e2e565b81516001600160401b03811115615e5a57615e5a6151e0565b615e6e81615e688454615add565b84615dfb565b602080601f831160018114615ea35760008415615e8b5750858301515b600019600386901b1c1916600185901b17855561190e565b600085815260208120601f198616915b82811015615ed257888601518255948401946001909101908401615eb3565b5085821015615ef05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251615f128184602087016150bb565b919091019291505056fe000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4868747470733a2f2f6d657461646174612e7368657a6d752e696f2f677561726469616e2fa26469706673582212203bed9aa80e86a391932afada7ce910cac8f826be26183c12dd3f4b19c35b55c964736f6c63430008110033

Deployed Bytecode

0x6080604052600436106103805760003560e01c8063715018a6116101d1578063a2ea14ba11610102578063debfb961116100a0578063f2fde38b1161006f578063f2fde38b14610a9d578063f40f0f5214610abd578063f74948ab14610b05578063ff3d9e4f14610b3a57600080fd5b8063debfb961146109f4578063e985e9c514610a14578063f0f4426014610a5d578063f242432a14610a7d57600080fd5b8063c444d064116100dc578063c444d06414610974578063c4d66de814610994578063c6c3bbe6146109b4578063d0d8bf7a146109d457600080fd5b8063a2ea14ba1461091c578063aaf5eb681461093c578063c2c2fd471461095257600080fd5b8063996517cf1161016f5780639e8c708e116101495780639e8c708e146108a55780639ec4066c146108c5578063a22cb465146108dc578063a2a957bb146108fc57600080fd5b8063996517cf1461085757806399d32fc41461086e5780639e6a1d7d1461088557600080fd5b80638456cb59116101ab5780638456cb59146107da57806389a30271146107ef5780638da5cb5b146108115780638de43c1f1461082f57600080fd5b8063715018a6146107735780637b0a47ee146107885780637b984e18146107ba57600080fd5b80632eb2c2d6116102b65780634e71d92d116102545780635d1e2d1b116102235780635d1e2d1b146106f257806361d027b3146107125780636593c2c914610733578063672434821461075357600080fd5b80634e71d92d1461069b5780634f6cb1cd146106a357806353d6fd59146106ba5780635c975abb146106da57600080fd5b80633e232dcf116102905780633e232dcf1461060b5780633f4ba83a1461062b5780634b0ee02a146106405780634e1273f41461066e57600080fd5b80632eb2c2d61461059257806332fe7b26146105b25780633af32abf146105da57600080fd5b806315d1c29211610323578063262d6152116102fd578063262d6152146105195780632954018c1461053a5780632a2befd91461055b5780632b166a211461057b57600080fd5b806315d1c292146104cb57806318160ddd146104e25780631a5fa2e3146104f957600080fd5b8063080d711a1161035f578063080d711a1461043057806309d2d0bc146104525780630e89341c1461048b57806315865eae146104ab57600080fd5b8062fdd58e1461038557806301ffc9a7146103b857806306fdde03146103e8575b600080fd5b34801561039157600080fd5b506103a56103a036600461505c565b610b42565b6040519081526020015b60405180910390f35b3480156103c457600080fd5b506103d86103d336600461509e565b610bdd565b60405190151581526020016103af565b3480156103f457600080fd5b506104236040518060400160405280600f81526020016e29b432bd36ba9023bab0b93234b0b760891b81525081565b6040516103af919061510b565b34801561043c57600080fd5b5061045061044b366004615169565b610c2d565b005b34801561045e57600080fd5b5061014154610473906001600160a01b031681565b6040516001600160a01b0390911681526020016103af565b34801561049757600080fd5b506104236104a63660046151aa565b610cbc565b3480156104b757600080fd5b506104506104c63660046151c3565b610d1c565b3480156104d757600080fd5b506103a56101405481565b3480156104ee57600080fd5b506103a56101335481565b34801561050557600080fd5b506104506105143660046151c3565b610e3a565b34801561052557600080fd5b5061014254610473906001600160a01b031681565b34801561054657600080fd5b5061013e54610473906001600160a01b031681565b34801561056757600080fd5b506104506105763660046151c3565b610e8c565b34801561058757600080fd5b506103a561012d5481565b34801561059e57600080fd5b506104506105ad366004615329565b610eb7565b3480156105be57600080fd5b50610473737a250d5630b4cf539739df2c5dacb4c659f2488d81565b3480156105e657600080fd5b506103d86105f53660046151c3565b6101436020526000908152604090205460ff1681565b34801561061757600080fd5b506104506106263660046153d6565b610f03565b34801561063757600080fd5b5061045061109f565b34801561064c57600080fd5b506103a561065b3660046151c3565b6101326020526000908152604090205481565b34801561067a57600080fd5b5061068e610689366004615417565b6110b1565b6040516103af919061551e565b6104506111da565b3480156106af57600080fd5b506103a561012f5481565b3480156106c657600080fd5b506104506106d536600461553f565b6115e8565b3480156106e657600080fd5b5060975460ff166103d8565b3480156106fe57600080fd5b5061045061070d36600461505c565b61161c565b34801561071e57600080fd5b5061012e54610473906001600160a01b031681565b34801561073f57600080fd5b5061045061074e3660046151c3565b61181d565b34801561075f57600080fd5b5061045061076e366004615578565b611848565b34801561077f57600080fd5b50610450611916565b34801561079457600080fd5b5061013454610135546107a5919082565b604080519283526020830191909152016103af565b3480156107c657600080fd5b506104506107d5366004615169565b611928565b3480156107e657600080fd5b506104506119aa565b3480156107fb57600080fd5b50610473600080516020615f1d83398151915281565b34801561081d57600080fd5b5060fb546001600160a01b0316610473565b34801561083b57600080fd5b50610473735fe72ed557d8a02fff49b3b826792c765d5ce16281565b34801561086357600080fd5b506103a56101315481565b34801561087a57600080fd5b506103a56101305481565b34801561089157600080fd5b506104506108a03660046151aa565b6119ba565b3480156108b157600080fd5b506104506108c03660046151c3565b611a20565b3480156108d157600080fd5b506103a561013f5481565b3480156108e857600080fd5b506104506108f736600461553f565b611aa8565b34801561090857600080fd5b506104506109173660046155e3565b611ab7565b34801561092857600080fd5b5061045061093736600461505c565b611b25565b34801561094857600080fd5b506103a561271081565b34801561095e57600080fd5b50610967611d92565b6040516103af919061564e565b34801561098057600080fd5b5061045061098f3660046153d6565b611da4565b3480156109a057600080fd5b506104506109af3660046151c3565b612361565b3480156109c057600080fd5b506104506109cf3660046153d6565b6125c6565b3480156109e057600080fd5b506104506109ef3660046151aa565b61274d565b348015610a0057600080fd5b50610450610a0f366004615661565b61275b565b348015610a2057600080fd5b506103d8610a2f3660046156af565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205460ff1690565b348015610a6957600080fd5b50610450610a783660046151c3565b6127b5565b348015610a8957600080fd5b50610450610a983660046156dd565b612833565b348015610aa957600080fd5b50610450610ab83660046151c3565b612878565b348015610ac957600080fd5b50610add610ad83660046151c3565b6128ee565b604080519586526020860194909452928401919091526060830152608082015260a0016103af565b348015610b1157600080fd5b50610b1a612b8c565b6040805194855260208501939093529183015260608201526080016103af565b610450612c01565b60006001600160a01b038316610bb25760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b5060008181526065602090815260408083206001600160a01b03861684529091529020545b92915050565b60006001600160e01b03198216636cdb3d1360e11b1480610c0e57506001600160e01b031982166303a24d0760e21b145b80610bd757506301ffc9a760e01b6001600160e01b0319831614610bd7565b610c35612ec8565b8060005b81811015610c7d57610c74848483818110610c5657610c56615745565b9050602002016020810190610c6b91906151c3565b61013690612f22565b50600101610c39565b507f2af8e725041af05e7616f64607221994cf28b2614abd44dc19aec098366692698383604051610caf92919061575b565b60405180910390a1505050565b606060068210610cd457610ccf82612f3e565b610bd7565b604051806060016040528060248152602001615f3d60249139610cf683612fd2565b604051602001610d0792919061579e565b60405160208183030381529060405292915050565b610d24613064565b6001600160a01b0316336001600160a01b031614610d555760405163bf63613560e01b815260040160405180910390fd5b6101335415610d925761013a54610d6c90426157f3565b61013454610d7a9190615806565b6101396000828254610d8c919061581d565b90915550505b4261013a556001600160a01b038116610dbe57604051635963709b60e01b815260040160405180910390fd5b600080610dca836130d3565b6001600160a01b0385166000908152610132602052604090205461013954929450909250610df791615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a764000091610e2a91615806565b610e349190615846565b90555050565b610e42612ec8565b6001600160a01b038116610e6957604051635963709b60e01b815260040160405180910390fd5b61013e80546001600160a01b0319166001600160a01b0392909216919091179055565b610e94612ec8565b61014180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038516331480610ed35750610ed38533610a2f565b610eef5760405162461bcd60e51b8152600401610ba99061585a565b610efc8585858585613278565b5050505050565b6101335415610f405761013a54610f1a90426157f3565b61013454610f289190615806565b6101396000828254610f3a919061581d565b90915550505b4261013a5533600080610f52836130d3565b6001600160a01b0385166000908152610132602052604090205461013954929450909250610f7f91615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a764000091610fb291615806565b610fbc9190615846565b8155831561100d5761012d54610fd29085615806565b82600101541015610ff65760405163fae8279160e01b815260040160405180910390fd5b61012d54600183018054918602909103905561103f565b61012d5482600101546110209190615846565b935061012d5482600101600082825461103991906158a8565b90915550505b61104a86868661345e565b856001600160a01b0316836001600160a01b03167f6c7e7d4cb83a668aef31739dd35dc3fc3d5f31d62b69e438b7b24d35b40dcc638660405161108f91815260200190565b60405180910390a3505050505050565b6110a7612ec8565b6110af613889565b565b606081518351146111165760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b6064820152608401610ba9565b600083516001600160401b03811115611131576111316151e0565b60405190808252806020026020018201604052801561115a578160200160208202803683370190505b50905060005b84518110156111d2576111a585828151811061117e5761117e615745565b602002602001015185838151811061119857611198615745565b6020026020010151610b42565b8282815181106111b7576111b7615745565b60209081029190910101526111cb816158bc565b9050611160565b509392505050565b61013354156112175761013a546111f190426157f3565b610134546111ff9190615806565b6101396000828254611211919061581d565b90915550505b4261013a55336000818152610132602052604081205490819003611239575050565b600080611245846130d3565b9150915082610139546112589190615806565b825561013c54670de0b6b3a764000090611273908590615806565b61127d9190615846565b815560006112896138db565b6001600160a01b0316336001600160a01b0316146113c95760006112b36112ae613926565b613971565b90506000611330737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ae91906158d5565b9050600061134061271083615806565b836101405488600101546113549190615806565b61135e9190615806565b6113689190615846565b90508015806113775750348111155b156113865761271093506113c1565b8061139361271034615806565b61139d9190615846565b935061096084116113c15760405163fae8279160e01b815260040160405180910390fd5b5050506113ce565b506127105b341561143d5760006113de613a4c565b6001600160a01b03163460405160006040518083038185875af1925050503d8060008114611428576040519150601f19603f3d011682016040523d82523d6000602084013e61142d565b606091505b505090508061143b57600080fd5b505b60006127108285600101546114529190615806565b61145c9190615846565b905080156114db5760018401805482900390556040516340c10f1960e01b8152735fe72ed557d8a02fff49b3b826792c765d5ce162906340c10f19906114a890899085906004016158f2565b600060405180830381600087803b1580156114c257600080fd5b505af11580156114d6573d6000803e3d6000fd5b505050505b600061156f6127108486600101546114f39190615806565b6114fd9190615846565b6040516370a0823160e01b8152306004820152600080516020615f1d833981519152906370a0823190602401602060405180830381865afa158015611546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156a919061590b565b613a97565b9050801561159b57600184018054829003905561159b600080516020615f1d8339815191528883613aad565b60408051838152602081018390526001600160a01b038916917f34fcbac0073d7c3d388e51312faf357774904998eeb8fca628b9e6f65ee1cbf7910160405180910390a250505050505050565b6115f0612ec8565b6001600160a01b0391909116600090815261014360205260409020805460ff1916911515919091179055565b61013354156116595761013a5461163390426157f3565b610134546116419190615806565b6101396000828254611653919061581d565b90915550505b4261013a556001600160a01b03821661168557604051635963709b60e01b815260040160405180910390fd5b33600081815261013260205260409020548211156116b65760405163fae8279160e01b815260040160405180910390fd5b6000806116c2836130d3565b6001600160a01b038516600090815261013260205260409020805487900390819055610139549294509092506116f791615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a76400009161172a91615806565b6117349190615846565b815561173f83613b03565b505060008061174d856130d3565b6001600160a01b03871660009081526101326020526040902080548701908190556101395492945090925061178191615806565b82556001600160a01b0385166000908152610132602052604090205461013c54670de0b6b3a7640000916117b491615806565b6117be9190615846565b81556117c985613b03565b5050826001600160a01b0316816001600160a01b03167f56b138798bd325f6cc79f626c4644aa2fd6703ecb0ab0fb168f883caed75bf328460405161181091815260200190565b60405180910390a3505050565b611825612ec8565b61014280546001600160a01b0319166001600160a01b0392909216919091179055565b611850612ec8565b610133541561188d5761013a5461186790426157f3565b610134546118759190615806565b6101396000828254611887919061581d565b90915550505b4261013a55828181146118b3576040516322ee6ae760e01b815260040160405180910390fd5b60005b8181101561190e576119068686838181106118d3576118d3615745565b90506020020160208101906118e891906151c3565b8585848181106118fa576118fa615745565b90506020020135613c0a565b6001016118b6565b505050505050565b61191e612ec8565b6110af6000613cff565b611930612ec8565b8060005b818110156119785761196f84848381811061195157611951615745565b905060200201602081019061196691906151c3565b61013690613d51565b50600101611934565b507fccb0a951adeec2b600e22533ea11a7aed53b518d6b6633101ad5a4a78065831c8383604051610caf92919061575b565b6119b2612ec8565b6110af613d66565b6119c2612ec8565b806000036119e35760405163fae8279160e01b815260040160405180910390fd5b6101318190556040518181527f03bbcf0896b4f83d0039a26c11ebb96733a8e027d9aa71d95753b6168dbb10ab906020015b60405180910390a150565b611a28612ec8565b611aa5336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a94919061590b565b6001600160a01b0384169190613aad565b50565b611ab3338383613da3565b5050565b611abf612ec8565b61012f84905561013083905561013f8290556101408190556040805185815260208101859052908101839052606081018290527f2c40e30353ae48a032fd20f1fece20031c1b80a2bc8512a2c172ff4de2e595199060800160405180910390a150505050565b611b2d6138db565b6001600160a01b0316336001600160a01b031614611b5e5760405163aedd0c1d60e01b815260040160405180910390fd5b6101335415611b9b5761013a54611b7590426157f3565b61013454611b839190615806565b6101396000828254611b95919061581d565b90915550505b4261013a556001600160a01b038216611bc757604051635963709b60e01b815260040160405180910390fd5b80600003611be85760405163fae8279160e01b815260040160405180910390fd5b600080611bf4846130d3565b6001600160a01b0386166000908152610132602052604090205461013954929450909250611c2191615806565b82556001600160a01b0384166000908152610132602052604090205461013c54670de0b6b3a764000091611c5491615806565b611c5e9190615846565b8155600181018054849190600090611c779084906157f3565b90915550506101425460405163095ea7b360e01b8152600080516020615f1d8339815191529163095ea7b391611cbb916001600160a01b03169087906004016158f2565b6020604051808303816000875af1158015611cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfe9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f992611d4692600080516020615f1d8339815191529289921690600401615941565b6060604051808303816000875af1158015611d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d899190615964565b50505050505050565b6060611d9f610136613e7b565b905090565b611dac6138db565b6001600160a01b0316336001600160a01b031614611ddd5760405163aedd0c1d60e01b815260040160405180910390fd5b6101335415611e1a5761013a54611df490426157f3565b61013454611e029190615806565b6101396000828254611e14919061581d565b90915550505b4261013a556001600160a01b038316611e4657604051635963709b60e01b815260040160405180910390fd5b801580611e5557506101315481115b15611e735760405163fae8279160e01b815260040160405180910390fd5b611e7f61013683613e88565b611e9c5760405163bc7fd0cf60e01b815260040160405180910390fd5b735fe72ed557d8a02fff49b3b826792c765d5ce1626379cc67903361012d54611ec59085615806565b6040518363ffffffff1660e01b8152600401611ee29291906158f2565b600060405180830381600087803b158015611efc57600080fd5b505af1158015611f10573d6000803e3d6000fd5b50505050600080611f20856130d3565b6001600160a01b0387166000908152610132602052604090205461013954929450909250611f4d91615806565b82556001600160a01b0385166000908152610132602052604090205461013c54670de0b6b3a764000091611f8091615806565b611f8a9190615846565b81600001819055506000670de0b6b3a7640000600080516020615f1d8339815191526001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200d9190615992565b61201890600a615a99565b61012f546120269190615806565b6120309190615846565b90508082600101541061216b578082600101600082825461205191906157f3565b90915550506101425460405163095ea7b360e01b8152600080516020615f1d8339815191529163095ea7b391612095916001600160a01b03169085906004016158f2565b6020604051808303816000875af11580156120b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d89190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f99261212092600080516020615f1d8339815191529287921690600401615941565b6060604051808303816000875af115801561213f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121639190615964565b50505061230c565b6000670de0b6b3a7640000866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d89190615992565b6121e390600a615a99565b61012f546121f19190615806565b6121fb9190615846565b90506122126001600160a01b038716333084613eaa565b6101425460405163095ea7b360e01b81526001600160a01b038881169263095ea7b392612247929091169085906004016158f2565b6020604051808303816000875af1158015612266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061228a9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f9926122c4928b9287921690600401615941565b6060604051808303816000875af11580156122e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123079190615964565b505050505b6123163385613c0a565b856001600160a01b03167f6b1d99469ed62a423d7e402bfa68a467261ca2229127c55045ee41e5d9a0f21d8560405161235191815260200190565b60405180910390a2505050505050565b600054610100900460ff16158080156123815750600054600160ff909116105b8061239b5750303b15801561239b575060005460ff166001145b6123fe5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610ba9565b6000805460ff191660011790558015612421576000805461ff0019166101001790555b6001600160a01b03821661244857604051635963709b60e01b815260040160405180910390fd5b61012e80546001600160a01b0319166001600160a01b0384161790556040805160c0810182526001815260056020820152600a918101919091526019606082015260326080820152606460a08201526124a690610138906006614f9f565b5067a688906bd8b0000061012d5567d02ab486cedc000061012f556124db610136600080516020615f1d833981519152613d51565b506124fc61013673dac17f958d2ee523a2206206994597c13d831ec7613d51565b5061251d610136736b175474e89094c44da98b954eedeac495271d0f613d51565b506107d0610130556064610131556125406201518067016345785d8a0000615846565b610134556203d09061013555612554613ee2565b612575604051806060016040528060248152602001615f3d60249139613f11565b61257d613f41565b8015611ab3576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b61013354156126035761013a546125dd90426157f3565b610134546125eb9190615806565b61013960008282546125fd919061581d565b90915550505b4261013a5561012d543390735fe72ed557d8a02fff49b3b826792c765d5ce162906379cc67909083906126369086615806565b6040518363ffffffff1660e01b81526004016126539291906158f2565b600060405180830381600087803b15801561266d57600080fd5b505af1158015612681573d6000803e3d6000fd5b50505050600080612691836130d3565b6001600160a01b03851660009081526101326020526040902054610139549294509092506126be91615806565b82556001600160a01b0383166000908152610132602052604090205461013c54670de0b6b3a7640000916126f191615806565b6126fb9190615846565b815561270886868661345e565b856001600160a01b0316836001600160a01b03167fab8530f87dc9b59234c4623bf917212bb2536d647574c8e7e5da92c2ede0c9f88660405161108f91815260200190565b612755612ec8565b61012d55565b612763612ec8565b61013354156127a05761013a5461277a90426157f3565b610134546127889190615806565b610139600082825461279a919061581d565b90915550505b4261013a558051610134556020015161013555565b6127bd612ec8565b6001600160a01b0381166127e457604051635963709b60e01b815260040160405180910390fd5b61012e80546001600160a01b0319166001600160a01b0383169081179091556040519081527ffb26c00f7d7dba814173c8a2db3466cb26ee25fdcec8867af7da3aa1f296addd90602001611a15565b6001600160a01b03851633148061284f575061284f8533610a2f565b61286b5760405162461bcd60e51b8152600401610ba99061585a565b610efc8585858585613f70565b612880612ec8565b6001600160a01b0381166128e55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ba9565b611aa581613cff565b6001600160a01b0381166000908152610132602052604081205481908190819081908015612b82576001600160a01b038716600090815261013b60209081526040808320815180830190925280548252600101549181019190915261013a5490919061295a90426157f3565b610134546129689190615806565b61013954612976919061581d565b90506000806129848b6140ac565b9092509050600081612996848261581d565b6001600160a01b038e16600090815261013b60205260409020546129ba8988615806565b6129c491906157f3565b6129ce9190615806565b6129d89190615846565b905061271061013054826129ec9190615806565b6129f69190615846565b818660200151612a06919061581d565b612a1091906157f3565b6001600160a01b038d16600090815261013d6020908152604091829020825180840190935280548084526001909101549183019190915261013c54929d509096509450670de0b6b3a76400009350612a6b9250869150615806565b612a759190615846565b8260200151612a84919061581d565b612a8e91906157f3565b9550506000612a9e6112ae613926565b90506000612af7737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b9050612710826101405461013f54612b0f919061581d565b612b19908b615806565b612b239190615806565b612b2d9190615846565b955061271061013f5489612b419190615806565b612b4b9190615846565b9450612b5961271082615806565b82610140548a612b699190615806565b612b739190615806565b612b7d9190615846565b935050505b5091939590929450565b61013f5461014054600080612ba26112ae613926565b9150612bf9737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b905090919293565b34600003612c0b57565b604080516002808252606082018352600092602083019080368337019050509050737a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca291906158d5565b81600081518110612cb557612cb5615745565b60200260200101906001600160a01b031690816001600160a01b031681525050600080516020615f1d83398151915281600181518110612cf757612cf7615745565b6001600160a01b0392909216602092830291909101909101526040516370a0823160e01b8152306004820152600090600080516020615f1d833981519152906370a0823190602401602060405180830381865afa158015612d5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d80919061590b565b60405163b6f9de9560e01b8152909150737a250d5630b4cf539739df2c5dacb4c659f2488d9063b6f9de95903490612dc390600090879030904290600401615aa8565b6000604051808303818588803b158015612ddc57600080fd5b505af1158015612df0573d6000803e3d6000fd5b50506040516370a0823160e01b815230600482015260009350849250600080516020615f1d83398151915291506370a0823190602401602060405180830381865afa158015612e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e67919061590b565b612e7191906157f3565b9050600061013354118015612e865750600081115b15612ec35761013354612ea1670de0b6b3a764000083615806565b612eab9190615846565b61013c6000828254612ebd919061581d565b90915550505b505050565b60fb546001600160a01b031633146110af5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ba9565b6000612f37836001600160a01b03841661419b565b9392505050565b606060678054612f4d90615add565b80601f0160208091040260200160405190810160405280929190818152602001828054612f7990615add565b8015612fc65780601f10612f9b57610100808354040283529160200191612fc6565b820191906000526020600020905b815481529060010190602001808311612fa957829003601f168201915b50505050509050919050565b60606000612fdf8361428e565b60010190506000816001600160401b03811115612ffe57612ffe6151e0565b6040519080825280601f01601f191660200182016040528015613028576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461303257509392505050565b61013e54604080516369576d8960e01b815290516000926001600160a01b0316916369576d899160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9f91906158d5565b6001600160a01b0381166000908152610132602090815260408083205461013b909252822091908180613105866140ac565b9092509050600081613117848261581d565b875461013954613128908890615806565b61313291906157f3565b61313c9190615806565b6131469190615846565b90506000612710610130548361315c9190615806565b6131669190615846565b905061317281836157f3565b876001016000828254613185919061581d565b909155505080156132085761012e546040516340c10f1960e01b8152735fe72ed557d8a02fff49b3b826792c765d5ce162916340c10f19916131d5916001600160a01b03169085906004016158f2565b600060405180830381600087803b1580156131ef57600080fd5b505af1158015613203573d6000803e3d6000fd5b505050505b6001600160a01b038816600090815261013d60205260409020805461013c5491975090670de0b6b3a764000090613240908890615806565b61324a9190615846565b61325491906157f3565b866001016000828254613267919061581d565b925050819055505050505050915091565b81518351146132da5760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610ba9565b6001600160a01b0384166133005760405162461bcd60e51b8152600401610ba990615b17565b3361330f818787878787614366565b60005b84518110156133f857600085828151811061332f5761332f615745565b60200260200101519050600085838151811061334d5761334d615745565b60209081029190910181015160008481526065835260408082206001600160a01b038e16835290935291909120549091508181101561339e5760405162461bcd60e51b8152600401610ba990615b5c565b60008381526065602090815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906133dd90849061581d565b92505081905550505050806133f1906158bc565b9050613312565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051613448929190615ba6565b60405180910390a461190e818787878787614603565b6001600160a01b03831661348557604051635963709b60e01b815260040160405180910390fd5b80158061349457506101315481115b156134b25760405163fae8279160e01b815260040160405180910390fd5b6134be61013683613e88565b6134db5760405163bc7fd0cf60e01b815260040160405180910390fd5b600061013d6000856001600160a01b03166001600160a01b0316815260200190815260200160002090506000670de0b6b3a7640000600080516020615f1d8339815191526001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135809190615992565b61358b90600a615a99565b61012f546135999190615806565b6135a39190615846565b9050808260010154106136de57808260010160008282546135c491906157f3565b90915550506101425460405163095ea7b360e01b8152600080516020615f1d8339815191529163095ea7b391613608916001600160a01b03169085906004016158f2565b6020604051808303816000875af1158015613627573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364b9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f99261369392600080516020615f1d8339815191529287921690600401615941565b6060604051808303816000875af11580156136b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d69190615964565b50505061387f565b6000670de0b6b3a7640000856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613727573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374b9190615992565b61375690600a615a99565b61012f546137649190615806565b61376e9190615846565b90506137856001600160a01b038616333084613eaa565b6101425460405163095ea7b360e01b81526001600160a01b038781169263095ea7b3926137ba929091169085906004016158f2565b6020604051808303816000875af11580156137d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137fd9190615924565b506101425461014154604051631c4009f960e01b81526001600160a01b0392831692631c4009f992613837928a9287921690600401615941565b6060604051808303816000875af1158015613856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387a9190615964565b505050505b610efc8584613c0a565b61389161475e565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b61013e546040805163564c123960e11b815290516000926001600160a01b03169163ac9824729160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b61013e5460408051630ef7063b60e41b815290516000926001600160a01b03169163ef7063b09160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b61013e546040805163175228df60e11b815290516000926001600160a01b031691632ea451be9160048083019260209291908290030181865afa1580156139bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139e091906158d5565b60405163eb9d14a960e01b81526001600160a01b038481166004830152919091169063eb9d14a990602401602060405180830381865afa158015613a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd7919061590b565b61013e5460408051631d8cf42560e11b815290516000926001600160a01b031691633b19e84a9160048083019260209291908290030181865afa1580156130af573d6000803e3d6000fd5b6000818310613aa65781612f37565b5090919050565b612ec38363a9059cbb60e01b8484604051602401613acc9291906158f2565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526147a7565b6001600160a01b03811660009081526101326020526040812054905b6006811015612ec3576000600182600660ff160303905060006101388260068110613b4c57613b4c615745565b602081049091015460ff601f9092166101000a9004168481613b7057613b70615830565b0490506000613b7f8684610b42565b905080821115613bab57613ba686848385036040518060200160405280600081525061487c565b613bc0565b80821015613bc057613bc08684848403614998565b6101388360068110613bd457613bd4615745565b602081049091015460ff601f9092166101000a9004168581613bf857613bf8615830565b0694505060019092019150613b1f9050565b600080613c16846130d3565b6001600160a01b0386166000908152610132602052604090208054860190556101338054860190819055610135549294509092501115613c895760026101346000016000828254613c679190615846565b9091555050610135805460029190600090613c83908490615806565b90915550505b6001600160a01b0384166000908152610132602052604090205461013954613cb19190615806565b82556001600160a01b0384166000908152610132602052604090205461013c54670de0b6b3a764000091613ce491615806565b613cee9190615846565b8155613cf984613b03565b50505050565b60fb80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000612f37836001600160a01b038416614b2c565b613d6e614b7b565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586138be3390565b816001600160a01b0316836001600160a01b031603613e165760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608401610ba9565b6001600160a01b03838116600081815260666020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c319101611810565b60606000612f3783614bc1565b6001600160a01b03811660009081526001830160205260408120541515612f37565b6040516001600160a01b0380851660248301528316604482015260648101829052613cf99085906323b872dd60e01b90608401613acc565b600054610100900460ff16613f095760405162461bcd60e51b8152600401610ba990615bd4565b6110af614c1c565b600054610100900460ff16613f385760405162461bcd60e51b8152600401610ba990615bd4565b611aa581614c4f565b600054610100900460ff16613f685760405162461bcd60e51b8152600401610ba990615bd4565b6110af614c7f565b6001600160a01b038416613f965760405162461bcd60e51b8152600401610ba990615b17565b336000613fa285614caf565b90506000613faf85614caf565b9050613fbf838989858589614366565b60008681526065602090815260408083206001600160a01b038c168452909152902054858110156140025760405162461bcd60e51b8152600401610ba990615b5c565b60008781526065602090815260408083206001600160a01b038d8116855292528083208985039055908a1682528120805488929061404190849061581d565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46140a1848a8a8a8a8a614cfa565b505050505050505050565b60008061013e60009054906101000a90046001600160a01b03166001600160a01b03166369576d896040518163ffffffff1660e01b8152600401602060405180830381865afa158015614103573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061412791906158d5565b60405163359a2fed60e01b81526001600160a01b038581166004830152919091169063359a2fed906024016040805180830381865afa15801561416e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141929190615c1f565b91509150915091565b600081815260018301602052604081205480156142845760006141bf6001836157f3565b85549091506000906141d3906001906157f3565b90508181146142385760008660000182815481106141f3576141f3615745565b906000526020600020015490508087600001848154811061421657614216615745565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061424957614249615c43565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610bd7565b6000915050610bd7565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106142cd5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef810000000083106142f9576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061431757662386f26fc10000830492506010015b6305f5e100831061432f576305f5e100830492506008015b612710831061434357612710830492506004015b60648310614355576064830492506002015b600a8310610bd75760010192915050565b61013354156143a35761013a5461437d90426157f3565b6101345461438b9190615806565b610139600082825461439d919061581d565b90915550505b4261013a556143b6868686868686614db5565b6001600160a01b0386163b15614405576001600160a01b0386166000908152610143602052604090205460ff1661440057604051635ffde35f60e11b815260040160405180910390fd5b614456565b6001600160a01b0384163b1515801561443857506001600160a01b0384166000908152610143602052604090205460ff16155b1561445657604051635ffde35f60e11b815260040160405180910390fd5b6001600160a01b038516158061447357506001600160a01b038416155b61190e57600080614483876130d3565b91509150600080614493886130d3565b90925090506000805b8851811015614510578781815181106144b7576144b7615745565b60200260200101516101388a83815181106144d4576144d4615745565b6020026020010151600681106144ec576144ec615745565b602081049091015460ff601f9092166101000a90041602919091019060010161449c565b506001600160a01b03808b166000818152610132602052604080822080548690038155938d16825281208054850190555254610139546145509190615806565b85556001600160a01b038a166000908152610132602052604090205461013c54670de0b6b3a76400009161458391615806565b61458d9190615846565b84556001600160a01b03891660009081526101326020526040902054610139546145b79190615806565b83556001600160a01b0389166000908152610132602052604090205461013c54670de0b6b3a7640000916145ea91615806565b6145f49190615846565b90915550505050505050505050565b6001600160a01b0384163b1561190e5760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906146479089908990889088908890600401615c59565b6020604051808303816000875af1925050508015614682575060408051601f3d908101601f1916820190925261467f91810190615cb7565b60015b61472e5761468e615cd4565b806308c379a0036146c757506146a2615cf0565b806146ad57506146c9565b8060405162461bcd60e51b8152600401610ba9919061510b565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b6064820152608401610ba9565b6001600160e01b0319811663bc197c8160e01b14611d895760405162461bcd60e51b8152600401610ba990615d79565b60975460ff166110af5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ba9565b60006147fc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e1d9092919063ffffffff16565b905080516000148061481d57508080602001905181019061481d9190615924565b612ec35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ba9565b6001600160a01b0384166148dc5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b6064820152608401610ba9565b3360006148e885614caf565b905060006148f585614caf565b905061490683600089858589614366565b60008681526065602090815260408083206001600160a01b038b1684529091528120805487929061493890849061581d565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4611d8983600089898989614cfa565b6001600160a01b0383166149fa5760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610ba9565b336000614a0684614caf565b90506000614a1384614caf565b9050614a3383876000858560405180602001604052806000815250614366565b60008581526065602090815260408083206001600160a01b038a16845290915290205484811015614ab25760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610ba9565b60008681526065602090815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4604080516020810190915260009052611d89565b6000818152600183016020526040812054614b7357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610bd7565b506000610bd7565b60975460ff16156110af5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610ba9565b606081600001805480602002602001604051908101604052809291908181526020018280548015612fc657602002820191906000526020600020905b815481526020019060010190808311614bfd5750505050509050919050565b600054610100900460ff16614c435760405162461bcd60e51b8152600401610ba990615bd4565b6097805460ff19169055565b600054610100900460ff16614c765760405162461bcd60e51b8152600401610ba990615bd4565b611aa581614e34565b600054610100900460ff16614ca65760405162461bcd60e51b8152600401610ba990615bd4565b6110af33613cff565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110614ce957614ce9615745565b602090810291909101015292915050565b6001600160a01b0384163b1561190e5760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190614d3e9089908990889088908890600401615dc1565b6020604051808303816000875af1925050508015614d79575060408051601f3d908101601f19168201909252614d7691810190615cb7565b60015b614d855761468e615cd4565b6001600160e01b0319811663f23a6e6160e01b14611d895760405162461bcd60e51b8152600401610ba990615d79565b60975460ff161561190e5760405162461bcd60e51b815260206004820152602c60248201527f455243313135355061757361626c653a20746f6b656e207472616e736665722060448201526b1dda1a5b19481c185d5cd95960a21b6064820152608401610ba9565b6060614e2c8484600085614e40565b949350505050565b6067611ab38282615e41565b606082471015614ea15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610ba9565b600080866001600160a01b03168587604051614ebd9190615f00565b60006040518083038185875af1925050503d8060008114614efa576040519150601f19603f3d011682016040523d82523d6000602084013e614eff565b606091505b5091509150614f1087838387614f1b565b979650505050505050565b60608315614f8a578251600003614f83576001600160a01b0385163b614f835760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ba9565b5081614e2c565b614e2c83838151156146ad5781518083602001fd5b6001830191839082156150225791602002820160005b83821115614ff357835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302614fb5565b80156150205782816101000a81549060ff0219169055600101602081600001049283019260010302614ff3565b505b5061502e929150615032565b5090565b5b8082111561502e5760008155600101615033565b6001600160a01b0381168114611aa557600080fd5b6000806040838503121561506f57600080fd5b823561507a81615047565b946020939093013593505050565b6001600160e01b031981168114611aa557600080fd5b6000602082840312156150b057600080fd5b8135612f3781615088565b60005b838110156150d65781810151838201526020016150be565b50506000910152565b600081518084526150f78160208601602086016150bb565b601f01601f19169290920160200192915050565b602081526000612f3760208301846150df565b60008083601f84011261513057600080fd5b5081356001600160401b0381111561514757600080fd5b6020830191508360208260051b850101111561516257600080fd5b9250929050565b6000806020838503121561517c57600080fd5b82356001600160401b0381111561519257600080fd5b61519e8582860161511e565b90969095509350505050565b6000602082840312156151bc57600080fd5b5035919050565b6000602082840312156151d557600080fd5b8135612f3781615047565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b038111828210171561521b5761521b6151e0565b6040525050565b60006001600160401b0382111561523b5761523b6151e0565b5060051b60200190565b600082601f83011261525657600080fd5b8135602061526382615222565b60405161527082826151f6565b83815260059390931b850182019282810191508684111561529057600080fd5b8286015b848110156152ab5780358352918301918301615294565b509695505050505050565b600082601f8301126152c757600080fd5b81356001600160401b038111156152e0576152e06151e0565b6040516152f7601f8301601f1916602001826151f6565b81815284602083860101111561530c57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561534157600080fd5b853561534c81615047565b9450602086013561535c81615047565b935060408601356001600160401b038082111561537857600080fd5b61538489838a01615245565b9450606088013591508082111561539a57600080fd5b6153a689838a01615245565b935060808801359150808211156153bc57600080fd5b506153c9888289016152b6565b9150509295509295909350565b6000806000606084860312156153eb57600080fd5b83356153f681615047565b9250602084013561540681615047565b929592945050506040919091013590565b6000806040838503121561542a57600080fd5b82356001600160401b038082111561544157600080fd5b818501915085601f83011261545557600080fd5b8135602061546282615222565b60405161546f82826151f6565b83815260059390931b850182019282810191508984111561548f57600080fd5b948201945b838610156154b65785356154a781615047565b82529482019490820190615494565b965050860135925050808211156154cc57600080fd5b506154d985828601615245565b9150509250929050565b600081518084526020808501945080840160005b83811015615513578151875295820195908201906001016154f7565b509495945050505050565b602081526000612f3760208301846154e3565b8015158114611aa557600080fd5b6000806040838503121561555257600080fd5b823561555d81615047565b9150602083013561556d81615531565b809150509250929050565b6000806000806040858703121561558e57600080fd5b84356001600160401b03808211156155a557600080fd5b6155b18883890161511e565b909650945060208701359150808211156155ca57600080fd5b506155d78782880161511e565b95989497509550505050565b600080600080608085870312156155f957600080fd5b5050823594602084013594506040840135936060013592509050565b600081518084526020808501945080840160005b838110156155135781516001600160a01b031687529582019590820190600101615629565b602081526000612f376020830184615615565b60006040828403121561567357600080fd5b604051604081018181106001600160401b0382111715615695576156956151e0565b604052823581526020928301359281019290925250919050565b600080604083850312156156c257600080fd5b82356156cd81615047565b9150602083013561556d81615047565b600080600080600060a086880312156156f557600080fd5b853561570081615047565b9450602086013561571081615047565b9350604086013592506060860135915060808601356001600160401b0381111561573957600080fd5b6153c9888289016152b6565b634e487b7160e01b600052603260045260246000fd5b60208082528181018390526000908460408401835b868110156152ab57823561578381615047565b6001600160a01b031682529183019190830190600101615770565b600083516157b08184602088016150bb565b8351908301906157c48183602088016150bb565b64173539b7b760d91b9101908152600501949350505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bd757610bd76157dd565b8082028115828204841417610bd757610bd76157dd565b80820180821115610bd757610bd76157dd565b634e487b7160e01b600052601260045260246000fd5b60008261585557615855615830565b500490565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b6000826158b7576158b7615830565b500690565b6000600182016158ce576158ce6157dd565b5060010190565b6000602082840312156158e757600080fd5b8151612f3781615047565b6001600160a01b03929092168252602082015260400190565b60006020828403121561591d57600080fd5b5051919050565b60006020828403121561593657600080fd5b8151612f3781615531565b6001600160a01b0393841681526020810192909252909116604082015260600190565b60008060006060848603121561597957600080fd5b8351925060208401519150604084015190509250925092565b6000602082840312156159a457600080fd5b815160ff81168114612f3757600080fd5b600181815b808511156159f05781600019048211156159d6576159d66157dd565b808516156159e357918102915b93841c93908002906159ba565b509250929050565b600082615a0757506001610bd7565b81615a1457506000610bd7565b8160018114615a2a5760028114615a3457615a50565b6001915050610bd7565b60ff841115615a4557615a456157dd565b50506001821b610bd7565b5060208310610133831016604e8410600b8410161715615a73575081810a610bd7565b615a7d83836159b5565b8060001904821115615a9157615a916157dd565b029392505050565b6000612f3760ff8416836159f8565b848152608060208201526000615ac16080830186615615565b6001600160a01b03949094166040830152506060015292915050565b600181811c90821680615af157607f821691505b602082108103615b1157634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b604081526000615bb960408301856154e3565b8281036020840152615bcb81856154e3565b95945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b60008060408385031215615c3257600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b0386811682528516602082015260a060408201819052600090615c85908301866154e3565b8281036060840152615c9781866154e3565b90508281036080840152615cab81856150df565b98975050505050505050565b600060208284031215615cc957600080fd5b8151612f3781615088565b600060033d1115615ced5760046000803e5060005160e01c5b90565b600060443d1015615cfe5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615d2d57505050505090565b8285019150815181811115615d455750505050505090565b843d8701016020828501011115615d5f5750505050505090565b615d6e602082860101876151f6565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090614f10908301846150df565b601f821115612ec357600081815260208120601f850160051c81016020861015615e225750805b601f850160051c820191505b8181101561190e57828155600101615e2e565b81516001600160401b03811115615e5a57615e5a6151e0565b615e6e81615e688454615add565b84615dfb565b602080601f831160018114615ea35760008415615e8b5750858301515b600019600386901b1c1916600185901b17855561190e565b600085815260208120601f198616915b82811015615ed257888601518255948401946001909101908401615eb3565b5085821015615ef05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251615f128184602087016150bb565b919091019291505056fe000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4868747470733a2f2f6d657461646174612e7368657a6d752e696f2f677561726469616e2fa26469706673582212203bed9aa80e86a391932afada7ce910cac8f826be26183c12dd3f4b19c35b55c964736f6c63430008110033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.