ETH Price: $3,093.59 (+8.73%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BNBMagaPresale

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : BNBMAGAPreale.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

error ZeroAddress(string parameter);
error InvalidStage(uint256 stageId);
error InvalidStageWindow(uint256 stageId);
error StageOverlap(uint256 stageId);
error StageSupplyTooLow(uint256 stageId, uint256 supply, uint256 sold);
error StageCapExceeded();
error InvalidAmount(string parameter);
error SaleNotActive();
error SyncFeeNotPermitted();
error SyncFeeCapExceeded(uint256 provided, uint256 maxAllowed);
error SyncFeeInsufficientValue(uint256 required, uint256 sent);
error ReferralFloorNotMet(uint256 floorNeeded, uint256 pending);
error UnsupportedChain(uint256 chainId);
error NothingToWithdraw();
error PaymentTransferFailed();
error PublicSaleLocked();
error PublicSaleNotActive();
error BelowMinimumBuy();
error WithdrawalCooldownInProgress(uint256 nextAllowed);
error ReferralLiabilityTooLow();
error SplitAccountingMismatch();
error SaleTokensLocked(uint256 requested, uint256 unlocked);
error ImmutableToken();
error ImmutablePriceFeed();

// Staking contract interface for auto-stake on buy
interface IBNBMagaStaking {
    /// Creates a staking position for `user` using `amount` tokens
    /// that are already held by the staking contract.    
    function onPresaleReceive(address user, uint256 amount, uint8 poolId)
        external
        returns (uint256);
}

/// @title BNBMAGA presale & public sale
/// @notice Handles staged presale, public sale, referrals, and auto-staking.
contract BNBMagaPresale is Ownable, ReentrancyGuard, Pausable {
    using SafeERC20 for IERC20;
    using ECDSA for bytes32;

    // ===== Core config =====
    IERC20 public token;
    IERC20Metadata public tokenMetadata;
    AggregatorV3Interface public priceFeed;
    address public paymentAddress;

    // Total token allocation used across presale + public sale
    uint256 public presaleTokenAmount = 1_400_000_000e18;
    uint256 public totalSold = 0;
    bool    public presaleActive = true;

    // Minimum buy size in USD (1e18)
    uint256 public minimumBuyUsd = 5e18;

    // Referral config / state
    uint256[] public referralBuyerTiers = [930, 430, 180, 80, 40, 15, 5, 0];
    uint256[] public referralBonuses    = [ 70,  50,  40, 30, 25, 20, 15, 10];

    mapping(address => uint256) public referralCounts;
    mapping(address => uint256) public referralBonus; // in native currency (ETH/BNB)
    uint256 public referralLiability;
    mapping(address => uint256) public lastWithdrawal;
    mapping(address => uint256) public totalWithdrawn;

    uint256 public withdrawalCooldown = 6 hours;
    uint256 public minReferralPayoutEth;
    uint256 public minReferralPayoutBnb;

    // Attestation/signature
    bytes32 public constant REFERRAL_PROJECT_ID = keccak256("BNBMAGA-REFERRAL-v1");
    address public aggregatorSigner;
    address public stampFeeRecipient;
    uint16  public maxSyncFeeBps = 300; // 3%
    mapping(address => uint256) public lastGlobalCount;

    // ===== Events =====
    event ReferralPurchase(address indexed referrer, address indexed buyer, uint256 usdAmount, uint256 nativeCurrencyPaid, uint256 cashbackAmount, uint256 bonusPercent, uint256 newReferralCount);
    event ReferralWithdrawn(address indexed referrer, uint256 amount, uint256 timestamp, uint256 totalWithdrawnToDate);
    event TierCrossed(address indexed referrer, uint8 fromTier, uint8 toTier, uint256 syncFee, uint256 attestedGlobalCount);
    event FundsWithdrawn(address indexed to, uint256 amount);
    event TokensWithdrawn(address indexed to, uint256 amount);
    event MinReferralPayoutEthUpdated(uint256 oldV, uint256 newV);
    event MinReferralPayoutBnbUpdated(uint256 oldV, uint256 newV);

    // ===== Staking wiring =====
    address public staking; // BNBMagaStaking contract address

    event StakedOnPurchase(address indexed buyer, uint256 indexed positionId, uint8 poolId, uint256 amount);

    function setStaking(address _staking) external onlyOwner {
        _nonZero(_staking, "staking");
        staking = _staking;
    }


    // ===== Stages =====
    struct Stage {
        uint256 id;
        uint256 bonus;   // %
        uint256 price;   // USD with 18 decimals
        uint256 start;   // timestamp
        uint256 end;     // timestamp
        uint256 supply;  // token units (token decimals)
        uint256 sold;    // token units sold in this stage
    }
    mapping(uint256 => Stage) public stages;
    uint256 public maxStage = 9;
    uint256 public currentStageId = 0;

    // Last stage id we’ve already rolled over from.
   uint256 private rolloverCursor;

    // --- internal guards ---
    function _nonZero(address value, string memory tag) private pure {
        if (value == address(0)) revert ZeroAddress(tag);
    }

    function _positive(uint256 value, string memory tag) private pure {
        if (value == 0) revert InvalidAmount(tag);
    }

    function _assertStageWindow(uint256 id, uint256 start, uint256 end) private pure {
        if (start == 0 || end == 0 || start >= end) revert InvalidStageWindow(id);
    }

    function _assertStageOrdering(uint256 id, uint256 start, uint256 end) private view {
        if (id > 1) {
            Stage memory prev = stages[id - 1];
            if (prev.id == id - 1 && start < prev.end) revert StageOverlap(id);
        }
        if (id < currentStageId) {
            Stage memory nextS = stages[id + 1];
            if (nextS.id == id + 1 && end > nextS.start) revert StageOverlap(id);
        }
    }
 
    // Update min referral payout threshold for ETH or BNB.
    function _setReferralFloor(bool isEth, uint256 value) private {
        _positive(value, isEth ? "minReferralEth" : "minReferralBnb");
        if (isEth) {
            uint256 old = minReferralPayoutEth;
            minReferralPayoutEth = value;
            emit MinReferralPayoutEthUpdated(old, value);
        } else {
            uint256 old = minReferralPayoutBnb;
            minReferralPayoutBnb = value;
            emit MinReferralPayoutBnbUpdated(old, value);
        }
    }


    event StageTimeUpdated(uint256 indexed id, uint256 newStart, uint256 newEnd);
    event StageSupplyUpdated(uint256 indexed id, uint256 oldSupply, uint256 newSupply);
    event StageConfigured(uint256 indexed id, uint256 bonus, uint256 price, uint256 start, uint256 end, uint256 supply);
    event StageRollover(uint256 indexed fromId, uint256 indexed toId, uint256 amount);

    // ===== Public Sale (start-only, no end; Option A) =====
    struct PublicSale {
        uint256 price;   // USD 1e18
        uint256 bonus;   // %
        uint256 start;   // timestamp; no end
        bool enabled;    // gate
    }
    PublicSale public publicSale;

    event PublicSaleConfigured(uint256 price, uint256 bonus, uint256 start, bool enabled);
    event PublicSalePriceUpdated(uint256 oldPrice, uint256 newPrice);

    // ===== Withdrawal history =====
    struct WithdrawalRecord {
        uint256 amount;
        uint256 timestamp;
        uint256 blockNumber;
    }
    mapping(address => WithdrawalRecord[]) public withdrawalHistory;

    // ===== Constructor =====
    constructor(
        address _payment,
        address _token,
        address _priceFeed,
        uint256 _minReferralPayoutEth,
        uint256 _minReferralPayoutBnb
    ) Ownable(msg.sender) {
        _nonZero(_payment, "payment");
        _nonZero(_token, "token");
        _nonZero(_priceFeed, "priceFeed");
        _positive(_minReferralPayoutEth, "minReferralEth");
        _positive(_minReferralPayoutBnb, "minReferralBnb");

        token = IERC20(_token);
        tokenMetadata = IERC20Metadata(_token);
        paymentAddress = _payment;
        priceFeed = AggregatorV3Interface(_priceFeed);
        require(priceFeed.decimals() <= 18, "feed decimals > 18");

        // Seed stages
        stages[1] = Stage(1, 100, 3000000000000000, 1764768445, 1767360445, 140000000e18, 0);
        stages[2] = Stage(2, 80,  5000000000000000, 1767360445, 1769952445, 140000000e18, 0);
        stages[3] = Stage(3, 65,  6000000000000000, 1769952445, 1771248445, 140000000e18, 0);
        stages[4] = Stage(4, 55,  7000000000000000, 1771248445, 1772544445, 140000000e18, 0);
        stages[5] = Stage(5, 40,  8000000000000000, 1772544445, 1773840445, 140000000e18, 0);
        stages[6] = Stage(6, 25,  9000000000000000, 1773840445, 1775136445, 140000000e18, 0);
        stages[7] = Stage(7, 17, 10000000000000000, 1775136445, 1776432445, 140000000e18, 0);
        stages[8] = Stage(8, 11, 12000000000000000, 1776432445, 1777728445, 140000000e18, 0);
        stages[9] = Stage(9,  8, 15000000000000000, 1777728445, 1779024445, 140000000e18, 0);
        currentStageId = 9;

        minReferralPayoutEth = _minReferralPayoutEth;
        minReferralPayoutBnb = _minReferralPayoutBnb;
    }

    // ===== Admin: pause =====
    function pause() external onlyOwner { _pause(); }
    function unpause() external onlyOwner { _unpause(); }

    // ===== Admin: basic config =====
    function setToken(address) external view onlyOwner {
        revert ImmutableToken();
    }

    function setPriceFeed(address) external view onlyOwner {
        revert ImmutablePriceFeed();
    }

    function setPaymentAddress(address _paymentAddress) external onlyOwner {
        _nonZero(_paymentAddress, "payment");
        paymentAddress = _paymentAddress;
    }

    function setPresaleTokenAmount(uint256 _amount) external onlyOwner {
        presaleTokenAmount = _amount;
    }

    function flipPresaleActive() external onlyOwner {
        presaleActive = !presaleActive;
    }

    function setMaxStage(uint256 _maxStage) external onlyOwner {
        maxStage = _maxStage;
    }

    function setTotalSold(uint256 _totalSold) external onlyOwner {
        totalSold = _totalSold;
    }

    function setMinimumBuyUsd(uint256 _minimumUsd) external onlyOwner {
        _positive(_minimumUsd, "minimumBuyUsd");
        minimumBuyUsd = _minimumUsd;
    }

    function setAggregatorSigner(address _signer) external onlyOwner {
        _nonZero(_signer, "signer");
        aggregatorSigner = _signer;
    }

    function setStampFeeRecipient(address _recipient) external onlyOwner {
        _nonZero(_recipient, "feeRecipient");
        stampFeeRecipient = _recipient;
    }

    function setMaxSyncFeeBps(uint16 bps) external onlyOwner {
        require(bps <= 10_000, "bps>100%");
        maxSyncFeeBps = bps;
    }
     
    function setMinReferralPayoutEth(uint256 v) external onlyOwner {
        _setReferralFloor(true, v);
    }

    function setMinReferralPayoutBnb(uint256 v) external onlyOwner {
        _setReferralFloor(false, v);
    }

    // ===== Chainlink oracle =====
    function getNativeCurrencyPrice() public view returns (int256) {
        (uint80 roundId, int256 price,, uint256 updatedAt, uint80 answeredInRound) = priceFeed.latestRoundData();
        require(price > 0, "bad price");
        require(block.timestamp - updatedAt <= 3600, "stale price");
        require(answeredInRound >= roundId && updatedAt > 0, "round incomplete");
        return price;
    }

    function weiToUsd(uint256 weiAmount) public view returns (uint256) {
        int256 nativePriceUsd = getNativeCurrencyPrice();
        return (weiAmount * uint256(nativePriceUsd) * 10**(18 - priceFeed.decimals())) / 1e18;
    }

    // ===== Referral helpers =====
    function getReferralBonusPercentage(uint256 totalBuyers) public view returns (uint256) {
        for (uint256 i = 0; i < referralBuyerTiers.length; i++) {
            if (totalBuyers >= referralBuyerTiers[i]) return referralBonuses[i];
        }
        return 0;
    }

    function _tierLevel(uint256 count) internal view returns (uint8) {
        for (uint8 i = 0; i < referralBuyerTiers.length; i++) {
            if (count >= referralBuyerTiers[i]) return uint8(referralBuyerTiers.length - i); // 8..1
        }
        return 1;
    }

    function _digest(
        address referrer,
        uint256 attestedGlobalCount,
        uint256 deadline,
        uint256 syncFee
    ) internal pure returns (bytes32) {
        bytes32 inner = keccak256(abi.encode(
            REFERRAL_PROJECT_ID,
            referrer,
            attestedGlobalCount,
            deadline,
            syncFee
        ));
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", inner));
    }

    // ===== Stages (with allocation) =====
    function addStage(
        uint256 _bonus,
        uint256 _price,
        uint256 _start,
        uint256 _end,
        uint256 _supply
    ) external onlyOwner {
        uint256 _id = currentStageId + 1;
        if (_id > maxStage) revert InvalidStage(_id);
        if (_bonus > 100) revert InvalidAmount("bonus");
        _assertStageWindow(_id, _start, _end);
        if (currentStageId > 0) {
            Stage memory prev = stages[currentStageId];
            if (prev.id == currentStageId && _start < prev.end) revert StageOverlap(_id);
        }
        currentStageId = _id;
        stages[_id] = Stage(_id, _bonus, _price, _start, _end, _supply, 0);

        emit StageConfigured(_id, _bonus, _price, _start, _end, _supply);
    }

    function setStage(
        uint256 _id,
        uint256 _bonus,
        uint256 _price,
        uint256 _start,
        uint256 _end,
        uint256 _supply
    ) external onlyOwner {
        Stage storage s = stages[_id];
        if (s.id != _id) revert InvalidStage(_id);
        if (_bonus > 100) revert InvalidAmount("bonus");
        _assertStageWindow(_id, _start, _end);
        if (_supply < s.sold) revert StageSupplyTooLow(_id, _supply, s.sold);
        _assertStageOrdering(_id, _start, _end);

        s.bonus  = _bonus;
        s.price  = _price;
        s.start  = _start;
        s.end    = _end;
        uint256 old = s.supply;
        s.supply = _supply;
        emit StageSupplyUpdated(_id, old, _supply);
        emit StageConfigured(_id, _bonus, _price, _start, _end, _supply);
    }

    function updateStageEndTime(uint256 _id, uint256 _newEnd) external onlyOwner {
        Stage storage s = stages[_id];
        if (s.id != _id) revert InvalidStage(_id);
        if (block.timestamp >= s.end) revert InvalidStageWindow(_id);
        if (_newEnd <= s.start || _newEnd < block.timestamp) revert InvalidStageWindow(_id);
        if (_id < currentStageId) {
            Stage memory nextS = stages[_id + 1];
            if (nextS.id == _id + 1 && _newEnd > nextS.start) revert StageOverlap(_id);
        }
        s.end = _newEnd;
        emit StageTimeUpdated(_id, s.start, s.end);

    }

    function updateStageStartTime(uint256 _id, uint256 _newStart) external onlyOwner {
        Stage storage s = stages[_id];
        if (s.id != _id) revert InvalidStage(_id);
        if (block.timestamp >= s.start) revert InvalidStageWindow(_id);
        if (_newStart <= block.timestamp || _newStart >= s.end) revert InvalidStageWindow(_id);
        if (_id > 1) {
            Stage memory prev = stages[_id - 1];
            if (prev.id == _id - 1 && _newStart < prev.end) revert StageOverlap(_id);
        }
        s.start = _newStart;
        emit StageTimeUpdated(_id, s.start, s.end);
    }

    /// @dev Roll leftover supply from finished stages [1..toId-1] into `toId`.
/// Uses a cursor so each stage is handled at most once.
function _autoRolloverTo(uint256 toId) internal {
    if (toId <= 1) return;

    // Start from the next unprocessed stage, stop before `toId`
    uint256 i = rolloverCursor + 1;
    if (i >= toId) return;

    for (; i < toId; i++) {
        Stage storage from = stages[i];
        if (from.id != i) continue;                 // skip holes
        if (block.timestamp <= from.end) break;     // stop at first not-ended stage

        uint256 remaining = from.supply > from.sold ? (from.supply - from.sold) : 0;
        if (remaining == 0) {
            continue; // nothing to roll from this stage
        }

        // idempotent: lock stage at its sold amount so it can't roll again
        from.supply = from.sold;

        // add remainder to the destination stage supply
        stages[toId].supply += remaining;

        emit StageRollover(i, toId, remaining);
    }

    // Future buys starting point
    rolloverCursor = i - 1;
}

    // ===== Public Sale (Option A) =====
    enum SaleMode { None, Presale, Public }

    function configurePublicSale(
        uint256 _price,
        uint256 _bonus,
        uint256 _start,
        bool _enabled
    ) external onlyOwner {
        // Immutable after start if previously enabled
        if (publicSale.enabled && block.timestamp >= publicSale.start) revert PublicSaleLocked();
        _positive(_price, "publicPrice");
        if (_bonus > 100) revert InvalidAmount("publicBonus");
        publicSale = PublicSale({ price: _price, bonus: _bonus, start: _start, enabled: _enabled });
        emit PublicSaleConfigured(_price, _bonus, _start, _enabled);
    }

    function setPublicSalePrice(uint256 _price) external onlyOwner {
        _positive(_price, "publicPrice");
        if (publicSale.enabled && block.timestamp >= publicSale.start) revert PublicSaleLocked();
        uint256 old = publicSale.price;
        publicSale.price = _price;
        emit PublicSalePriceUpdated(old, _price);
    }

    // ===== Active sale resolution =====
    function _activePresaleStageId() internal view returns (uint256) {
        if (currentStageId == 0) return 0;
        for (uint256 i = 1; i <= currentStageId; i++) {
            Stage memory s = stages[i];
            if (block.timestamp >= s.start && block.timestamp <= s.end) {
                if (s.sold < s.supply) return i;
            }
        }
        return 0;
    }

    /// @notice Returns effective supply and sold amount for stage `toId`
/// after simulating rollover from previous stages.
function simulateRolloverSupply(uint256 toId) public view returns (uint256 effectiveSupply, uint256 soldAlready) {
    if (toId == 0) return (0, 0);
    Stage memory to = stages[toId];
    effectiveSupply = to.supply;
    soldAlready     = to.sold;

    // Sum leftovers from finished earlier stages.
    for (uint256 i = 1; i < toId; i++) {
        Stage memory from = stages[i];
        if (from.id != i) continue;                // skip holes
        if (block.timestamp <= from.end) break;    // stop at first not-ended stage (ordered stages)
        uint256 remaining = from.supply > from.sold ? (from.supply - from.sold) : 0;
        effectiveSupply += remaining;
    }
}


    function getActiveSale() public view returns (SaleMode mode, uint256 stageId) {
        uint256 sid = _activePresaleStageId();
        if (sid != 0) return (SaleMode.Presale, sid);
        if (publicSale.enabled && block.timestamp >= publicSale.start) return (SaleMode.Public, 0);
        return (SaleMode.None, 0);
    }

    function _currentPriceAndBonus() internal view returns (uint256 price, uint256 bonus, SaleMode mode, uint256 stageId) {
        (mode, stageId) = getActiveSale();
        if (mode == SaleMode.Presale) {
            Stage memory s = stages[stageId];
            return (s.price, s.bonus, mode, stageId);
        } else if (mode == SaleMode.Public) {
            return (publicSale.price, publicSale.bonus, mode, 0);
        } else {
            revert("No active sale");
        }
    }

    // ===== Quotes =====
    function _quoteTokens(uint256 weiAmount, uint256 price, uint256 bonus) internal view returns (uint256 tokens) {
        uint256 usdValue = weiToUsd(weiAmount);
        uint256 decimals = tokenMetadata.decimals();
        tokens = (usdValue * (10**decimals) * (100 + bonus)) / (price * 100);
    }

    function _quoteWeiForTokens(uint256 tokenAmount, uint256 price, uint256 bonus) internal view returns (uint256 weiNeeded) {
    uint256 decimals = tokenMetadata.decimals();
    uint256 baseTokens = (tokenAmount * 100) / (100 + bonus);
    uint256 usdValue   = (baseTokens * price) / (10**decimals);

    // USD value of 1e18 wei (in 1e18 USD units)
    uint256 denom = weiToUsd(1e18);
    if (denom == 0) revert InvalidAmount("priceDenom");

    // Round up so we always charge enough wei    
    weiNeeded = (usdValue * 1e18 + denom - 1) / denom;
    }

    // ===== Public entrypoints =====

    // Simple wrappers for backwards-compatible buys
    function buyToken() external payable whenNotPaused {
        _buyAutoSplit(address(0), 0, 0, 0, hex"");
    }
    function buyToken(address _referrer) public payable whenNotPaused {
        _buyAutoSplit(_referrer, 0, 0, 0, hex"");
    }

    // Full buy path (with attestation) — uses auto-split
    function buyToken(
        address _referrer,
        uint256 attestedGlobalCount,
        uint256 deadline,
        uint256 syncFee,
        bytes calldata sig
    ) external payable whenNotPaused {
        _buyAutoSplit(_referrer, attestedGlobalCount, deadline, syncFee, sig);
    }

    /// @notice Buy tokens and immediately stake them into `stakePoolId`.
    function buyAndStake(
        address _referrer,
        uint256 attestedGlobalCount,
        uint256 deadline,
        uint256 syncFee,
        bytes calldata sig,
        uint8 stakePoolId
    ) external payable whenNotPaused {
        if (staking == address(0)) revert ZeroAddress("staking");
        _buyAutoSplitStake(_referrer, attestedGlobalCount, deadline, syncFee, sig, stakePoolId);
    }

    // --- convenience auto-stake overloads ---
function buyAndStake(uint8 stakePoolId)
    external
    payable
    whenNotPaused
{
    if (staking == address(0)) revert ZeroAddress("staking");
    _buyCore(address(0), 0, 0, 0, hex"", true, stakePoolId);
}

function buyAndStake(address _referrer, uint8 stakePoolId)
    external
    payable
    whenNotPaused
{
    if (staking == address(0)) revert ZeroAddress("staking");
    _buyCore(_referrer, 0, 0, 0, hex"", true, stakePoolId);
}

    // ===== Core buy with auto-split =====
    struct BuyVars {
        uint256 referralCashback;
        uint256 referralPct;
        uint256 effectiveGlobalCount;
        uint256 localAfter;
        uint8   fromTier;
        uint8   toTier;
        bool    attOk;
    }

    // ---- unified buy engine
function _buyCore(
    address _referrer,
    uint256 attestedGlobalCount,
    uint256 deadline,
    uint256 syncFee,
    bytes memory sig,
    bool deliverToStaking, // false = send to buyer, true = send to staking + open position
    uint8 stakePoolId
) internal nonReentrant {
    if (!presaleActive) revert SaleNotActive();
    if (msg.value == 0) revert InvalidAmount("msg.value");

    // Referral / attestation handling
    BuyVars memory v;
    if (_referrer != address(0) && _referrer != msg.sender) {
        uint256 localBefore = referralCounts[_referrer];
        v.localAfter = localBefore + 1;

        if (sig.length > 0) {
            _nonZero(aggregatorSigner, "signer");
            require(block.timestamp <= deadline, "att expired");
            address signer = _digest(_referrer, attestedGlobalCount, deadline, syncFee).recover(sig);
            if (signer == aggregatorSigner && attestedGlobalCount >= v.localAfter) {
                v.attOk = true;
            }
        }
        uint256 prevGlobal = lastGlobalCount[_referrer];
        v.effectiveGlobalCount = v.attOk
            ? attestedGlobalCount
            : (prevGlobal > v.localAfter ? prevGlobal : v.localAfter);

        v.fromTier = _tierLevel(prevGlobal);
        v.toTier   = _tierLevel(v.effectiveGlobalCount);

        if (v.attOk && v.toTier > v.fromTier) {
            _nonZero(stampFeeRecipient, "feeRecipient");
            _positive(syncFee, "syncFee");
            if (msg.value < syncFee) revert SyncFeeInsufficientValue(syncFee, msg.value);
            uint256 cap = (msg.value * maxSyncFeeBps) / 10_000;
            if (syncFee > cap) revert SyncFeeCapExceeded(syncFee, cap);
        } else {
            if (syncFee != 0) revert SyncFeeNotPermitted();
        }

        v.referralPct = getReferralBonusPercentage(v.effectiveGlobalCount);
    } else {
        if (syncFee != 0) revert SyncFeeNotPermitted();
    }

    uint256 purchaseValue = msg.value - syncFee;
    if (purchaseValue == 0) revert InvalidAmount("purchaseValue");
    if (weiToUsd(purchaseValue) < minimumBuyUsd) revert BelowMinimumBuy();

    // Plan phase: presale first, then public
    uint256 tokensTotal = 0;
    uint256 weiSpent    = 0;

    // 1) Use presale stages first
    {
        uint256 weiLeft = purchaseValue - weiSpent;

        while (weiLeft > 0) {
            (SaleMode modeP, uint256 sid) = getActiveSale();
            if (modeP != SaleMode.Presale) break;

            _autoRolloverTo(sid);

            Stage memory s = stages[sid];
            uint256 stageRem = s.supply > s.sold ? (s.supply - s.sold) : 0;
            if (stageRem == 0) { continue; }

            uint256 tokensAllWei = _quoteTokens(weiLeft, s.price, s.bonus);
            if (tokensAllWei == 0) { break; }

            uint256 bal = token.balanceOf(address(this));
            uint256 globalRem = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;

            uint256 availGlobal = globalRem > tokensTotal ? (globalRem - tokensTotal) : 0;
            uint256 availBal    = bal       > tokensTotal ? (bal       - tokensTotal) : 0;

            uint256 cap = stageRem;
            if (cap > availGlobal) cap = availGlobal;
            if (cap > availBal)    cap = availBal;
            if (cap == 0) break;

            if (tokensAllWei <= cap) {
                uint256 usedWei = _quoteWeiForTokens(tokensAllWei, s.price, s.bonus);
            
                if (usedWei > weiLeft) usedWei = weiLeft;
                if (usedWei == 0) { break; }

                stages[sid].sold += tokensAllWei;
                tokensTotal += tokensAllWei;
                weiSpent    += usedWei;
                weiLeft     -= usedWei;
            } else {
                uint256 usedWei = _quoteWeiForTokens(cap, s.price, s.bonus);
                if (usedWei > weiLeft) usedWei = weiLeft;
                if (usedWei == 0) { break; }

                stages[sid].sold += cap;
                tokensTotal += cap;
                weiSpent    += usedWei;
                weiLeft     -= usedWei;
            }
        }
    }

    // 2) Public sale (all-or-nothing)
    {
        uint256 weiLeft = purchaseValue - weiSpent;
        if (weiLeft > 0) {
            (SaleMode mode2, ) = getActiveSale();
            if (mode2 != SaleMode.Public) revert PublicSaleNotActive();

            uint256 tokensAllWei = _quoteTokens(weiLeft, publicSale.price, publicSale.bonus);

            uint256 bal = token.balanceOf(address(this));
            uint256 globalRem = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;

            uint256 availGlobal = globalRem > tokensTotal ? (globalRem - tokensTotal) : 0;
            uint256 availBal    = bal       > tokensTotal ? (bal       - tokensTotal) : 0;
            uint256 cap = availGlobal < availBal ? availGlobal : availBal;

            if (tokensAllWei > cap) revert StageCapExceeded();

            tokensTotal += tokensAllWei;
            weiSpent    += weiLeft;
        }
    }

    if (weiSpent != purchaseValue) revert SplitAccountingMismatch();
    if (tokensTotal == 0) revert InvalidAmount("tokensTotal");

    // Effects
    totalSold += tokensTotal;

    uint256 referralCashback = 0;
    if (_referrer != address(0) && _referrer != msg.sender && v.referralPct > 0) {
        referralCashback = (purchaseValue * v.referralPct) / 100;
        referralBonus[_referrer] += referralCashback;
        referralLiability += referralCashback;
        referralCounts[_referrer] = v.localAfter;
        if (v.attOk && v.effectiveGlobalCount > lastGlobalCount[_referrer]) {
            lastGlobalCount[_referrer] = v.effectiveGlobalCount;
        }
    }

    if (v.attOk && v.toTier > v.fromTier) {
        (bool okFee, ) = payable(stampFeeRecipient).call{value: syncFee}("");
        require(okFee, "sync fee xfer failed");
        emit TierCrossed(_referrer, v.fromTier, v.toTier, syncFee, v.effectiveGlobalCount);
    }

    // Delivery: send tokens or stake them
    if (!deliverToStaking) {
        // normal flow: deliver to buyer
        token.safeTransfer(msg.sender, tokensTotal);
    } else {
        // auto-stake flow: deliver to staking, then create position
        if (staking == address(0)) revert ZeroAddress("staking");
        token.safeTransfer(staking, tokensTotal);
        uint256 positionId = IBNBMagaStaking(staking).onPresaleReceive(
            msg.sender,
            tokensTotal,
            stakePoolId
        );
        emit StakedOnPurchase(msg.sender, positionId, stakePoolId, tokensTotal);
    }

     // Project payment
    uint256 paymentToAddress = purchaseValue - referralCashback;
    _nonZero(paymentAddress, "payment");
    (bool sent, ) = payable(paymentAddress).call{ value: paymentToAddress }("");
    if (!sent) revert PaymentTransferFailed();

    uint256 totalUsd = weiToUsd(purchaseValue);
    if (_referrer != address(0) && v.referralPct > 0) {
        emit ReferralPurchase(_referrer, msg.sender, totalUsd, purchaseValue, referralCashback, v.referralPct, v.effectiveGlobalCount);
    }
}

// Thin wrappers for readability
function _buyAutoSplit(
    address _referrer,
    uint256 attestedGlobalCount,
    uint256 deadline,
    uint256 syncFee,
    bytes memory sig
) internal {
    _buyCore(_referrer, attestedGlobalCount, deadline, syncFee, sig, false, 0);
}

function _buyAutoSplitStake(
    address _referrer,
    uint256 attestedGlobalCount,
    uint256 deadline,
    uint256 syncFee,
    bytes memory sig,
    uint8 stakePoolId
) internal {
    _buyCore(_referrer, attestedGlobalCount, deadline, syncFee, sig, true, stakePoolId);
}

    // ===== Calculators (respect caps & balances) =====
    function calculateTokenAmount(uint256 weiAmount) external view returns (uint256) {
        (SaleMode mode, uint256 sid) = getActiveSale();
        if (mode == SaleMode.None) return 0;

        uint256 price; uint256 bonus;
        if (mode == SaleMode.Presale) { Stage memory s = stages[sid]; price = s.price; bonus = s.bonus; }
        else { price = publicSale.price; bonus = publicSale.bonus; }

        uint256 tokens = _quoteTokens(weiAmount, price, bonus);

        // global cap & balance
        uint256 globalRem = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;
        if (tokens > globalRem) tokens = globalRem;
        uint256 bal = token.balanceOf(address(this));
        if (tokens > bal) tokens = bal;

        // stage cap if presale
    if (mode == SaleMode.Presale) {
    (uint256 effSupply, uint256 soldAlready) = simulateRolloverSupply(sid);
    uint256 stageRem = effSupply > soldAlready ? (effSupply - soldAlready) : 0;
    if (tokens > stageRem) tokens = stageRem;
    }
        return tokens;
    }

    function calculateRequiredPayment(uint256 tokenAmount) external view returns (uint256) {
        (SaleMode mode, uint256 sid) = getActiveSale();
        if (mode == SaleMode.None) return 0;
        uint256 price; uint256 bonus;
        if (mode == SaleMode.Presale) { Stage memory s = stages[sid]; price = s.price; bonus = s.bonus; }
        else { price = publicSale.price; bonus = publicSale.bonus; }
        return _quoteWeiForTokens(tokenAmount, price, bonus);
    }

    function getMinimumBuyWei() external view returns (uint256) {
        return (minimumBuyUsd * 1e18) / weiToUsd(1e18);
    }

    /// @notice Current public sale capacity in tokens.
function getPublicCapacityTokens() public view returns (uint256) {
    uint256 bal = token.balanceOf(address(this));
    uint256 globalRem = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;
    return globalRem < bal ? globalRem : bal;
}

// @notice Max wei that fits fully at public-sale terms right now.
function getMaxPublicBuyWei() external view returns (uint256) {
    if (!(publicSale.enabled && block.timestamp >= publicSale.start)) return 0;
    uint256 capTokens = getPublicCapacityTokens();
    if (capTokens == 0) return 0;
    return _quoteWeiForTokens(capTokens, publicSale.price, publicSale.bonus);
}

/// @notice Max wei that won't revert if sent now (presale first, then public).
function getMaxAcceptableWei() external view returns (uint256) {
    (SaleMode mode, uint256 sid) = getActiveSale();
    if (mode == SaleMode.None) return 0;

    uint256 tokensPlanned = 0;

    // Presale capacity now (simulate rollover)
    if (mode == SaleMode.Presale) {
        (uint256 effSupply, uint256 soldAlready) = simulateRolloverSupply(sid);
        uint256 stageRem = effSupply > soldAlready ? (effSupply - soldAlready) : 0;

        uint256 bal = token.balanceOf(address(this));
        uint256 globalRem = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;
        if (stageRem > globalRem) stageRem = globalRem;
        if (stageRem > bal)       stageRem = bal;

        tokensPlanned = stageRem;
    }

    // Public capacity for the leftover (all-or-nothing)
    uint256 publicWeiMax = 0;
    if (publicSale.enabled && block.timestamp >= publicSale.start) {
        uint256 bal = token.balanceOf(address(this));
        uint256 globalRem = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;

        uint256 availGlobal = globalRem > tokensPlanned ? (globalRem - tokensPlanned) : 0;
        uint256 availBal    = bal       > tokensPlanned ? (bal       - tokensPlanned) : 0;
        uint256 publicCapTokens = availGlobal < availBal ? availGlobal : availBal;

        if (publicCapTokens > 0) {
            publicWeiMax = _quoteWeiForTokens(publicCapTokens, publicSale.price, publicSale.bonus);
        }
    }

    uint256 presaleWeiApprox = 0;
    if (mode == SaleMode.Presale && tokensPlanned > 0) {
        Stage memory s = stages[sid];
        presaleWeiApprox = _quoteWeiForTokens(tokensPlanned, s.price, s.bonus);
    }

    return presaleWeiApprox + publicWeiMax;
}

    // ===== Attestation sync =====
    function updateReferralAttestation(
        address referrer,
        uint256 attestedGlobalCount,
        uint256 deadline,
        uint256 syncFee,
        bytes calldata sig
    ) external whenNotPaused {
        _nonZero(aggregatorSigner, "signer");
        require(block.timestamp <= deadline, "expired");
        address signer = _digest(referrer, attestedGlobalCount, deadline, syncFee).recover(sig);
        require(signer == aggregatorSigner, "bad sig");
        require(attestedGlobalCount >= lastGlobalCount[referrer], "non-monotonic");
        lastGlobalCount[referrer] = attestedGlobalCount;
    }

    // ===== Withdrawals =====
    function withdrawExcess() external onlyOwner nonReentrant {
        uint256 bal = address(this).balance;
        if (bal <= referralLiability) revert NothingToWithdraw();
        uint256 amount = bal - referralLiability;
        (bool ok, ) = payable(msg.sender).call{value: amount}("");
        if (!ok) revert PaymentTransferFailed();
        emit FundsWithdrawn(msg.sender, amount);
    }

    function withdrawTokens(address _to, uint256 _amount) external onlyOwner nonReentrant {
        _nonZero(_to, "to");
        uint256 balance = token.balanceOf(address(this));
        uint256 reserved = presaleTokenAmount > totalSold ? (presaleTokenAmount - totalSold) : 0;
        uint256 unlocked = balance > reserved ? (balance - reserved) : 0;
        if (_amount > unlocked) revert SaleTokensLocked(_amount, unlocked);
        token.safeTransfer(_to, _amount);
        emit TokensWithdrawn(_to, _amount);
    }

    function withdrawReferralBonus() external nonReentrant whenNotPaused {
        uint256 next = lastWithdrawal[msg.sender] + withdrawalCooldown;
        if (block.timestamp < next) revert WithdrawalCooldownInProgress(next);
        uint256 bonus = referralBonus[msg.sender];

        uint256 floor;
        if (block.chainid == 1 || block.chainid == 11155111) {
            floor = minReferralPayoutEth;
        } else if (block.chainid == 56 || block.chainid == 97) {
            floor = minReferralPayoutBnb;
        } else {
            revert UnsupportedChain(block.chainid);
        }
        if (bonus < floor) revert ReferralFloorNotMet(floor, bonus);
        if (referralLiability < bonus) revert ReferralLiabilityTooLow();

        referralBonus[msg.sender] = 0;
        referralLiability -= bonus;
        lastWithdrawal[msg.sender] = block.timestamp;
        withdrawalHistory[msg.sender].push(WithdrawalRecord({
            amount: bonus,
            timestamp: block.timestamp,
            blockNumber: block.number
        }));
        totalWithdrawn[msg.sender] += bonus;

        (bool success, ) = msg.sender.call{value: bonus}("");
        if (!success) revert PaymentTransferFailed();

        emit ReferralWithdrawn(msg.sender, bonus, block.timestamp, totalWithdrawn[msg.sender]);
    }

    // ===== Views =====
    
    /// @notice Combined referral count used by staking.
    /// Returns max(local referrals, attested global referrals).    
    function referralCount(address user) external view returns (uint256) {
        uint256 local = referralCounts[user];       // tracked direct referrals
        uint256 global = lastGlobalCount[user];     // attested/global referrals
        return local > global ? local : global;
    }


    function getReferrerInfo(address _referrer) external view returns (
        uint256 totalReferrals,
        uint256 pendingCashback,
        uint256 bonusPercentage,
        uint256 nextWithdrawalTime,
        uint256 totalEarned,
        uint256 withdrawalCount
    ) {
        totalReferrals = referralCounts[_referrer];
        pendingCashback = referralBonus[_referrer];
        bonusPercentage = getReferralBonusPercentage(totalReferrals);
        nextWithdrawalTime = lastWithdrawal[_referrer] + withdrawalCooldown;
        totalEarned = totalWithdrawn[_referrer] + pendingCashback;
        withdrawalCount = withdrawalHistory[_referrer].length;
    }

    function getGlobalReferralInfo(address referrer) external view returns (
        uint256 globalCount,
        uint256 bonusPercentage,
        uint8 tierLevel
    ) {
        globalCount = lastGlobalCount[referrer];
        bonusPercentage = getReferralBonusPercentage(globalCount);
        tierLevel = _tierLevel(globalCount);
    }

    /// @notice Remaining tokens for a stage, including simulated rollover.
    function getEffectiveStageRemaining(uint256 stageId) external view returns (uint256 remaining) {
    (uint256 effSupply, uint256 soldAlready) = simulateRolloverSupply(stageId);
    remaining = effSupply > soldAlready ? (effSupply - soldAlready) : 0;
    
    }

    function getWithdrawalHistory(address _user) external view returns (WithdrawalRecord[] memory) {
        return withdrawalHistory[_user];
    }

    function getWithdrawalCount(address _user) external view returns (uint256) {
        return withdrawalHistory[_user].length;
    }

    function getLatestWithdrawal(address _user) external view returns (WithdrawalRecord memory) {
        require(withdrawalHistory[_user].length > 0, "none");
        return withdrawalHistory[_user][withdrawalHistory[_user].length - 1];
    }

    function getWithdrawalsPaginated(address _user, uint256 _offset, uint256 _limit) external view returns (WithdrawalRecord[] memory) {
        WithdrawalRecord[] storage userHistory = withdrawalHistory[_user];
        require(_offset < userHistory.length, "oob");
        uint256 end = _offset + _limit;
        if (end > userHistory.length) end = userHistory.length;
        WithdrawalRecord[] memory result = new WithdrawalRecord[](end - _offset);
        for (uint256 i = _offset; i < end; i++) result[i - _offset] = userHistory[i];
        return result;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(
        bytes32 hash,
        bytes memory signature
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly ("memory-safe") {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

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

    bool private _paused;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

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

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 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 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, 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.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

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

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface AggregatorV3Interface {
  function decimals() external view returns (uint8);

  function description() external view returns (string memory);

  function version() external view returns (uint256);

  function getRoundData(
    uint80 _roundId
  ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

  function latestRoundData()
    external
    view
    returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity >=0.6.2;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
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);
}

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

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

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

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

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

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

File 12 of 14 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 13 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * 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[ERC 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);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_payment","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"uint256","name":"_minReferralPayoutEth","type":"uint256"},{"internalType":"uint256","name":"_minReferralPayoutBnb","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BelowMinimumBuy","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"ImmutablePriceFeed","type":"error"},{"inputs":[],"name":"ImmutableToken","type":"error"},{"inputs":[{"internalType":"string","name":"parameter","type":"string"}],"name":"InvalidAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"stageId","type":"uint256"}],"name":"InvalidStage","type":"error"},{"inputs":[{"internalType":"uint256","name":"stageId","type":"uint256"}],"name":"InvalidStageWindow","type":"error"},{"inputs":[],"name":"NothingToWithdraw","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PaymentTransferFailed","type":"error"},{"inputs":[],"name":"PublicSaleLocked","type":"error"},{"inputs":[],"name":"PublicSaleNotActive","type":"error"},{"inputs":[{"internalType":"uint256","name":"floorNeeded","type":"uint256"},{"internalType":"uint256","name":"pending","type":"uint256"}],"name":"ReferralFloorNotMet","type":"error"},{"inputs":[],"name":"ReferralLiabilityTooLow","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SaleNotActive","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"unlocked","type":"uint256"}],"name":"SaleTokensLocked","type":"error"},{"inputs":[],"name":"SplitAccountingMismatch","type":"error"},{"inputs":[],"name":"StageCapExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"stageId","type":"uint256"}],"name":"StageOverlap","type":"error"},{"inputs":[{"internalType":"uint256","name":"stageId","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"sold","type":"uint256"}],"name":"StageSupplyTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"maxAllowed","type":"uint256"}],"name":"SyncFeeCapExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"sent","type":"uint256"}],"name":"SyncFeeInsufficientValue","type":"error"},{"inputs":[],"name":"SyncFeeNotPermitted","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"UnsupportedChain","type":"error"},{"inputs":[{"internalType":"uint256","name":"nextAllowed","type":"uint256"}],"name":"WithdrawalCooldownInProgress","type":"error"},{"inputs":[{"internalType":"string","name":"parameter","type":"string"}],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldV","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newV","type":"uint256"}],"name":"MinReferralPayoutBnbUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldV","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newV","type":"uint256"}],"name":"MinReferralPayoutEthUpdated","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":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bonus","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"PublicSaleConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"PublicSalePriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"usdAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeCurrencyPaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cashbackAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bonusPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReferralCount","type":"uint256"}],"name":"ReferralPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalWithdrawnToDate","type":"uint256"}],"name":"ReferralWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bonus","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"}],"name":"StageConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"toId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StageRollover","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newSupply","type":"uint256"}],"name":"StageSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStart","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEnd","type":"uint256"}],"name":"StageTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"poolId","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakedOnPurchase","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint8","name":"fromTier","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"toTier","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"syncFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"}],"name":"TierCrossed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"REFERRAL_PROJECT_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bonus","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"},{"internalType":"uint256","name":"_supply","type":"uint256"}],"name":"addStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"aggregatorSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"syncFee","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"},{"internalType":"uint8","name":"stakePoolId","type":"uint8"}],"name":"buyAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"uint8","name":"stakePoolId","type":"uint8"}],"name":"buyAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8","name":"stakePoolId","type":"uint8"}],"name":"buyAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"syncFee","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"buyToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"}],"name":"buyToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"buyToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"calculateRequiredPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"weiAmount","type":"uint256"}],"name":"calculateTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_bonus","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"configurePublicSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentStageId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipPresaleActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getActiveSale","outputs":[{"internalType":"enum BNBMagaPresale.SaleMode","name":"mode","type":"uint8"},{"internalType":"uint256","name":"stageId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stageId","type":"uint256"}],"name":"getEffectiveStageRemaining","outputs":[{"internalType":"uint256","name":"remaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"}],"name":"getGlobalReferralInfo","outputs":[{"internalType":"uint256","name":"globalCount","type":"uint256"},{"internalType":"uint256","name":"bonusPercentage","type":"uint256"},{"internalType":"uint8","name":"tierLevel","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getLatestWithdrawal","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"internalType":"struct BNBMagaPresale.WithdrawalRecord","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxAcceptableWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxPublicBuyWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinimumBuyWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNativeCurrencyPrice","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPublicCapacityTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalBuyers","type":"uint256"}],"name":"getReferralBonusPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referrer","type":"address"}],"name":"getReferrerInfo","outputs":[{"internalType":"uint256","name":"totalReferrals","type":"uint256"},{"internalType":"uint256","name":"pendingCashback","type":"uint256"},{"internalType":"uint256","name":"bonusPercentage","type":"uint256"},{"internalType":"uint256","name":"nextWithdrawalTime","type":"uint256"},{"internalType":"uint256","name":"totalEarned","type":"uint256"},{"internalType":"uint256","name":"withdrawalCount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getWithdrawalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getWithdrawalHistory","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"internalType":"struct BNBMagaPresale.WithdrawalRecord[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_offset","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"getWithdrawalsPaginated","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"internalType":"struct BNBMagaPresale.WithdrawalRecord[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastGlobalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lastWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxStage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSyncFeeBps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minReferralPayoutBnb","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minReferralPayoutEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumBuyUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"paymentAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicSale","outputs":[{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"bonus","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"bool","name":"enabled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralBonus","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"referralBonuses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"referralBuyerTiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"referralCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralCounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralLiability","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setAggregatorSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxStage","type":"uint256"}],"name":"setMaxStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"bps","type":"uint16"}],"name":"setMaxSyncFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"v","type":"uint256"}],"name":"setMinReferralPayoutBnb","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"v","type":"uint256"}],"name":"setMinReferralPayoutEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumUsd","type":"uint256"}],"name":"setMinimumBuyUsd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentAddress","type":"address"}],"name":"setPaymentAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"setPresaleTokenAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"setPriceFeed","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPublicSalePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_bonus","type":"uint256"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"},{"internalType":"uint256","name":"_supply","type":"uint256"}],"name":"setStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staking","type":"address"}],"name":"setStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"setStampFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"setToken","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalSold","type":"uint256"}],"name":"setTotalSold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"toId","type":"uint256"}],"name":"simulateRolloverSupply","outputs":[{"internalType":"uint256","name":"effectiveSupply","type":"uint256"},{"internalType":"uint256","name":"soldAlready","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stages","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"bonus","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"sold","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"staking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stampFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenMetadata","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalWithdrawn","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":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"attestedGlobalCount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"syncFee","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"updateReferralAttestation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_newEnd","type":"uint256"}],"name":"updateStageEndTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_newStart","type":"uint256"}],"name":"updateStageStartTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"weiAmount","type":"uint256"}],"name":"weiToUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawExcess","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawReferralBonus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawalHistory","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"}]

6b04860d8812f0b388780000006006555f60078190556008805460ff19166001178155674563918244f400006009556101806040526103a260809081526101ae60a05260b460c052605060e052602861010052600f610120526005610140526101609290925261007191600a916109e1565b5060408051610100810182526046815260326020820152602891810191909152601e606082015260196080820152601460a0820152600f60c0820152600a60e08201526100c290600b906008610a30565b506154606011556015805461ffff60a01b1916604b60a21b17905560096019555f601a553480156100f1575f5ffd5b50604051615f72380380615f7283398101604081905261011091610a9d565b338061013657604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b61013f81610943565b50600180556002805460ff191690556040805180820190915260078152661c185e5b595b9d60ca1b6020820152610177908690610992565b6101a484604051806040016040528060058152602001643a37b5b2b760d91b81525061099260201b60201c565b6101d583604051806040016040528060098152602001681c1c9a58d95199595960ba1b81525061099260201b60201c565b61020b826040518060400160405280600e81526020016d0dad2dca4cacccae4e4c2d88ae8d60931b8152506109bf60201b60201c565b610241816040518060400160405280600e81526020016d36b4b72932b332b93930b621373160911b8152506109bf60201b60201c565b60028054610100600160a81b0319166101006001600160a01b0387811691820292909217909255600380546001600160a01b031990811690931790556005805483168883161790556004805490921690851690811782556040805163313ce56760e01b8152905160129363313ce567928082019260209290918290030181865afa1580156102d1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102f59190610aef565b60ff16111561033b5760405162461bcd60e51b81526020600482015260126024820152710cccacac840c8cac6d2dac2d8e6407c4062760731b604482015260640161012d565b6040518060e001604052806001815260200160648152602001660aa87bee53800081526020016369303abd8152602001636957c7bd81526020016a73ce27351811f40c00000081526020015f81525060185f600181526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e0016040528060028152602001605081526020016611c37937e080008152602001636957c7bd815260200163697f54bd81526020016a73ce27351811f40c00000081526020015f81525060185f600281526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e001604052806003815260200160418152602001661550f7dca70000815260200163697f54bd81526020016369931b3d81526020016a73ce27351811f40c00000081526020015f81525060185f600381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e0016040528060048152602001603781526020016618de76816d800081526020016369931b3d81526020016369a6e1bd81526020016a73ce27351811f40c00000081526020015f81525060185f600481526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e001604052806005815260200160288152602001661c6bf52634000081526020016369a6e1bd81526020016369baa83d81526020016a73ce27351811f40c00000081526020015f81525060185f600581526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e001604052806006815260200160198152602001661ff973cafa800081526020016369baa83d81526020016369ce6ebd81526020016a73ce27351811f40c00000081526020015f81525060185f600681526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e001604052806007815260200160118152602001662386f26fc1000081526020016369ce6ebd81526020016369e2353d81526020016a73ce27351811f40c00000081526020015f81525060185f600781526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e0016040528060088152602001600b8152602001662aa1efb94e000081526020016369e2353d81526020016369f5fbbd81526020016a73ce27351811f40c00000081526020015f81525060185f600881526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506040518060e00160405280600981526020016008815260200166354a6ba7a1800081526020016369f5fbbd8152602001636a09c23d81526020016a73ce27351811f40c00000081526020015f81525060185f600981526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601559050506009601a8190555081601281905550806013819055505050505050610b4b565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0382166109bb578060405163eac0d38960e01b815260040161012d9190610b16565b5050565b815f036109bb578060405163589956a560e11b815260040161012d9190610b16565b828054828255905f5260205f20908101928215610a20579160200282015b82811115610a20578251829061ffff169055916020019190600101906109ff565b50610a2c929150610a6e565b5090565b828054828255905f5260205f20908101928215610a20579160200282015b82811115610a20578251829060ff16905591602001919060010190610a4e565b5b80821115610a2c575f8155600101610a6f565b80516001600160a01b0381168114610a98575f5ffd5b919050565b5f5f5f5f5f60a08688031215610ab1575f5ffd5b610aba86610a82565b9450610ac860208701610a82565b9350610ad660408701610a82565b6060870151608090970151959894975095949392505050565b5f60208284031215610aff575f5ffd5b815160ff81168114610b0f575f5ffd5b9392505050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b61541a80610b585f395ff3fe60806040526004361061048f575f3560e01c806382870f6411610257578063c7ea0c511161013f578063e3245933116100be578063f1eb6db811610083578063f1eb6db814610ece578063f2fde38b14610ee3578063f5b2cad714610f02578063f6eeddfd14610f21578063fc0c546a14610f36578063fd69f25414610f5a575f5ffd5b8063e324593314610dfb578063e4fae6da14610e0f578063e918032314610e42578063ebe6c9ff14610e8e578063ec45127a14610eb9575f5ffd5b8063d43449b611610104578063d43449b614610d6a578063d6c89c6014610d89578063db74559b14610d9e578063dbfce1da14610dbd578063e06ebb4114610ddc575f5ffd5b8063c7ea0c5114610ca5578063c8123eb814610ce2578063ccf01f0114610d01578063cec297a014610d20578063d3f2407b14610d4b575f5ffd5b8063909d6283116101d6578063a24bcf461161019b578063a24bcf4614610c0d578063a482171914610c2c578063a70184ce14610c34578063adca184d14610c53578063b70dcf3514610c72578063c264a06314610c91575f5ffd5b8063909d628314610b725780639106d7ba14610b9157806391ca7f3c14610ba657806398585c5014610bba5780639aa89d4214610bd9575f5ffd5b80638b1903761161021c5780638b19037614610ae45780638b250eff14610b035780638c733fdf14610b185780638da5cb5b14610b375780638ff3909914610b53575f5ffd5b806382870f64146109eb5780638456cb59146109fe578063845ddcb214610a1257806384b3997c14610a9d578063875a682a14610ad0575f5ffd5b80634571a7f11161037a5780636dbbbb59116102f957806378e29afd116102be57806378e29afd14610953578063791a2519146109725780637b5e6b9e146109915780637d7511bb146109b05780637e72fb52146109c357806381bf4425146109d6575f5ffd5b80636dbbbb59146108cb578063715018a6146108ed578063724e78da14610901578063741bef1a14610920578063773110491461093f575f5ffd5b806359f679e51161033f57806359f679e5146108445780635c975abb146108635780635e1e10041461087a57806360e6512114610899578063633423be146108ac575f5ffd5b80634571a7f1146107815780634a56c9a7146107965780634a7e588c146107d05780634cf088d9146107e457806353135ca01461081b575f5ffd5b80632d705e831161041157806337851598116103d657806337851598146106a557806339ce1089146106c45780633f4ba83a146106ef57806340154c40146107035780634468e8741461072257806344fec8eb1461074d575f5ffd5b80632d705e83146105e25780633114740e146106015780633151338e14610620578063328a77261461063f57806333bc1c5c1461065e575f5ffd5b8063144fa6d711610457578063144fa6d7146105505780631ba705781461056f578063200f366014610583578063219666bb14610597578063285d7aff146105c3575f5ffd5b806302f659631461049357806306b091f9146104a85780630a64143a146104c75780630fe93211146105055780631053234714610531575b5f5ffd5b6104a66104a1366004614d88565b610f6f565b005b3480156104b3575f5ffd5b506104a66104c2366004614df4565b610fc1565b3480156104d2575f5ffd5b506104f26104e1366004614e1c565b60106020525f908152604090205481565b6040519081526020015b60405180910390f35b348015610510575f5ffd5b5061052461051f366004614e35565b611143565b6040516104fc9190614e65565b34801561053c575f5ffd5b506104a661054b366004614ec6565b6112b1565b34801561055b575f5ffd5b506104a661056a366004614e1c565b61144b565b34801561057a575f5ffd5b506104f261146c565b34801561058e575f5ffd5b506104f26114a2565b3480156105a2575f5ffd5b506105b66105b1366004614e1c565b6114f1565b6040516104fc9190614ee6565b3480156105ce575f5ffd5b506104a66105dd366004614f07565b6115cd565b3480156105ed575f5ffd5b506104f26105fc366004614f3e565b6117bd565b34801561060c575f5ffd5b5061052461061b366004614e1c565b611820565b34801561062b575f5ffd5b506104a661063a366004614f3e565b6118ad565b34801561064a575f5ffd5b506104a6610659366004614f3e565b6118ba565b348015610669575f5ffd5b50601c54601d54601e54601f546106839392919060ff1684565b60408051948552602085019390935291830152151560608201526080016104fc565b3480156106b0575f5ffd5b506104a66106bf366004614f3e565b6118f6565b3480156106cf575f5ffd5b506104f26106de366004614e1c565b60166020525f908152604090205481565b3480156106fa575f5ffd5b506104a6611903565b34801561070e575f5ffd5b506104a661071d366004614d88565b611915565b34801561072d575f5ffd5b506104f261073c366004614e1c565b600d6020525f908152604090205481565b348015610758575f5ffd5b5060155461076e90600160a01b900461ffff1681565b60405161ffff90911681526020016104fc565b34801561078c575f5ffd5b506104f260195481565b3480156107a1575f5ffd5b506107b56107b0366004614df4565b611a9a565b604080519384526020840192909252908201526060016104fc565b3480156107db575f5ffd5b506104f2611ad7565b3480156107ef575f5ffd5b50601754610803906001600160a01b031681565b6040516001600160a01b0390911681526020016104fc565b348015610826575f5ffd5b506008546108349060ff1681565b60405190151581526020016104fc565b34801561084f575f5ffd5b506104f261085e366004614f3e565b611b85565b34801561086e575f5ffd5b5060025460ff16610834565b348015610885575f5ffd5b506104a6610894366004614e1c565b611ba4565b6104a66108a7366004614f63565b611bf7565b3480156108b7575f5ffd5b50600554610803906001600160a01b031681565b3480156108d6575f5ffd5b506108df611c75565b6040516104fc929190614ff6565b3480156108f8575f5ffd5b506104a6611cc0565b34801561090c575f5ffd5b506104a661091b366004614e1c565b611cd1565b34801561092b575f5ffd5b50600454610803906001600160a01b031681565b34801561094a575f5ffd5b506104a6611cf2565b34801561095e575f5ffd5b50601554610803906001600160a01b031681565b34801561097d575f5ffd5b506104a661098c366004614f3e565b611d0e565b34801561099c575f5ffd5b506104a66109ab366004615020565b611dba565b6104a66109be366004615041565b611e25565b6104a66109d1366004614e1c565b611e74565b3480156109e1575f5ffd5b506104f2600e5481565b6104a66109f9366004615076565b611e9a565b348015610a09575f5ffd5b506104a6611ee9565b348015610a1d575f5ffd5b50610a68610a2c366004614f3e565b60186020525f90815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016104fc565b348015610aa8575f5ffd5b506104f27ffa8b458545377bec9568500b00b33c407fe4f3b1f74043a0f121d056b1562b8381565b348015610adb575f5ffd5b506104f2611ef9565b348015610aef575f5ffd5b506104a6610afe366004614f3e565b61206e565b348015610b0e575f5ffd5b506104f260065481565b348015610b23575f5ffd5b506104f2610b32366004614f3e565b61207b565b348015610b42575f5ffd5b505f546001600160a01b0316610803565b348015610b5e575f5ffd5b506104a6610b6d366004614e1c565b61213f565b348015610b7d575f5ffd5b506104a6610b8c366004615091565b612192565b348015610b9c575f5ffd5b506104f260075481565b348015610bb1575f5ffd5b506104a6612313565b348015610bc5575f5ffd5b506104f2610bd4366004614f3e565b612591565b348015610be4575f5ffd5b50610bf8610bf3366004614f3e565b6125c0565b604080519283526020830191909152016104fc565b348015610c18575f5ffd5b506104f2610c27366004614f3e565b612709565b6104a66128dc565b348015610c3f575f5ffd5b506104a6610c4e366004614f3e565b6128ff565b348015610c5e575f5ffd5b506104a6610c6d366004614f3e565b612911565b348015610c7d575f5ffd5b506104f2610c8c366004614f3e565b612924565b348015610c9c575f5ffd5b506104a6612933565b348015610cb0575f5ffd5b50610cc4610cbf366004614e1c565b612a20565b60408051938452602084019290925260ff16908201526060016104fc565b348015610ced575f5ffd5b506104f2610cfc366004614f3e565b612a56565b348015610d0c575f5ffd5b50601454610803906001600160a01b031681565b348015610d2b575f5ffd5b506104f2610d3a366004614e1c565b600c6020525f908152604090205481565b348015610d56575f5ffd5b506104a6610d653660046150d0565b612b24565b348015610d75575f5ffd5b506104a6610d84366004614e1c565b612c56565b348015610d94575f5ffd5b506104f260115481565b348015610da9575f5ffd5b506104f2610db8366004614e1c565b612ca8565b348015610dc8575f5ffd5b506104a6610dd7366004614ec6565b612cdf565b348015610de7575f5ffd5b506104a6610df6366004614e1c565b612e71565b348015610e06575f5ffd5b506104f2612ec9565b348015610e1a575f5ffd5b506104f2610e29366004614e1c565b6001600160a01b03165f90815260208052604090205490565b348015610e4d575f5ffd5b50610e61610e5c366004614e1c565b6131b0565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016104fc565b348015610e99575f5ffd5b506104f2610ea8366004614e1c565b600f6020525f908152604090205481565b348015610ec4575f5ffd5b506104f2601a5481565b348015610ed9575f5ffd5b506104f260135481565b348015610eee575f5ffd5b506104a6610efd366004614e1c565b613253565b348015610f0d575f5ffd5b50600354610803906001600160a01b031681565b348015610f2c575f5ffd5b506104f260095481565b348015610f41575f5ffd5b506002546108039061010090046001600160a01b031681565b348015610f65575f5ffd5b506104f260125481565b610f7761328d565b610fb98686868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506132d392505050565b505050505050565b610fc96132e9565b610fd1613315565b610ff58260405180604001604052806002815260200161746f60f01b81525061336e565b6002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015611040573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110649190615112565b90505f60075460065411611078575f611088565b600754600654611088919061513d565b90505f818311611098575f6110a2565b6110a2828461513d565b9050808411156110d4576040516371d63b8360e01b815260048101859052602481018290526044015b60405180910390fd5b6002546110f09061010090046001600160a01b03168686613397565b846001600160a01b03167f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b8560405161112b91815260200190565b60405180910390a250505061113f60018055565b5050565b6001600160a01b0383165f908152602080526040902080546060919084106111935760405162461bcd60e51b815260206004820152600360248201526237b7b160e91b60448201526064016110cb565b5f61119e8486615150565b82549091508111156111ae575080545b5f6111b9868361513d565b67ffffffffffffffff8111156111d1576111d1615163565b60405190808252806020026020018201604052801561122357816020015b61121060405180606001604052805f81526020015f81526020015f81525090565b8152602001906001900390816111ef5790505b509050855b828110156112a65783818154811061124257611242615177565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050828883611283919061513d565b8151811061129357611293615177565b6020908102919091010152600101611228565b509695505050505050565b6112b96132e9565b5f828152601860205260409020805483146112ea5760405163213975eb60e01b8152600481018490526024016110cb565b80600401544210611311576040516397db424160e01b8152600481018490526024016110cb565b80600301548211158061132357504282105b15611344576040516397db424160e01b8152600481018490526024016110cb565b601a548310156113fe575f60188161135d866001615150565b81526020019081526020015f206040518060e00160405290815f8201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152505090508360016113c99190615150565b81511480156113db5750806060015183115b156113fc57604051637437e81760e01b8152600481018590526024016110cb565b505b600481018290556003810154604080519182526020820184905284917f74064869fb3619f32eb8e86259fe1d5051e6d16ce61718dad7d2420bcfe0fcc891015b60405180910390a2505050565b6114536132e9565b604051633a0477af60e21b815260040160405180910390fd5b5f61147e670de0b6b3a764000061207b565b60095461149390670de0b6b3a764000061518b565b61149d91906151a2565b905090565b601f545f9060ff1680156114b85750601e544210155b6114c157505f90565b5f6114ca611ad7565b9050805f036114da575f91505090565b601c54601d546114eb9183916133ee565b91505090565b61151260405180606001604052805f81526020015f81526020015f81525090565b6001600160a01b0382165f90815260208052604090205461155e5760405162461bcd60e51b81526004016110cb906020808252600490820152636e6f6e6560e01b604082015260600190565b6001600160a01b0382165f908152602080526040902080546115829060019061513d565b8154811061159257611592615177565b905f5260205f2090600302016040518060600160405290815f8201548152602001600182015481526020016002820154815250509050919050565b6115d56132e9565b5f601a5460016115e59190615150565b905060195481111561160d5760405163213975eb60e01b8152600481018290526024016110cb565b60648611156116475760405163589956a560e11b8152602060048201526005602482015264626f6e757360d81b60448201526064016110cb565b61165281858561353f565b601a54156116ef57601a545f81815260186020908152604091829020825160e08101845281548082526001830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a08401526006015460c083015290911480156116cc5750806080015185105b156116ed57604051637437e81760e01b8152600481018390526024016110cb565b505b601a8190556040805160e081018252828152602080820189815282840189815260608085018a815260808087018b815260a08089018c81525f60c08b018181528d825260188b52908c90209a518b55975160018b0155955160028a01559251600389015551600488015592516005870155925160069095019490945584518b81529283018a905293820188905291810186905291820184905282917f85691ece3b5cb16ac00911efb4d9dfadc0fe04f47d8acaa92f8acdea6ae27b80910160405180910390a2505050505050565b5f805b600a5481101561181857600a81815481106117dd576117dd615177565b905f5260205f200154831061181057600b81815481106117ff576117ff615177565b905f5260205f200154915050919050565b6001016117c0565b505f92915050565b6001600160a01b0381165f90815260208080526040808320805482518185028101850190935280835260609492939192909184015b828210156118a2578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505081526020019060010190611855565b505050509050919050565b6118b56132e9565b600655565b6118c26132e9565b6118f1816040518060400160405280600d81526020016c1b5a5b9a5b5d5b509d5e555cd9609a1b815250613576565b600955565b6118fe6132e9565b600755565b61190b6132e9565b611913613598565b565b61191d61328d565b60145460408051808201909152600681526539b4b3b732b960d11b6020820152611950916001600160a01b03169061336e565b8342111561198a5760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b60448201526064016110cb565b5f6119d883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506119d292508b91508a905089896135ea565b906136a0565b6014549091506001600160a01b03808316911614611a225760405162461bcd60e51b81526020600482015260076024820152666261642073696760c81b60448201526064016110cb565b6001600160a01b0387165f90815260166020526040902054861015611a795760405162461bcd60e51b815260206004820152600d60248201526c6e6f6e2d6d6f6e6f746f6e696360981b60448201526064016110cb565b505050506001600160a01b03929092165f9081526016602052604090205550565b60208052815f5260405f208181548110611ab2575f80fd5b5f91825260209091206003909102018054600182015460029092015490935090915083565b6002546040516370a0823160e01b81523060048201525f9182916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611b25573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b499190615112565b90505f60075460065411611b5d575f611b6d565b600754600654611b6d919061513d565b9050818110611b7c5781611b7e565b805b9250505090565b600b8181548110611b94575f80fd5b5f91825260209091200154905081565b611bac6132e9565b611bd581604051806040016040528060078152602001661c185e5b595b9d60ca1b81525061336e565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b611bff61328d565b6017546001600160a01b0316611c285760405163eac0d38960e01b81526004016110cb906151c1565b611c6c8787878787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508992506136ca915050565b50505050505050565b5f5f5f611c806136da565b90508015611c92576001939092509050565b601f5460ff168015611ca65750601e544210155b15611cb657506002925f92509050565b505f928392509050565b611cc86132e9565b6119135f61379e565b611cd96132e9565b60405163a7d2664960e01b815260040160405180910390fd5b611cfa6132e9565b6008805460ff19811660ff90911615179055565b611d166132e9565b611d43816040518060400160405280600b81526020016a7075626c6963507269636560a81b815250613576565b601f5460ff168015611d575750601e544210155b15611d75576040516301e3224f60e71b815260040160405180910390fd5b601c80549082905560408051828152602081018490527fdb2f808b5469eed94e6d03074d5839d580bdcc00f06bf1d9e58bf4a9add60b36910160405180910390a15050565b611dc26132e9565b6127108161ffff161115611e035760405162461bcd60e51b81526020600482015260086024820152676270733e3130302560c01b60448201526064016110cb565b6015805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b611e2d61328d565b6017546001600160a01b0316611e565760405163eac0d38960e01b81526004016110cb906151c1565b61113f825f5f5f60405180602001604052805f8152506001876137ed565b611e7c61328d565b611e97815f5f5f60405180602001604052805f8152506132d3565b50565b611ea261328d565b6017546001600160a01b0316611ecb5760405163eac0d38960e01b81526004016110cb906151c1565b611e975f5f5f5f60405180602001604052805f8152506001876137ed565b611ef16132e9565b6119136145c6565b5f5f5f5f5f60045f9054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611f4e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7291906151fb565b9450945050935093505f8313611fb65760405162461bcd60e51b815260206004820152600960248201526862616420707269636560b81b60448201526064016110cb565b610e10611fc3834261513d565b1115611fff5760405162461bcd60e51b815260206004820152600b60248201526a7374616c6520707269636560a81b60448201526064016110cb565b8369ffffffffffffffffffff168169ffffffffffffffffffff161015801561202657505f82115b6120655760405162461bcd60e51b815260206004820152601060248201526f726f756e6420696e636f6d706c65746560801b60448201526064016110cb565b50909392505050565b6120766132e9565b601955565b5f5f612085611ef9565b9050670de0b6b3a764000060045f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121049190615249565b61210f906012615264565b61211a90600a615360565b612124838661518b565b61212e919061518b565b61213891906151a2565b9392505050565b6121476132e9565b61217081604051806040016040528060078152602001667374616b696e6760c81b81525061336e565b601780546001600160a01b0319166001600160a01b0392909216919091179055565b61219a6132e9565b5f868152601860205260409020805487146121cb5760405163213975eb60e01b8152600481018890526024016110cb565b60648611156122055760405163589956a560e11b8152602060048201526005602482015264626f6e757360d81b60448201526064016110cb565b61221087858561353f565b806006015482101561224c5760068101546040516317c5e69960e01b8152600481018990526024810184905260448101919091526064016110cb565b612257878585614603565b6001810186905560028101859055600381018490556004810183905560058101805490839055604080518281526020810185905289917fff4c985d0c54731f2fd581dfae5af208edee7e2ced78baa1e9ac1fd03ebe1bc0910160405180910390a26040805188815260208101889052908101869052606081018590526080810184905288907f85691ece3b5cb16ac00911efb4d9dfadc0fe04f47d8acaa92f8acdea6ae27b809060a00160405180910390a25050505050505050565b61231b613315565b61232361328d565b601154335f908152600f6020526040812054909161234091615150565b90508042101561236657604051630eb71c9760e41b8152600481018290526024016110cb565b335f908152600d602052604081205490600146148061238757504662aa36a7145b1561239557506012546123cd565b46603814806123a45750466061145b156123b257506013546123cd565b604051631874ab9360e31b81524660048201526024016110cb565b808210156123f857604051631014af1b60e21b815260048101829052602481018390526044016110cb565b81600e54101561241b5760405163a3e0846f60e01b815260040160405180910390fd5b335f908152600d60205260408120819055600e805484929061243e90849061513d565b9091555050335f818152600f6020908152604080832042908190558280528184208251606081018452888152808501928352438185019081528254600181810185559388528688209251600390910290920191825592519181019190915590516002909101559282526010905290812080548492906124be908490615150565b90915550506040515f90339084908381818185875af1925050503d805f8114612502576040519150601f19603f3d011682016040523d82523d5f602084013e612507565b606091505b505090508061252957604051632ee66eed60e01b815260040160405180910390fd5b335f81815260106020526040908190205490517fbda0558246f195546ecc523f23162b871fd8da11710453e986bb762d620175869161257c91879142919283526020830191909152604082015260600190565b60405180910390a25050505061191360018055565b5f5f5f61259d846125c0565b915091508082116125ae575f6125b8565b6125b8818361513d565b949350505050565b5f5f825f036125d357505f928392509050565b50505f81815260186020908152604091829020825160e08101845281548152600180830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a0840181905260069091015460c08401819052909290915b84811015612702575f81815260186020908152604091829020825160e08101845281548082526001830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a08401526006015460c083015282146126ae57506126fa565b806080015142116126bf5750612702565b5f8160c001518260a00151116126d5575f6126e9565b8160c001518260a001516126e9919061513d565b90506126f58187615150565b955050505b60010161263d565b5050915091565b5f5f5f612714611c75565b90925090505f82600281111561272c5761272c614fe2565b0361273a57505f9392505050565b5f80600184600281111561275057612750614fe2565b036127b95750505f81815260186020908152604091829020825160e08101845281548152600182015492810183905260028201549381018490526003820154606082015260048201546080820152600582015460a082015260069091015460c0909101526127c2565b5050601c54601d545b5f6127ce87848461477a565b90505f600754600654116127e2575f6127f2565b6007546006546127f2919061513d565b905080821115612800578091505b6002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa15801561284b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061286f9190615112565b90508083111561287d578092505b600187600281111561289157612891614fe2565b036128cf575f5f6128a1886125c0565b915091505f8183116128b3575f6128bd565b6128bd828461513d565b9050808611156128cb578095505b5050505b5090979650505050505050565b6128e461328d565b6119135f5f5f5f60405180602001604052805f8152506132d3565b6129076132e9565b611e975f82614840565b6129196132e9565b611e97600182614840565b600a8181548110611b94575f80fd5b61293b6132e9565b612943613315565b600e544790811161296757604051630686827b60e51b815260040160405180910390fd5b5f600e5482612976919061513d565b6040519091505f90339083908381818185875af1925050503d805f81146129b8576040519150601f19603f3d011682016040523d82523d5f602084013e6129bd565b606091505b50509050806129df57604051632ee66eed60e01b815260040160405180910390fd5b60405182815233907feaff4b37086828766ad3268786972c0cd24259d4c87a80f9d3963a3c3d999b0d9060200160405180910390a250505061191360018055565b6001600160a01b0381165f908152601660205260408120549080612a43836117bd565b9150612a4e8361492c565b929491935050565b5f5f5f612a61611c75565b90925090505f826002811115612a7957612a79614fe2565b03612a8757505f9392505050565b5f806001846002811115612a9d57612a9d614fe2565b03612b065750505f81815260186020908152604091829020825160e08101845281548152600182015492810183905260028201549381018490526003820154606082015260048201546080820152600582015460a082015260069091015460c090910152612b0f565b5050601c54601d545b612b1a8683836133ee565b9695505050505050565b612b2c6132e9565b601f5460ff168015612b405750601e544210155b15612b5e576040516301e3224f60e71b815260040160405180910390fd5b612b8b846040518060400160405280600b81526020016a7075626c6963507269636560a81b815250613576565b6064831115612bcb5760405163589956a560e11b815260206004820152600b60248201526a7075626c6963426f6e757360a81b60448201526064016110cb565b604080516080808201835286825260208083018790528284018690528415156060938401819052601c899055601d889055601e879055601f805460ff1916821790558451898152918201889052938101869052918201929092527f05a3ff2b79c8d3a61428aeacdd316adc30b6a97a6b36b34894efa4ffcac9f753910160405180910390a150505050565b612c5e6132e9565b612c86816040518060400160405280600681526020016539b4b3b732b960d11b81525061336e565b601480546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381165f908152600c60209081526040808320546016909252822054808211612cd857806125b8565b5092915050565b612ce76132e9565b5f82815260186020526040902080548314612d185760405163213975eb60e01b8152600481018490526024016110cb565b80600301544210612d3f576040516397db424160e01b8152600481018490526024016110cb565b4282111580612d52575080600401548210155b15612d73576040516397db424160e01b8152600481018490526024016110cb565b6001831115612e2c575f601881612d8b60018761513d565b81526020019081526020015f206040518060e00160405290815f820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050600184612df7919061513d565b8151148015612e095750806080015183105b15612e2a57604051637437e81760e01b8152600481018590526024016110cb565b505b60038101829055600481015460405184917f74064869fb3619f32eb8e86259fe1d5051e6d16ce61718dad7d2420bcfe0fcc89161143e91868252602082015260400190565b612e796132e9565b612ea7816040518060400160405280600c81526020016b199959549958da5c1a595b9d60a21b81525061336e565b601580546001600160a01b0319166001600160a01b0392909216919091179055565b5f5f5f612ed4611c75565b90925090505f826002811115612eec57612eec614fe2565b03612ef9575f9250505090565b5f6001836002811115612f0e57612f0e614fe2565b03612ff3575f5f612f1e846125c0565b915091505f818311612f30575f612f3a565b612f3a828461513d565b6002546040516370a0823160e01b81523060048201529192505f916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015612f89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fad9190615112565b90505f60075460065411612fc1575f612fd1565b600754600654612fd1919061513d565b905080831115612fdf578092505b81831115612feb578192505b509093505050505b601f545f9060ff1680156130095750601e544210155b15613109576002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015613059573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061307d9190615112565b90505f60075460065411613091575f6130a1565b6007546006546130a1919061513d565b90505f8482116130b1575f6130bb565b6130bb858361513d565b90505f8584116130cb575f6130d5565b6130d5868561513d565b90505f8183106130e557816130e7565b825b9050801561310357601c54601d546131009183916133ee565b95505b50505050505b5f600185600281111561311e5761311e614fe2565b14801561312a57505f83115b1561319c575f84815260186020908152604091829020825160e08101845281548152600182015492810183905260028201549381018490526003820154606082015260048201546080820152600582015460a082015260069091015460c082015291613198918691906133ee565b9150505b6131a68282615150565b9550505050505090565b6001600160a01b0381165f908152600c6020908152604080832054600d90925282205490918080806131e1866117bd565b6011546001600160a01b0389165f908152600f602052604090205491955061320891615150565b6001600160a01b0388165f9081526010602052604090205490935061322e908690615150565b6001600160a01b039097165f9081526020805260409020549597949693959294915050565b61325b6132e9565b6001600160a01b03811661328457604051631e4fbdf760e01b81525f60048201526024016110cb565b611e978161379e565b60025460ff16156119135760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016110cb565b6132e285858585855f5f6137ed565b5050505050565b5f546001600160a01b031633146119135760405163118cdaa760e01b81523360048201526024016110cb565b6002600154036133675760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016110cb565b6002600155565b6001600160a01b03821661113f578060405163eac0d38960e01b81526004016110cb919061536e565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526133e990849061498d565b505050565b5f5f60035f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613440573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134649190615249565b60ff1690505f613475846064615150565b61348087606461518b565b61348a91906151a2565b90505f61349883600a6153a3565b6134a2878461518b565b6134ac91906151a2565b90505f6134c0670de0b6b3a764000061207b565b9050805f036134ff5760405163589956a560e11b815260206004820152600a602482015269707269636544656e6f6d60b01b60448201526064016110cb565b8060018161351585670de0b6b3a764000061518b565b61351f9190615150565b613529919061513d565b61353391906151a2565b98975050505050505050565b81158061354a575080155b806135555750808210155b156133e9576040516397db424160e01b8152600481018490526024016110cb565b815f0361113f578060405163589956a560e11b81526004016110cb919061536e565b6135a06149f9565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b604080517ffa8b458545377bec9568500b00b33c407fe4f3b1f74043a0f121d056b1562b836020808301919091526001600160a01b0396909616818301526060810194909452608084019290925260a0808401919091528151808403909101815260c0830182528051908401207f19457468657265756d205369676e6564204d6573736167653a0a33320000000060e084015260fc808401919091528151808403909101815261011c9092019052805191012090565b5f5f5f5f6136ae8686614a42565b9250925092506136be8282614a8b565b50909150505b92915050565b610fb986868686866001876137ed565b5f601a545f036136e957505f90565b60015b601a548111613797575f81815260186020908152604091829020825160e0810184528154815260018201549281019290925260028101549282019290925260038201546060820181905260048301546080830152600583015460a083015260069092015460c0820152904210801590613769575080608001514211155b15613784578060a001518160c0015110156137845750919050565b508061378f816153ae565b9150506136ec565b505f905090565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6137f5613315565b60085460ff166138185760405163b7b2409760e01b815260040160405180910390fd5b345f036138545760405163589956a560e11b81526020600482015260096024820152686d73672e76616c756560b81b60448201526064016110cb565b6138956040518060e001604052805f81526020015f81526020015f81526020015f81526020015f60ff1681526020015f60ff1681526020015f151581525090565b6001600160a01b038816158015906138b657506001600160a01b0388163314155b15613b4c576001600160a01b0388165f908152600c60205260409020546138de816001615150565b606083015284511561399f5760145460408051808201909152600681526539b4b3b732b960d11b602082015261391d916001600160a01b03169061336e565b8642111561395b5760405162461bcd60e51b815260206004820152600b60248201526a185d1d08195e1c1a5c995960aa1b60448201526064016110cb565b5f61396c866119d28c8c8c8c6135ea565b6014549091506001600160a01b038083169116148015613990575082606001518910155b1561399d57600160c08401525b505b6001600160a01b0389165f9081526016602052604090205460c08301516139db57826060015181116139d55782606001516139dd565b806139dd565b885b60408401526139eb8161492c565b60ff1660808401526040830151613a019061492c565b60ff1660a084015260c08301518015613a275750826080015160ff168360a0015160ff16115b15613b135760155460408051808201909152600c81526b199959549958da5c1a595b9d60a21b6020820152613a65916001600160a01b03169061336e565b613a8e876040518060400160405280600781526020016673796e6346656560c81b815250613576565b86341015613ab85760405163ed82eac160e01b8152600481018890523460248201526044016110cb565b6015545f9061271090613ad690600160a01b900461ffff163461518b565b613ae091906151a2565b905080881115613b0d5760405163ea4749c160e01b815260048101899052602481018290526044016110cb565b50613b32565b8615613b32576040516381a3e9d160e01b815260040160405180910390fd5b613b3f83604001516117bd565b602084015250613b6b9050565b8415613b6b576040516381a3e9d160e01b815260040160405180910390fd5b5f613b76863461513d565b9050805f03613bb85760405163589956a560e11b815260206004820152600d60248201526c707572636861736556616c756560981b60448201526064016110cb565b600954613bc48261207b565b1015613be357604051633093be2760e11b815260040160405180910390fd5b5f8080613bf0818561513d565b90505b8015613f05575f5f613c03611c75565b90925090506001826002811115613c1c57613c1c614fe2565b14613c28575050613f05565b613c3181614b43565b5f818152601860209081526040808320815160e081018352815481526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a0830181905260069091015460c0830181905291929110613ca0575f613cb4565b8160c001518260a00151613cb4919061513d565b9050805f03613cc65750505050613bf3565b5f613cda868460400151856020015161477a565b9050805f03613ced575050505050613f05565b6002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015613d38573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d5c9190615112565b90505f60075460065411613d70575f613d80565b600754600654613d80919061513d565b90505f8a8211613d90575f613d9a565b613d9a8b8361513d565b90505f8b8411613daa575f613db4565b613db48c8561513d565b90508582811115613dc25750815b81811115613dcd5750805b805f03613de35750505050505050505050613f05565b808611613e72575f613dfe878a604001518b602001516133ee565b90508b811115613e0b57508a5b805f03613e22575050505050505050505050613f05565b5f8a81526018602052604081206006018054899290613e42908490615150565b90915550613e529050878f615150565b9d50613e5e818e615150565b9c50613e6a818d61513d565b9b5050613ef6565b5f613e86828a604001518b602001516133ee565b90508b811115613e9357508a5b805f03613eaa575050505050505050505050613f05565b5f8a81526018602052604081206006018054849290613eca908490615150565b90915550613eda9050828f615150565b9d50613ee6818e615150565b9c50613ef2818d61513d565b9b50505b50505050505050505050613bf3565b505f613f11828561513d565b9050801561408c575f613f22611c75565b5090506002816002811115613f3957613f39614fe2565b14613f57576040516331f423c160e21b815260040160405180910390fd5b5f613f6c83601c5f0154601c6001015461477a565b6002546040516370a0823160e01b81523060048201529192505f916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015613fbb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613fdf9190615112565b90505f60075460065411613ff3575f614003565b600754600654614003919061513d565b90505f878211614013575f61401d565b61401d888361513d565b90505f88841161402d575f614037565b614037898561513d565b90505f8183106140475781614049565b825b90508086111561406c57604051631092d60960e31b815260040160405180910390fd5b614076868b615150565b9950614082888a615150565b9850505050505050505b508281146140ad576040516349db855d60e11b815260040160405180910390fd5b815f036140eb5760405163589956a560e11b815260206004820152600b60248201526a1d1bdad95b9cd51bdd185b60aa1b60448201526064016110cb565b8160075f8282546140fc9190615150565b909155505f90506001600160a01b038c161580159061412457506001600160a01b038c163314155b801561413357505f8560200151115b1561420a57606485602001518561414a919061518b565b61415491906151a2565b6001600160a01b038d165f908152600d6020526040812080549293508392909190614180908490615150565b9250508190555080600e5f8282546141989190615150565b909155505060608501516001600160a01b038d165f908152600c602052604090205560c085015180156141e657506001600160a01b038c165f90815260166020526040908190205490860151115b1561420a576040808601516001600160a01b038e165f908152601660205291909120555b8460c0015180156142285750846080015160ff168560a0015160ff16115b15614329576015546040515f916001600160a01b0316908b908381818185875af1925050503d805f8114614277576040519150601f19603f3d011682016040523d82523d5f602084013e61427c565b606091505b50509050806142c45760405162461bcd60e51b81526020600482015260146024820152731cde5b98c8199959481e19995c8819985a5b195960621b60448201526064016110cb565b60808087015160a08801516040808a0151815160ff948516815293909216602084015282018d905260608201526001600160a01b038f16917f97c2e0ed1152da7606a66de340db9914d8a9adf6b7c6bb511355f6c9fae9bbe4910160405180910390a2505b8661434f5760025461434a9061010090046001600160a01b03163385613397565b61445a565b6017546001600160a01b03166143785760405163eac0d38960e01b81526004016110cb906151c1565b60175460025461439a916001600160a01b036101009092048216911685613397565b60175460405163200d69b160e21b81523360048201526024810185905260ff881660448201525f916001600160a01b031690638035a6c4906064016020604051808303815f875af11580156143f1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144159190615112565b6040805160ff8a16815260208101879052919250829133917f49b72192b6d6993c4b6f8e281f1e6ead3948764836d596c9864c72aa7da9559e910160405180910390a3505b5f614465828661513d565b6005546040805180820190915260078152661c185e5b595b9d60ca1b602082015291925061449e916001600160a01b039091169061336e565b6005546040515f916001600160a01b03169083908381818185875af1925050503d805f81146144e8576040519150601f19603f3d011682016040523d82523d5f602084013e6144ed565b606091505b505090508061450f57604051632ee66eed60e01b815260040160405180910390fd5b5f6145198761207b565b90506001600160a01b038f161580159061453657505f8860200151115b156145b557336001600160a01b03168f6001600160a01b03167f21a585c6e206cdf092092c3c9823edfa9f2da82c6fb0356215ef2981edea0707838a888d602001518e604001516040516145ac959493929190948552602085019390935260408401919091526060830152608082015260a00190565b60405180910390a35b5050505050505050611c6c60018055565b6145ce61328d565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135cd3390565b60018311156146bc575f60188161461b60018761513d565b81526020019081526020015f206040518060e00160405290815f820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050600184614687919061513d565b81511480156146995750806080015183105b156146ba57604051637437e81760e01b8152600481018590526024016110cb565b505b601a548310156133e9575f6018816146d5866001615150565b81526020019081526020015f206040518060e00160405290815f8201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152505090508360016147419190615150565b81511480156147535750806060015182115b1561477457604051637437e81760e01b8152600481018590526024016110cb565b50505050565b5f5f6147858561207b565b90505f60035f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156147d8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906147fc9190615249565b60ff16905061480c85606461518b565b614817856064615150565b61482283600a6153a3565b61482c908561518b565b614836919061518b565b612b1a91906151a2565b6148a18183614875576040518060400160405280600e81526020016d36b4b72932b332b93930b621373160911b815250613576565b6040518060400160405280600e81526020016d0dad2dca4cacccae4e4c2d88ae8d60931b815250613576565b81156148ee57601280549082905560408051828152602081018490527fc56a0ee2629ef404bb6fe2387c705f2ffb6534aed14846dfffd5cc6dcf79cbe991015b60405180910390a1505050565b601380549082905560408051828152602081018490527faef4b147818441ea163ba8de03e7d561e33d9a8dbc7b74b59e9bf4024428de8191016148e1565b5f805b600a5460ff8216101561498457600a8160ff168154811061495257614952615177565b905f5260205f200154831061497257600a546121389060ff83169061513d565b8061497c816153c6565b91505061492f565b50600192915050565b5f5f60205f8451602086015f885af1806149ac576040513d5f823e3d81fd5b50505f513d915081156149c35780600114156149d0565b6001600160a01b0384163b155b1561477457604051635274afe760e01b81526001600160a01b03851660048201526024016110cb565b60025460ff166119135760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016110cb565b5f5f5f8351604103614a79576020840151604085015160608601515f1a614a6b88828585614c60565b955095509550505050614a84565b505081515f91506002905b9250925092565b5f826003811115614a9e57614a9e614fe2565b03614aa7575050565b6001826003811115614abb57614abb614fe2565b03614ad95760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115614aed57614aed614fe2565b03614b0e5760405163fce698f760e01b8152600481018290526024016110cb565b6003826003811115614b2257614b22614fe2565b0361113f576040516335e2f38360e21b8152600481018290526024016110cb565b60018111614b4e5750565b5f601b546001614b5e9190615150565b9050818110614b6b575050565b81811015614c4e575f81815260186020526040902080548214614b8e5750614c46565b80600401544211614b9f5750614c4e565b5f8160060154826005015411614bb5575f614bc9565b81600601548260050154614bc9919061513d565b9050805f03614bd9575050614c46565b60068201546005808401919091555f8581526018602052604081209091018054839290614c07908490615150565b9091555050604051818152849084907faa1e781edf243a8b1b82cde778cbbcc2375e35cf108adaed7814c05230be20a89060200160405180910390a350505b600101614b6b565b614c5960018261513d565b601b555050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115614c9957505f91506003905082614d1e565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015614cea573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116614d1557505f925060019150829050614d1e565b92505f91508190505b9450945094915050565b80356001600160a01b0381168114614d3e575f5ffd5b919050565b5f5f83601f840112614d53575f5ffd5b50813567ffffffffffffffff811115614d6a575f5ffd5b602083019150836020828501011115614d81575f5ffd5b9250929050565b5f5f5f5f5f5f60a08789031215614d9d575f5ffd5b614da687614d28565b9550602087013594506040870135935060608701359250608087013567ffffffffffffffff811115614dd6575f5ffd5b614de289828a01614d43565b979a9699509497509295939492505050565b5f5f60408385031215614e05575f5ffd5b614e0e83614d28565b946020939093013593505050565b5f60208284031215614e2c575f5ffd5b61213882614d28565b5f5f5f60608486031215614e47575f5ffd5b614e5084614d28565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b81811015614ebb57614ea58385518051825260208082015190830152604090810151910152565b6020939093019260609290920191600101614e7e565b509095945050505050565b5f5f60408385031215614ed7575f5ffd5b50508035926020909101359150565b815181526020808301519082015260408083015190820152606081016136c4565b5f5f5f5f5f60a08688031215614f1b575f5ffd5b505083359560208501359550604085013594606081013594506080013592509050565b5f60208284031215614f4e575f5ffd5b5035919050565b60ff81168114611e97575f5ffd5b5f5f5f5f5f5f5f60c0888a031215614f79575f5ffd5b614f8288614d28565b9650602088013595506040880135945060608801359350608088013567ffffffffffffffff811115614fb2575f5ffd5b614fbe8a828b01614d43565b90945092505060a0880135614fd281614f55565b8091505092959891949750929550565b634e487b7160e01b5f52602160045260245ffd5b604081016003841061501657634e487b7160e01b5f52602160045260245ffd5b9281526020015290565b5f60208284031215615030575f5ffd5b813561ffff81168114612138575f5ffd5b5f5f60408385031215615052575f5ffd5b61505b83614d28565b9150602083013561506b81614f55565b809150509250929050565b5f60208284031215615086575f5ffd5b813561213881614f55565b5f5f5f5f5f5f60c087890312156150a6575f5ffd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b5f5f5f5f608085870312156150e3575f5ffd5b84359350602085013592506040850135915060608501358015158114615107575f5ffd5b939692955090935050565b5f60208284031215615122575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156136c4576136c4615129565b808201808211156136c4576136c4615129565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b80820281158282048414176136c4576136c4615129565b5f826151bc57634e487b7160e01b5f52601260045260245ffd5b500490565b6020808252600790820152667374616b696e6760c81b604082015260600190565b805169ffffffffffffffffffff81168114614d3e575f5ffd5b5f5f5f5f5f60a0868803121561520f575f5ffd5b615218866151e2565b6020870151604088015160608901519297509095509350915061523d608087016151e2565b90509295509295909350565b5f60208284031215615259575f5ffd5b815161213881614f55565b60ff82811682821603908111156136c4576136c4615129565b6001815b60018411156152b85780850481111561529c5761529c615129565b60018416156152aa57908102905b60019390931c928002615281565b935093915050565b5f826152ce575060016136c4565b816152da57505f6136c4565b81600181146152f057600281146152fa57615316565b60019150506136c4565b60ff84111561530b5761530b615129565b50506001821b6136c4565b5060208310610133831016604e8410600b8410161715615339575081810a6136c4565b6153455f19848461527d565b805f190482111561535857615358615129565b029392505050565b5f61213860ff8416836152c0565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f61213883836152c0565b5f600182016153bf576153bf615129565b5060010190565b5f60ff821660ff81036153db576153db615129565b6001019291505056fea2646970667358221220081a0aa408b4c5375b449601a32c3ff7948ec578104e09554cf5bcfcdc7aa17c64736f6c634300081e0033000000000000000000000000648b478c5142072610ffc1ccdc081fd632a14247000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841900000000000000000000000000000000000000000000000000027ca57357c0000000000000000000000000000000000000000000000000000007d0e36a818000

Deployed Bytecode

0x60806040526004361061048f575f3560e01c806382870f6411610257578063c7ea0c511161013f578063e3245933116100be578063f1eb6db811610083578063f1eb6db814610ece578063f2fde38b14610ee3578063f5b2cad714610f02578063f6eeddfd14610f21578063fc0c546a14610f36578063fd69f25414610f5a575f5ffd5b8063e324593314610dfb578063e4fae6da14610e0f578063e918032314610e42578063ebe6c9ff14610e8e578063ec45127a14610eb9575f5ffd5b8063d43449b611610104578063d43449b614610d6a578063d6c89c6014610d89578063db74559b14610d9e578063dbfce1da14610dbd578063e06ebb4114610ddc575f5ffd5b8063c7ea0c5114610ca5578063c8123eb814610ce2578063ccf01f0114610d01578063cec297a014610d20578063d3f2407b14610d4b575f5ffd5b8063909d6283116101d6578063a24bcf461161019b578063a24bcf4614610c0d578063a482171914610c2c578063a70184ce14610c34578063adca184d14610c53578063b70dcf3514610c72578063c264a06314610c91575f5ffd5b8063909d628314610b725780639106d7ba14610b9157806391ca7f3c14610ba657806398585c5014610bba5780639aa89d4214610bd9575f5ffd5b80638b1903761161021c5780638b19037614610ae45780638b250eff14610b035780638c733fdf14610b185780638da5cb5b14610b375780638ff3909914610b53575f5ffd5b806382870f64146109eb5780638456cb59146109fe578063845ddcb214610a1257806384b3997c14610a9d578063875a682a14610ad0575f5ffd5b80634571a7f11161037a5780636dbbbb59116102f957806378e29afd116102be57806378e29afd14610953578063791a2519146109725780637b5e6b9e146109915780637d7511bb146109b05780637e72fb52146109c357806381bf4425146109d6575f5ffd5b80636dbbbb59146108cb578063715018a6146108ed578063724e78da14610901578063741bef1a14610920578063773110491461093f575f5ffd5b806359f679e51161033f57806359f679e5146108445780635c975abb146108635780635e1e10041461087a57806360e6512114610899578063633423be146108ac575f5ffd5b80634571a7f1146107815780634a56c9a7146107965780634a7e588c146107d05780634cf088d9146107e457806353135ca01461081b575f5ffd5b80632d705e831161041157806337851598116103d657806337851598146106a557806339ce1089146106c45780633f4ba83a146106ef57806340154c40146107035780634468e8741461072257806344fec8eb1461074d575f5ffd5b80632d705e83146105e25780633114740e146106015780633151338e14610620578063328a77261461063f57806333bc1c5c1461065e575f5ffd5b8063144fa6d711610457578063144fa6d7146105505780631ba705781461056f578063200f366014610583578063219666bb14610597578063285d7aff146105c3575f5ffd5b806302f659631461049357806306b091f9146104a85780630a64143a146104c75780630fe93211146105055780631053234714610531575b5f5ffd5b6104a66104a1366004614d88565b610f6f565b005b3480156104b3575f5ffd5b506104a66104c2366004614df4565b610fc1565b3480156104d2575f5ffd5b506104f26104e1366004614e1c565b60106020525f908152604090205481565b6040519081526020015b60405180910390f35b348015610510575f5ffd5b5061052461051f366004614e35565b611143565b6040516104fc9190614e65565b34801561053c575f5ffd5b506104a661054b366004614ec6565b6112b1565b34801561055b575f5ffd5b506104a661056a366004614e1c565b61144b565b34801561057a575f5ffd5b506104f261146c565b34801561058e575f5ffd5b506104f26114a2565b3480156105a2575f5ffd5b506105b66105b1366004614e1c565b6114f1565b6040516104fc9190614ee6565b3480156105ce575f5ffd5b506104a66105dd366004614f07565b6115cd565b3480156105ed575f5ffd5b506104f26105fc366004614f3e565b6117bd565b34801561060c575f5ffd5b5061052461061b366004614e1c565b611820565b34801561062b575f5ffd5b506104a661063a366004614f3e565b6118ad565b34801561064a575f5ffd5b506104a6610659366004614f3e565b6118ba565b348015610669575f5ffd5b50601c54601d54601e54601f546106839392919060ff1684565b60408051948552602085019390935291830152151560608201526080016104fc565b3480156106b0575f5ffd5b506104a66106bf366004614f3e565b6118f6565b3480156106cf575f5ffd5b506104f26106de366004614e1c565b60166020525f908152604090205481565b3480156106fa575f5ffd5b506104a6611903565b34801561070e575f5ffd5b506104a661071d366004614d88565b611915565b34801561072d575f5ffd5b506104f261073c366004614e1c565b600d6020525f908152604090205481565b348015610758575f5ffd5b5060155461076e90600160a01b900461ffff1681565b60405161ffff90911681526020016104fc565b34801561078c575f5ffd5b506104f260195481565b3480156107a1575f5ffd5b506107b56107b0366004614df4565b611a9a565b604080519384526020840192909252908201526060016104fc565b3480156107db575f5ffd5b506104f2611ad7565b3480156107ef575f5ffd5b50601754610803906001600160a01b031681565b6040516001600160a01b0390911681526020016104fc565b348015610826575f5ffd5b506008546108349060ff1681565b60405190151581526020016104fc565b34801561084f575f5ffd5b506104f261085e366004614f3e565b611b85565b34801561086e575f5ffd5b5060025460ff16610834565b348015610885575f5ffd5b506104a6610894366004614e1c565b611ba4565b6104a66108a7366004614f63565b611bf7565b3480156108b7575f5ffd5b50600554610803906001600160a01b031681565b3480156108d6575f5ffd5b506108df611c75565b6040516104fc929190614ff6565b3480156108f8575f5ffd5b506104a6611cc0565b34801561090c575f5ffd5b506104a661091b366004614e1c565b611cd1565b34801561092b575f5ffd5b50600454610803906001600160a01b031681565b34801561094a575f5ffd5b506104a6611cf2565b34801561095e575f5ffd5b50601554610803906001600160a01b031681565b34801561097d575f5ffd5b506104a661098c366004614f3e565b611d0e565b34801561099c575f5ffd5b506104a66109ab366004615020565b611dba565b6104a66109be366004615041565b611e25565b6104a66109d1366004614e1c565b611e74565b3480156109e1575f5ffd5b506104f2600e5481565b6104a66109f9366004615076565b611e9a565b348015610a09575f5ffd5b506104a6611ee9565b348015610a1d575f5ffd5b50610a68610a2c366004614f3e565b60186020525f90815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016104fc565b348015610aa8575f5ffd5b506104f27ffa8b458545377bec9568500b00b33c407fe4f3b1f74043a0f121d056b1562b8381565b348015610adb575f5ffd5b506104f2611ef9565b348015610aef575f5ffd5b506104a6610afe366004614f3e565b61206e565b348015610b0e575f5ffd5b506104f260065481565b348015610b23575f5ffd5b506104f2610b32366004614f3e565b61207b565b348015610b42575f5ffd5b505f546001600160a01b0316610803565b348015610b5e575f5ffd5b506104a6610b6d366004614e1c565b61213f565b348015610b7d575f5ffd5b506104a6610b8c366004615091565b612192565b348015610b9c575f5ffd5b506104f260075481565b348015610bb1575f5ffd5b506104a6612313565b348015610bc5575f5ffd5b506104f2610bd4366004614f3e565b612591565b348015610be4575f5ffd5b50610bf8610bf3366004614f3e565b6125c0565b604080519283526020830191909152016104fc565b348015610c18575f5ffd5b506104f2610c27366004614f3e565b612709565b6104a66128dc565b348015610c3f575f5ffd5b506104a6610c4e366004614f3e565b6128ff565b348015610c5e575f5ffd5b506104a6610c6d366004614f3e565b612911565b348015610c7d575f5ffd5b506104f2610c8c366004614f3e565b612924565b348015610c9c575f5ffd5b506104a6612933565b348015610cb0575f5ffd5b50610cc4610cbf366004614e1c565b612a20565b60408051938452602084019290925260ff16908201526060016104fc565b348015610ced575f5ffd5b506104f2610cfc366004614f3e565b612a56565b348015610d0c575f5ffd5b50601454610803906001600160a01b031681565b348015610d2b575f5ffd5b506104f2610d3a366004614e1c565b600c6020525f908152604090205481565b348015610d56575f5ffd5b506104a6610d653660046150d0565b612b24565b348015610d75575f5ffd5b506104a6610d84366004614e1c565b612c56565b348015610d94575f5ffd5b506104f260115481565b348015610da9575f5ffd5b506104f2610db8366004614e1c565b612ca8565b348015610dc8575f5ffd5b506104a6610dd7366004614ec6565b612cdf565b348015610de7575f5ffd5b506104a6610df6366004614e1c565b612e71565b348015610e06575f5ffd5b506104f2612ec9565b348015610e1a575f5ffd5b506104f2610e29366004614e1c565b6001600160a01b03165f90815260208052604090205490565b348015610e4d575f5ffd5b50610e61610e5c366004614e1c565b6131b0565b604080519687526020870195909552938501929092526060840152608083015260a082015260c0016104fc565b348015610e99575f5ffd5b506104f2610ea8366004614e1c565b600f6020525f908152604090205481565b348015610ec4575f5ffd5b506104f2601a5481565b348015610ed9575f5ffd5b506104f260135481565b348015610eee575f5ffd5b506104a6610efd366004614e1c565b613253565b348015610f0d575f5ffd5b50600354610803906001600160a01b031681565b348015610f2c575f5ffd5b506104f260095481565b348015610f41575f5ffd5b506002546108039061010090046001600160a01b031681565b348015610f65575f5ffd5b506104f260125481565b610f7761328d565b610fb98686868686868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506132d392505050565b505050505050565b610fc96132e9565b610fd1613315565b610ff58260405180604001604052806002815260200161746f60f01b81525061336e565b6002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015611040573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110649190615112565b90505f60075460065411611078575f611088565b600754600654611088919061513d565b90505f818311611098575f6110a2565b6110a2828461513d565b9050808411156110d4576040516371d63b8360e01b815260048101859052602481018290526044015b60405180910390fd5b6002546110f09061010090046001600160a01b03168686613397565b846001600160a01b03167f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b8560405161112b91815260200190565b60405180910390a250505061113f60018055565b5050565b6001600160a01b0383165f908152602080526040902080546060919084106111935760405162461bcd60e51b815260206004820152600360248201526237b7b160e91b60448201526064016110cb565b5f61119e8486615150565b82549091508111156111ae575080545b5f6111b9868361513d565b67ffffffffffffffff8111156111d1576111d1615163565b60405190808252806020026020018201604052801561122357816020015b61121060405180606001604052805f81526020015f81526020015f81525090565b8152602001906001900390816111ef5790505b509050855b828110156112a65783818154811061124257611242615177565b905f5260205f2090600302016040518060600160405290815f820154815260200160018201548152602001600282015481525050828883611283919061513d565b8151811061129357611293615177565b6020908102919091010152600101611228565b509695505050505050565b6112b96132e9565b5f828152601860205260409020805483146112ea5760405163213975eb60e01b8152600481018490526024016110cb565b80600401544210611311576040516397db424160e01b8152600481018490526024016110cb565b80600301548211158061132357504282105b15611344576040516397db424160e01b8152600481018490526024016110cb565b601a548310156113fe575f60188161135d866001615150565b81526020019081526020015f206040518060e00160405290815f8201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152505090508360016113c99190615150565b81511480156113db5750806060015183115b156113fc57604051637437e81760e01b8152600481018590526024016110cb565b505b600481018290556003810154604080519182526020820184905284917f74064869fb3619f32eb8e86259fe1d5051e6d16ce61718dad7d2420bcfe0fcc891015b60405180910390a2505050565b6114536132e9565b604051633a0477af60e21b815260040160405180910390fd5b5f61147e670de0b6b3a764000061207b565b60095461149390670de0b6b3a764000061518b565b61149d91906151a2565b905090565b601f545f9060ff1680156114b85750601e544210155b6114c157505f90565b5f6114ca611ad7565b9050805f036114da575f91505090565b601c54601d546114eb9183916133ee565b91505090565b61151260405180606001604052805f81526020015f81526020015f81525090565b6001600160a01b0382165f90815260208052604090205461155e5760405162461bcd60e51b81526004016110cb906020808252600490820152636e6f6e6560e01b604082015260600190565b6001600160a01b0382165f908152602080526040902080546115829060019061513d565b8154811061159257611592615177565b905f5260205f2090600302016040518060600160405290815f8201548152602001600182015481526020016002820154815250509050919050565b6115d56132e9565b5f601a5460016115e59190615150565b905060195481111561160d5760405163213975eb60e01b8152600481018290526024016110cb565b60648611156116475760405163589956a560e11b8152602060048201526005602482015264626f6e757360d81b60448201526064016110cb565b61165281858561353f565b601a54156116ef57601a545f81815260186020908152604091829020825160e08101845281548082526001830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a08401526006015460c083015290911480156116cc5750806080015185105b156116ed57604051637437e81760e01b8152600481018390526024016110cb565b505b601a8190556040805160e081018252828152602080820189815282840189815260608085018a815260808087018b815260a08089018c81525f60c08b018181528d825260188b52908c90209a518b55975160018b0155955160028a01559251600389015551600488015592516005870155925160069095019490945584518b81529283018a905293820188905291810186905291820184905282917f85691ece3b5cb16ac00911efb4d9dfadc0fe04f47d8acaa92f8acdea6ae27b80910160405180910390a2505050505050565b5f805b600a5481101561181857600a81815481106117dd576117dd615177565b905f5260205f200154831061181057600b81815481106117ff576117ff615177565b905f5260205f200154915050919050565b6001016117c0565b505f92915050565b6001600160a01b0381165f90815260208080526040808320805482518185028101850190935280835260609492939192909184015b828210156118a2578382905f5260205f2090600302016040518060600160405290815f82015481526020016001820154815260200160028201548152505081526020019060010190611855565b505050509050919050565b6118b56132e9565b600655565b6118c26132e9565b6118f1816040518060400160405280600d81526020016c1b5a5b9a5b5d5b509d5e555cd9609a1b815250613576565b600955565b6118fe6132e9565b600755565b61190b6132e9565b611913613598565b565b61191d61328d565b60145460408051808201909152600681526539b4b3b732b960d11b6020820152611950916001600160a01b03169061336e565b8342111561198a5760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b60448201526064016110cb565b5f6119d883838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506119d292508b91508a905089896135ea565b906136a0565b6014549091506001600160a01b03808316911614611a225760405162461bcd60e51b81526020600482015260076024820152666261642073696760c81b60448201526064016110cb565b6001600160a01b0387165f90815260166020526040902054861015611a795760405162461bcd60e51b815260206004820152600d60248201526c6e6f6e2d6d6f6e6f746f6e696360981b60448201526064016110cb565b505050506001600160a01b03929092165f9081526016602052604090205550565b60208052815f5260405f208181548110611ab2575f80fd5b5f91825260209091206003909102018054600182015460029092015490935090915083565b6002546040516370a0823160e01b81523060048201525f9182916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611b25573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b499190615112565b90505f60075460065411611b5d575f611b6d565b600754600654611b6d919061513d565b9050818110611b7c5781611b7e565b805b9250505090565b600b8181548110611b94575f80fd5b5f91825260209091200154905081565b611bac6132e9565b611bd581604051806040016040528060078152602001661c185e5b595b9d60ca1b81525061336e565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b611bff61328d565b6017546001600160a01b0316611c285760405163eac0d38960e01b81526004016110cb906151c1565b611c6c8787878787878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508992506136ca915050565b50505050505050565b5f5f5f611c806136da565b90508015611c92576001939092509050565b601f5460ff168015611ca65750601e544210155b15611cb657506002925f92509050565b505f928392509050565b611cc86132e9565b6119135f61379e565b611cd96132e9565b60405163a7d2664960e01b815260040160405180910390fd5b611cfa6132e9565b6008805460ff19811660ff90911615179055565b611d166132e9565b611d43816040518060400160405280600b81526020016a7075626c6963507269636560a81b815250613576565b601f5460ff168015611d575750601e544210155b15611d75576040516301e3224f60e71b815260040160405180910390fd5b601c80549082905560408051828152602081018490527fdb2f808b5469eed94e6d03074d5839d580bdcc00f06bf1d9e58bf4a9add60b36910160405180910390a15050565b611dc26132e9565b6127108161ffff161115611e035760405162461bcd60e51b81526020600482015260086024820152676270733e3130302560c01b60448201526064016110cb565b6015805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b611e2d61328d565b6017546001600160a01b0316611e565760405163eac0d38960e01b81526004016110cb906151c1565b61113f825f5f5f60405180602001604052805f8152506001876137ed565b611e7c61328d565b611e97815f5f5f60405180602001604052805f8152506132d3565b50565b611ea261328d565b6017546001600160a01b0316611ecb5760405163eac0d38960e01b81526004016110cb906151c1565b611e975f5f5f5f60405180602001604052805f8152506001876137ed565b611ef16132e9565b6119136145c6565b5f5f5f5f5f60045f9054906101000a90046001600160a01b03166001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611f4e573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7291906151fb565b9450945050935093505f8313611fb65760405162461bcd60e51b815260206004820152600960248201526862616420707269636560b81b60448201526064016110cb565b610e10611fc3834261513d565b1115611fff5760405162461bcd60e51b815260206004820152600b60248201526a7374616c6520707269636560a81b60448201526064016110cb565b8369ffffffffffffffffffff168169ffffffffffffffffffff161015801561202657505f82115b6120655760405162461bcd60e51b815260206004820152601060248201526f726f756e6420696e636f6d706c65746560801b60448201526064016110cb565b50909392505050565b6120766132e9565b601955565b5f5f612085611ef9565b9050670de0b6b3a764000060045f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120e0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121049190615249565b61210f906012615264565b61211a90600a615360565b612124838661518b565b61212e919061518b565b61213891906151a2565b9392505050565b6121476132e9565b61217081604051806040016040528060078152602001667374616b696e6760c81b81525061336e565b601780546001600160a01b0319166001600160a01b0392909216919091179055565b61219a6132e9565b5f868152601860205260409020805487146121cb5760405163213975eb60e01b8152600481018890526024016110cb565b60648611156122055760405163589956a560e11b8152602060048201526005602482015264626f6e757360d81b60448201526064016110cb565b61221087858561353f565b806006015482101561224c5760068101546040516317c5e69960e01b8152600481018990526024810184905260448101919091526064016110cb565b612257878585614603565b6001810186905560028101859055600381018490556004810183905560058101805490839055604080518281526020810185905289917fff4c985d0c54731f2fd581dfae5af208edee7e2ced78baa1e9ac1fd03ebe1bc0910160405180910390a26040805188815260208101889052908101869052606081018590526080810184905288907f85691ece3b5cb16ac00911efb4d9dfadc0fe04f47d8acaa92f8acdea6ae27b809060a00160405180910390a25050505050505050565b61231b613315565b61232361328d565b601154335f908152600f6020526040812054909161234091615150565b90508042101561236657604051630eb71c9760e41b8152600481018290526024016110cb565b335f908152600d602052604081205490600146148061238757504662aa36a7145b1561239557506012546123cd565b46603814806123a45750466061145b156123b257506013546123cd565b604051631874ab9360e31b81524660048201526024016110cb565b808210156123f857604051631014af1b60e21b815260048101829052602481018390526044016110cb565b81600e54101561241b5760405163a3e0846f60e01b815260040160405180910390fd5b335f908152600d60205260408120819055600e805484929061243e90849061513d565b9091555050335f818152600f6020908152604080832042908190558280528184208251606081018452888152808501928352438185019081528254600181810185559388528688209251600390910290920191825592519181019190915590516002909101559282526010905290812080548492906124be908490615150565b90915550506040515f90339084908381818185875af1925050503d805f8114612502576040519150601f19603f3d011682016040523d82523d5f602084013e612507565b606091505b505090508061252957604051632ee66eed60e01b815260040160405180910390fd5b335f81815260106020526040908190205490517fbda0558246f195546ecc523f23162b871fd8da11710453e986bb762d620175869161257c91879142919283526020830191909152604082015260600190565b60405180910390a25050505061191360018055565b5f5f5f61259d846125c0565b915091508082116125ae575f6125b8565b6125b8818361513d565b949350505050565b5f5f825f036125d357505f928392509050565b50505f81815260186020908152604091829020825160e08101845281548152600180830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a0840181905260069091015460c08401819052909290915b84811015612702575f81815260186020908152604091829020825160e08101845281548082526001830154938201939093526002820154938101939093526003810154606084015260048101546080840152600581015460a08401526006015460c083015282146126ae57506126fa565b806080015142116126bf5750612702565b5f8160c001518260a00151116126d5575f6126e9565b8160c001518260a001516126e9919061513d565b90506126f58187615150565b955050505b60010161263d565b5050915091565b5f5f5f612714611c75565b90925090505f82600281111561272c5761272c614fe2565b0361273a57505f9392505050565b5f80600184600281111561275057612750614fe2565b036127b95750505f81815260186020908152604091829020825160e08101845281548152600182015492810183905260028201549381018490526003820154606082015260048201546080820152600582015460a082015260069091015460c0909101526127c2565b5050601c54601d545b5f6127ce87848461477a565b90505f600754600654116127e2575f6127f2565b6007546006546127f2919061513d565b905080821115612800578091505b6002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa15801561284b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061286f9190615112565b90508083111561287d578092505b600187600281111561289157612891614fe2565b036128cf575f5f6128a1886125c0565b915091505f8183116128b3575f6128bd565b6128bd828461513d565b9050808611156128cb578095505b5050505b5090979650505050505050565b6128e461328d565b6119135f5f5f5f60405180602001604052805f8152506132d3565b6129076132e9565b611e975f82614840565b6129196132e9565b611e97600182614840565b600a8181548110611b94575f80fd5b61293b6132e9565b612943613315565b600e544790811161296757604051630686827b60e51b815260040160405180910390fd5b5f600e5482612976919061513d565b6040519091505f90339083908381818185875af1925050503d805f81146129b8576040519150601f19603f3d011682016040523d82523d5f602084013e6129bd565b606091505b50509050806129df57604051632ee66eed60e01b815260040160405180910390fd5b60405182815233907feaff4b37086828766ad3268786972c0cd24259d4c87a80f9d3963a3c3d999b0d9060200160405180910390a250505061191360018055565b6001600160a01b0381165f908152601660205260408120549080612a43836117bd565b9150612a4e8361492c565b929491935050565b5f5f5f612a61611c75565b90925090505f826002811115612a7957612a79614fe2565b03612a8757505f9392505050565b5f806001846002811115612a9d57612a9d614fe2565b03612b065750505f81815260186020908152604091829020825160e08101845281548152600182015492810183905260028201549381018490526003820154606082015260048201546080820152600582015460a082015260069091015460c090910152612b0f565b5050601c54601d545b612b1a8683836133ee565b9695505050505050565b612b2c6132e9565b601f5460ff168015612b405750601e544210155b15612b5e576040516301e3224f60e71b815260040160405180910390fd5b612b8b846040518060400160405280600b81526020016a7075626c6963507269636560a81b815250613576565b6064831115612bcb5760405163589956a560e11b815260206004820152600b60248201526a7075626c6963426f6e757360a81b60448201526064016110cb565b604080516080808201835286825260208083018790528284018690528415156060938401819052601c899055601d889055601e879055601f805460ff1916821790558451898152918201889052938101869052918201929092527f05a3ff2b79c8d3a61428aeacdd316adc30b6a97a6b36b34894efa4ffcac9f753910160405180910390a150505050565b612c5e6132e9565b612c86816040518060400160405280600681526020016539b4b3b732b960d11b81525061336e565b601480546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381165f908152600c60209081526040808320546016909252822054808211612cd857806125b8565b5092915050565b612ce76132e9565b5f82815260186020526040902080548314612d185760405163213975eb60e01b8152600481018490526024016110cb565b80600301544210612d3f576040516397db424160e01b8152600481018490526024016110cb565b4282111580612d52575080600401548210155b15612d73576040516397db424160e01b8152600481018490526024016110cb565b6001831115612e2c575f601881612d8b60018761513d565b81526020019081526020015f206040518060e00160405290815f820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050600184612df7919061513d565b8151148015612e095750806080015183105b15612e2a57604051637437e81760e01b8152600481018590526024016110cb565b505b60038101829055600481015460405184917f74064869fb3619f32eb8e86259fe1d5051e6d16ce61718dad7d2420bcfe0fcc89161143e91868252602082015260400190565b612e796132e9565b612ea7816040518060400160405280600c81526020016b199959549958da5c1a595b9d60a21b81525061336e565b601580546001600160a01b0319166001600160a01b0392909216919091179055565b5f5f5f612ed4611c75565b90925090505f826002811115612eec57612eec614fe2565b03612ef9575f9250505090565b5f6001836002811115612f0e57612f0e614fe2565b03612ff3575f5f612f1e846125c0565b915091505f818311612f30575f612f3a565b612f3a828461513d565b6002546040516370a0823160e01b81523060048201529192505f916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015612f89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fad9190615112565b90505f60075460065411612fc1575f612fd1565b600754600654612fd1919061513d565b905080831115612fdf578092505b81831115612feb578192505b509093505050505b601f545f9060ff1680156130095750601e544210155b15613109576002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015613059573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061307d9190615112565b90505f60075460065411613091575f6130a1565b6007546006546130a1919061513d565b90505f8482116130b1575f6130bb565b6130bb858361513d565b90505f8584116130cb575f6130d5565b6130d5868561513d565b90505f8183106130e557816130e7565b825b9050801561310357601c54601d546131009183916133ee565b95505b50505050505b5f600185600281111561311e5761311e614fe2565b14801561312a57505f83115b1561319c575f84815260186020908152604091829020825160e08101845281548152600182015492810183905260028201549381018490526003820154606082015260048201546080820152600582015460a082015260069091015460c082015291613198918691906133ee565b9150505b6131a68282615150565b9550505050505090565b6001600160a01b0381165f908152600c6020908152604080832054600d90925282205490918080806131e1866117bd565b6011546001600160a01b0389165f908152600f602052604090205491955061320891615150565b6001600160a01b0388165f9081526010602052604090205490935061322e908690615150565b6001600160a01b039097165f9081526020805260409020549597949693959294915050565b61325b6132e9565b6001600160a01b03811661328457604051631e4fbdf760e01b81525f60048201526024016110cb565b611e978161379e565b60025460ff16156119135760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016110cb565b6132e285858585855f5f6137ed565b5050505050565b5f546001600160a01b031633146119135760405163118cdaa760e01b81523360048201526024016110cb565b6002600154036133675760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016110cb565b6002600155565b6001600160a01b03821661113f578060405163eac0d38960e01b81526004016110cb919061536e565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526133e990849061498d565b505050565b5f5f60035f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613440573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134649190615249565b60ff1690505f613475846064615150565b61348087606461518b565b61348a91906151a2565b90505f61349883600a6153a3565b6134a2878461518b565b6134ac91906151a2565b90505f6134c0670de0b6b3a764000061207b565b9050805f036134ff5760405163589956a560e11b815260206004820152600a602482015269707269636544656e6f6d60b01b60448201526064016110cb565b8060018161351585670de0b6b3a764000061518b565b61351f9190615150565b613529919061513d565b61353391906151a2565b98975050505050505050565b81158061354a575080155b806135555750808210155b156133e9576040516397db424160e01b8152600481018490526024016110cb565b815f0361113f578060405163589956a560e11b81526004016110cb919061536e565b6135a06149f9565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b604080517ffa8b458545377bec9568500b00b33c407fe4f3b1f74043a0f121d056b1562b836020808301919091526001600160a01b0396909616818301526060810194909452608084019290925260a0808401919091528151808403909101815260c0830182528051908401207f19457468657265756d205369676e6564204d6573736167653a0a33320000000060e084015260fc808401919091528151808403909101815261011c9092019052805191012090565b5f5f5f5f6136ae8686614a42565b9250925092506136be8282614a8b565b50909150505b92915050565b610fb986868686866001876137ed565b5f601a545f036136e957505f90565b60015b601a548111613797575f81815260186020908152604091829020825160e0810184528154815260018201549281019290925260028101549282019290925260038201546060820181905260048301546080830152600583015460a083015260069092015460c0820152904210801590613769575080608001514211155b15613784578060a001518160c0015110156137845750919050565b508061378f816153ae565b9150506136ec565b505f905090565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6137f5613315565b60085460ff166138185760405163b7b2409760e01b815260040160405180910390fd5b345f036138545760405163589956a560e11b81526020600482015260096024820152686d73672e76616c756560b81b60448201526064016110cb565b6138956040518060e001604052805f81526020015f81526020015f81526020015f81526020015f60ff1681526020015f60ff1681526020015f151581525090565b6001600160a01b038816158015906138b657506001600160a01b0388163314155b15613b4c576001600160a01b0388165f908152600c60205260409020546138de816001615150565b606083015284511561399f5760145460408051808201909152600681526539b4b3b732b960d11b602082015261391d916001600160a01b03169061336e565b8642111561395b5760405162461bcd60e51b815260206004820152600b60248201526a185d1d08195e1c1a5c995960aa1b60448201526064016110cb565b5f61396c866119d28c8c8c8c6135ea565b6014549091506001600160a01b038083169116148015613990575082606001518910155b1561399d57600160c08401525b505b6001600160a01b0389165f9081526016602052604090205460c08301516139db57826060015181116139d55782606001516139dd565b806139dd565b885b60408401526139eb8161492c565b60ff1660808401526040830151613a019061492c565b60ff1660a084015260c08301518015613a275750826080015160ff168360a0015160ff16115b15613b135760155460408051808201909152600c81526b199959549958da5c1a595b9d60a21b6020820152613a65916001600160a01b03169061336e565b613a8e876040518060400160405280600781526020016673796e6346656560c81b815250613576565b86341015613ab85760405163ed82eac160e01b8152600481018890523460248201526044016110cb565b6015545f9061271090613ad690600160a01b900461ffff163461518b565b613ae091906151a2565b905080881115613b0d5760405163ea4749c160e01b815260048101899052602481018290526044016110cb565b50613b32565b8615613b32576040516381a3e9d160e01b815260040160405180910390fd5b613b3f83604001516117bd565b602084015250613b6b9050565b8415613b6b576040516381a3e9d160e01b815260040160405180910390fd5b5f613b76863461513d565b9050805f03613bb85760405163589956a560e11b815260206004820152600d60248201526c707572636861736556616c756560981b60448201526064016110cb565b600954613bc48261207b565b1015613be357604051633093be2760e11b815260040160405180910390fd5b5f8080613bf0818561513d565b90505b8015613f05575f5f613c03611c75565b90925090506001826002811115613c1c57613c1c614fe2565b14613c28575050613f05565b613c3181614b43565b5f818152601860209081526040808320815160e081018352815481526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a0830181905260069091015460c0830181905291929110613ca0575f613cb4565b8160c001518260a00151613cb4919061513d565b9050805f03613cc65750505050613bf3565b5f613cda868460400151856020015161477a565b9050805f03613ced575050505050613f05565b6002546040516370a0823160e01b81523060048201525f9161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015613d38573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d5c9190615112565b90505f60075460065411613d70575f613d80565b600754600654613d80919061513d565b90505f8a8211613d90575f613d9a565b613d9a8b8361513d565b90505f8b8411613daa575f613db4565b613db48c8561513d565b90508582811115613dc25750815b81811115613dcd5750805b805f03613de35750505050505050505050613f05565b808611613e72575f613dfe878a604001518b602001516133ee565b90508b811115613e0b57508a5b805f03613e22575050505050505050505050613f05565b5f8a81526018602052604081206006018054899290613e42908490615150565b90915550613e529050878f615150565b9d50613e5e818e615150565b9c50613e6a818d61513d565b9b5050613ef6565b5f613e86828a604001518b602001516133ee565b90508b811115613e9357508a5b805f03613eaa575050505050505050505050613f05565b5f8a81526018602052604081206006018054849290613eca908490615150565b90915550613eda9050828f615150565b9d50613ee6818e615150565b9c50613ef2818d61513d565b9b50505b50505050505050505050613bf3565b505f613f11828561513d565b9050801561408c575f613f22611c75565b5090506002816002811115613f3957613f39614fe2565b14613f57576040516331f423c160e21b815260040160405180910390fd5b5f613f6c83601c5f0154601c6001015461477a565b6002546040516370a0823160e01b81523060048201529192505f916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015613fbb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613fdf9190615112565b90505f60075460065411613ff3575f614003565b600754600654614003919061513d565b90505f878211614013575f61401d565b61401d888361513d565b90505f88841161402d575f614037565b614037898561513d565b90505f8183106140475781614049565b825b90508086111561406c57604051631092d60960e31b815260040160405180910390fd5b614076868b615150565b9950614082888a615150565b9850505050505050505b508281146140ad576040516349db855d60e11b815260040160405180910390fd5b815f036140eb5760405163589956a560e11b815260206004820152600b60248201526a1d1bdad95b9cd51bdd185b60aa1b60448201526064016110cb565b8160075f8282546140fc9190615150565b909155505f90506001600160a01b038c161580159061412457506001600160a01b038c163314155b801561413357505f8560200151115b1561420a57606485602001518561414a919061518b565b61415491906151a2565b6001600160a01b038d165f908152600d6020526040812080549293508392909190614180908490615150565b9250508190555080600e5f8282546141989190615150565b909155505060608501516001600160a01b038d165f908152600c602052604090205560c085015180156141e657506001600160a01b038c165f90815260166020526040908190205490860151115b1561420a576040808601516001600160a01b038e165f908152601660205291909120555b8460c0015180156142285750846080015160ff168560a0015160ff16115b15614329576015546040515f916001600160a01b0316908b908381818185875af1925050503d805f8114614277576040519150601f19603f3d011682016040523d82523d5f602084013e61427c565b606091505b50509050806142c45760405162461bcd60e51b81526020600482015260146024820152731cde5b98c8199959481e19995c8819985a5b195960621b60448201526064016110cb565b60808087015160a08801516040808a0151815160ff948516815293909216602084015282018d905260608201526001600160a01b038f16917f97c2e0ed1152da7606a66de340db9914d8a9adf6b7c6bb511355f6c9fae9bbe4910160405180910390a2505b8661434f5760025461434a9061010090046001600160a01b03163385613397565b61445a565b6017546001600160a01b03166143785760405163eac0d38960e01b81526004016110cb906151c1565b60175460025461439a916001600160a01b036101009092048216911685613397565b60175460405163200d69b160e21b81523360048201526024810185905260ff881660448201525f916001600160a01b031690638035a6c4906064016020604051808303815f875af11580156143f1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144159190615112565b6040805160ff8a16815260208101879052919250829133917f49b72192b6d6993c4b6f8e281f1e6ead3948764836d596c9864c72aa7da9559e910160405180910390a3505b5f614465828661513d565b6005546040805180820190915260078152661c185e5b595b9d60ca1b602082015291925061449e916001600160a01b039091169061336e565b6005546040515f916001600160a01b03169083908381818185875af1925050503d805f81146144e8576040519150601f19603f3d011682016040523d82523d5f602084013e6144ed565b606091505b505090508061450f57604051632ee66eed60e01b815260040160405180910390fd5b5f6145198761207b565b90506001600160a01b038f161580159061453657505f8860200151115b156145b557336001600160a01b03168f6001600160a01b03167f21a585c6e206cdf092092c3c9823edfa9f2da82c6fb0356215ef2981edea0707838a888d602001518e604001516040516145ac959493929190948552602085019390935260408401919091526060830152608082015260a00190565b60405180910390a35b5050505050505050611c6c60018055565b6145ce61328d565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135cd3390565b60018311156146bc575f60188161461b60018761513d565b81526020019081526020015f206040518060e00160405290815f820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050600184614687919061513d565b81511480156146995750806080015183105b156146ba57604051637437e81760e01b8152600481018590526024016110cb565b505b601a548310156133e9575f6018816146d5866001615150565b81526020019081526020015f206040518060e00160405290815f8201548152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201548152505090508360016147419190615150565b81511480156147535750806060015182115b1561477457604051637437e81760e01b8152600481018590526024016110cb565b50505050565b5f5f6147858561207b565b90505f60035f9054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156147d8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906147fc9190615249565b60ff16905061480c85606461518b565b614817856064615150565b61482283600a6153a3565b61482c908561518b565b614836919061518b565b612b1a91906151a2565b6148a18183614875576040518060400160405280600e81526020016d36b4b72932b332b93930b621373160911b815250613576565b6040518060400160405280600e81526020016d0dad2dca4cacccae4e4c2d88ae8d60931b815250613576565b81156148ee57601280549082905560408051828152602081018490527fc56a0ee2629ef404bb6fe2387c705f2ffb6534aed14846dfffd5cc6dcf79cbe991015b60405180910390a1505050565b601380549082905560408051828152602081018490527faef4b147818441ea163ba8de03e7d561e33d9a8dbc7b74b59e9bf4024428de8191016148e1565b5f805b600a5460ff8216101561498457600a8160ff168154811061495257614952615177565b905f5260205f200154831061497257600a546121389060ff83169061513d565b8061497c816153c6565b91505061492f565b50600192915050565b5f5f60205f8451602086015f885af1806149ac576040513d5f823e3d81fd5b50505f513d915081156149c35780600114156149d0565b6001600160a01b0384163b155b1561477457604051635274afe760e01b81526001600160a01b03851660048201526024016110cb565b60025460ff166119135760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016110cb565b5f5f5f8351604103614a79576020840151604085015160608601515f1a614a6b88828585614c60565b955095509550505050614a84565b505081515f91506002905b9250925092565b5f826003811115614a9e57614a9e614fe2565b03614aa7575050565b6001826003811115614abb57614abb614fe2565b03614ad95760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115614aed57614aed614fe2565b03614b0e5760405163fce698f760e01b8152600481018290526024016110cb565b6003826003811115614b2257614b22614fe2565b0361113f576040516335e2f38360e21b8152600481018290526024016110cb565b60018111614b4e5750565b5f601b546001614b5e9190615150565b9050818110614b6b575050565b81811015614c4e575f81815260186020526040902080548214614b8e5750614c46565b80600401544211614b9f5750614c4e565b5f8160060154826005015411614bb5575f614bc9565b81600601548260050154614bc9919061513d565b9050805f03614bd9575050614c46565b60068201546005808401919091555f8581526018602052604081209091018054839290614c07908490615150565b9091555050604051818152849084907faa1e781edf243a8b1b82cde778cbbcc2375e35cf108adaed7814c05230be20a89060200160405180910390a350505b600101614b6b565b614c5960018261513d565b601b555050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115614c9957505f91506003905082614d1e565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015614cea573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116614d1557505f925060019150829050614d1e565b92505f91508190505b9450945094915050565b80356001600160a01b0381168114614d3e575f5ffd5b919050565b5f5f83601f840112614d53575f5ffd5b50813567ffffffffffffffff811115614d6a575f5ffd5b602083019150836020828501011115614d81575f5ffd5b9250929050565b5f5f5f5f5f5f60a08789031215614d9d575f5ffd5b614da687614d28565b9550602087013594506040870135935060608701359250608087013567ffffffffffffffff811115614dd6575f5ffd5b614de289828a01614d43565b979a9699509497509295939492505050565b5f5f60408385031215614e05575f5ffd5b614e0e83614d28565b946020939093013593505050565b5f60208284031215614e2c575f5ffd5b61213882614d28565b5f5f5f60608486031215614e47575f5ffd5b614e5084614d28565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b81811015614ebb57614ea58385518051825260208082015190830152604090810151910152565b6020939093019260609290920191600101614e7e565b509095945050505050565b5f5f60408385031215614ed7575f5ffd5b50508035926020909101359150565b815181526020808301519082015260408083015190820152606081016136c4565b5f5f5f5f5f60a08688031215614f1b575f5ffd5b505083359560208501359550604085013594606081013594506080013592509050565b5f60208284031215614f4e575f5ffd5b5035919050565b60ff81168114611e97575f5ffd5b5f5f5f5f5f5f5f60c0888a031215614f79575f5ffd5b614f8288614d28565b9650602088013595506040880135945060608801359350608088013567ffffffffffffffff811115614fb2575f5ffd5b614fbe8a828b01614d43565b90945092505060a0880135614fd281614f55565b8091505092959891949750929550565b634e487b7160e01b5f52602160045260245ffd5b604081016003841061501657634e487b7160e01b5f52602160045260245ffd5b9281526020015290565b5f60208284031215615030575f5ffd5b813561ffff81168114612138575f5ffd5b5f5f60408385031215615052575f5ffd5b61505b83614d28565b9150602083013561506b81614f55565b809150509250929050565b5f60208284031215615086575f5ffd5b813561213881614f55565b5f5f5f5f5f5f60c087890312156150a6575f5ffd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b5f5f5f5f608085870312156150e3575f5ffd5b84359350602085013592506040850135915060608501358015158114615107575f5ffd5b939692955090935050565b5f60208284031215615122575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156136c4576136c4615129565b808201808211156136c4576136c4615129565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b80820281158282048414176136c4576136c4615129565b5f826151bc57634e487b7160e01b5f52601260045260245ffd5b500490565b6020808252600790820152667374616b696e6760c81b604082015260600190565b805169ffffffffffffffffffff81168114614d3e575f5ffd5b5f5f5f5f5f60a0868803121561520f575f5ffd5b615218866151e2565b6020870151604088015160608901519297509095509350915061523d608087016151e2565b90509295509295909350565b5f60208284031215615259575f5ffd5b815161213881614f55565b60ff82811682821603908111156136c4576136c4615129565b6001815b60018411156152b85780850481111561529c5761529c615129565b60018416156152aa57908102905b60019390931c928002615281565b935093915050565b5f826152ce575060016136c4565b816152da57505f6136c4565b81600181146152f057600281146152fa57615316565b60019150506136c4565b60ff84111561530b5761530b615129565b50506001821b6136c4565b5060208310610133831016604e8410600b8410161715615339575081810a6136c4565b6153455f19848461527d565b805f190482111561535857615358615129565b029392505050565b5f61213860ff8416836152c0565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f61213883836152c0565b5f600182016153bf576153bf615129565b5060010190565b5f60ff821660ff81036153db576153db615129565b6001019291505056fea2646970667358221220081a0aa408b4c5375b449601a32c3ff7948ec578104e09554cf5bcfcdc7aa17c64736f6c634300081e0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000648b478c5142072610ffc1ccdc081fd632a14247000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841900000000000000000000000000000000000000000000000000027ca57357c0000000000000000000000000000000000000000000000000000007d0e36a818000

-----Decoded View---------------
Arg [0] : _payment (address): 0x648b478C5142072610ffC1cCdc081fd632A14247
Arg [1] : _token (address): 0xBb0E53741f2D1ebFb87F6a89632242F58A08f13B
Arg [2] : _priceFeed (address): 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
Arg [3] : _minReferralPayoutEth (uint256): 700000000000000
Arg [4] : _minReferralPayoutBnb (uint256): 2200000000000000

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000648b478c5142072610ffc1ccdc081fd632a14247
Arg [1] : 000000000000000000000000bb0e53741f2d1ebfb87f6a89632242f58a08f13b
Arg [2] : 0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419
Arg [3] : 00000000000000000000000000000000000000000000000000027ca57357c000
Arg [4] : 0000000000000000000000000000000000000000000000000007d0e36a818000


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.