ETH Price: $2,034.64 (+1.98%)
 

Overview

Max Total Supply

530,827.075111448938979719 lazyUSD

Holders

8

Transfers

-
5

Market

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
LazyUSDVault

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
File 1 of 18 : LazyUSDVault.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IVault} from "./interfaces/IVault.sol";
import {IRoleManager} from "./interfaces/IRoleManager.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

/**
 * @title LazyUSDVault
 * @notice A USDC-denominated savings vault with share-based NAV model
 * @dev Uses internal yield tracking and IRoleManager for access control
 *
 * Architecture:
 * - Vault tracks deposits/withdrawals automatically (totalDeposited, totalWithdrawn)
 * - Yield from external on-chain strategies is reported via reportYieldAndCollectFees()
 * - totalAssets = totalDeposited - totalWithdrawn + accumulatedYield
 * - IRoleManager: Controls pause state and operator access
 *
 * Key features:
 * - Share-based accounting (1 USDC = 1 share initially)
 * - Async withdrawal queue with FIFO processing
 * - Share escrow on withdrawal request (prevents double-spend)
 * - Protocol fees on positive yield (via share minting to treasury)
 * - Operator-only withdrawal fulfillment
 * - Reentrancy protection on state-changing functions
 *
 * =============================================================================
 * FORMAL INVARIANT SPECIFICATION
 * =============================================================================
 *
 * INVARIANT I.1 — Conservation of Value via Shares (Primary)
 * ----------------------------------------------------------------------------
 * The protocol SHALL NOT transfer any amount of USDC out of the Vault unless
 * a corresponding amount of shares is irrevocably burned at the current NAV.
 *
 * Formal: S_burned = floor(A_out / NAV)
 *         totalAssets_after = totalAssets_before - A_out
 *         totalShares_after = totalShares_before - S_burned
 *
 * No execution path MAY reduce totalAssets without reducing totalShares.
 *
 * INVARIANT I.2 — Share Escrow Safety
 * ----------------------------------------------------------------------------
 * Shares submitted for withdrawal SHALL be transferred to the Vault and
 * SHALL NOT be transferable, reusable, or withdrawable until either:
 *   a) The withdrawal is fulfilled and shares are burned, OR
 *   b) The withdrawal is cancelled and shares are returned to requester
 *
 * This prevents duplicate claims and double-withdraw attacks.
 *
 * INVARIANT I.3 — Universal NAV Application
 * ----------------------------------------------------------------------------
 * Any update to totalAssets SHALL apply uniformly to ALL outstanding shares:
 *   - Shares held by users
 *   - Shares held in withdrawal escrow (by vault)
 *   - Shares held by Treasury
 *
 * No class of shares SHALL be excluded from gains or losses.
 *
 * INVARIANT I.4 — Fee Isolation
 * ----------------------------------------------------------------------------
 * Protocol fees SHALL:
 *   - Be assessed only on share price increases (yield, not deposits)
 *   - Be capped by MAX_FEE_RATE
 *   - Be paid exclusively via minting new shares to Treasury
 *
 * Fees SHALL NEVER cause a transfer of USDC from the Vault.
 *
 * INVARIANT I.5 — Withdrawal Queue Liveness
 * ----------------------------------------------------------------------------
 * The withdrawal fulfillment mechanism SHALL:
 *   - Process requests in FIFO order
 *   - Never revert due to insufficient USDC balance
 *   - Terminate gracefully if available liquidity is insufficient
 *
 * =============================================================================
 * EXPLICIT DESIGN STATEMENTS
 * =============================================================================
 *
 * STATEMENT D.1 — Emergency Scope Declaration
 * ----------------------------------------------------------------------------
 * Emergency overrides (forceProcessWithdrawal, cancelWithdrawal) exist to
 * restore liveness or user safety for individual withdrawals, not to rebalance
 * protocol state globally. These functions preserve invariants I.1 and I.2.
 *
 * STATEMENT D.2 — Oracle Trust Assumption
 * ----------------------------------------------------------------------------
 * Yield reports are trusted inputs controlled by governance. The protocol does
 * not attempt to algorithmically defend against oracle manipulation. Deposits
 * and withdrawals are tracked automatically; only yield requires reporting.
 *
 * STATEMENT D.3 — Fee Accounting Rule
 * ----------------------------------------------------------------------------
 * Protocol fees are calculated as a percentage of positive yield at report time.
 * When reportYieldAndCollectFees() is called with positive yield:
 *   fee = yield * feeRate / PRECISION
 * Fee shares are minted directly to treasury. No USDC is transferred for fees.
 *
 * STATEMENT D.4 — Queue Append-Only Design
 * ----------------------------------------------------------------------------
 * The withdrawal queue is append-only. Processed entries are marked with
 * shares=0 and skipped via withdrawalQueueHead cursor. Entries are never
 * deleted. This is intentional to preserve FIFO ordering, maintain requestId
 * stability, and avoid costly array shifts.
 *
 * STATEMENT D.5 — Governance Delegation Pattern
 * ----------------------------------------------------------------------------
 * This Vault deliberately does NOT use OpenZeppelin's Ownable or Pausable.
 * Authority and emergency control are delegated to an external RoleManager
 * contract to:
 *
 *   1. Allow multi-role governance (Owner, Operator, Guardian)
 *   2. Enable future governance upgrades without redeploying the Vault
 *   3. Avoid hard-coding authority assumptions into the asset custody layer
 *
 * OpenZeppelin components are used ONLY where they provide pure mechanical
 * safety guarantees and do not encode governance semantics:
 *   - ReentrancyGuard: Prevents cross-function reentrancy (mechanical safety)
 *   - ERC20: Standard token mechanics (vault IS the share token)
 *
 * This separation ensures the Vault focuses solely on asset custody and
 * accounting, while governance logic remains modular and upgradeable.
 *
 * =============================================================================
 * SINGLE-LINE SUMMARY
 * =============================================================================
 * The only way value exits the system is by destroying shares at current NAV;
 * all shares, regardless of state, rise and fall together.
 * =============================================================================
 */
contract LazyUSDVault is IVault, ERC20, ReentrancyGuard {
    using SafeERC20 for IERC20;

    // ============ Constants ============

    uint256 public constant PRECISION = 1e18;
    uint256 public constant MAX_FEE_RATE = 0.5e18; // 50% max fee
    uint256 public constant MIN_COOLDOWN = 1 days;
    uint256 public constant MAX_COOLDOWN = 30 days;
    uint256 public constant CANCELLATION_WINDOW = 1 hours; // H-3: User can cancel within this window
    uint256 public constant MAX_PENDING_PER_USER = 10; // M-1: Limit pending requests per user

    // Timelock durations for critical configuration changes
    uint256 public constant TIMELOCK_FEE_RATE = 1 days;
    uint256 public constant TIMELOCK_TREASURY = 2 days;
    uint256 public constant TIMELOCK_MULTISIG = 3 days;
    uint256 public constant TIMELOCK_COOLDOWN = 1 days;

    // Initial share price: 1 USDC (6 decimals) = 1 share (18 decimals)
    // Price is scaled to 18 decimals: 1e6 means 1 USDC per share
    uint256 public constant INITIAL_SHARE_PRICE = 1e6;

    // Yield reporting constraints
    uint256 public constant MIN_YIELD_REPORT_INTERVAL = 1 days;

    // ============ Immutables ============

    IERC20 public immutable usdc;
    IRoleManager public immutable roleManager;

    // ============ State ============

    // Addresses
    address public multisig;
    address public treasury;

    // Configuration
    uint256 public feeRate; // Fee rate on profits (18 decimals, e.g., 0.2e18 = 20%)
    uint256 public globalCap; // Max total AUM (0 = unlimited)
    uint256 public withdrawalBuffer; // USDC to retain for withdrawals
    uint256 public cooldownPeriod; // Minimum time before withdrawal fulfillment

    // NAV tracking (deposits and withdrawals tracked automatically)
    uint256 public totalDeposited; // Cumulative USDC deposited
    uint256 public totalWithdrawn; // Cumulative USDC withdrawn

    // Yield tracking (previously in StrategyOracle)
    /// @notice Cumulative yield from external strategies (can be negative for losses)
    /// @dev Used in NAV calculation: totalAssets = deposits - withdrawals + accumulatedYield
    int256 public accumulatedYield;
    /// @notice Timestamp of the last yield report
    /// @dev Used to enforce MIN_YIELD_REPORT_INTERVAL between reports
    uint256 public lastYieldReportTime;
    /// @notice Maximum allowed yield change as percentage of NAV (18 decimals)
    /// @dev Safety bound: prevents accidental misreporting (e.g., wrong decimals).
    ///      Default 0.5% (0.005e18). Set to 0 to disable bounds checking.
    uint256 public maxYieldChangePercent = 0.005e18;

    // Withdrawal queue (append-only design - see STATEMENT D.4)
    /// @notice Array of all withdrawal requests (processed entries have shares=0)
    WithdrawalRequest[] public withdrawalQueue;
    /// @notice Cursor pointing to next unprocessed request (FIFO ordering)
    uint256 public withdrawalQueueHead;
    /// @notice Total shares currently held in escrow for pending withdrawals
    /// @dev Must always equal balanceOf(address(this)) minus any orphaned shares
    uint256 public pendingWithdrawalShares;
    /// @notice Count of pending withdrawal requests per user (prevents queue spam)
    /// @dev Enforces MAX_PENDING_PER_USER limit per address
    mapping(address => uint256) public userPendingRequests;

    // Timelock pending changes
    // Each config change requires: queue -> wait timelock -> execute
    // Value of 0 means no pending change; timestamp of 0 means not queued
    /// @notice Pending fee rate value awaiting timelock expiry
    uint256 public pendingFeeRate;
    /// @notice Timestamp when pendingFeeRate can be executed (0 = not queued)
    uint256 public pendingFeeRateTimestamp;
    /// @notice Pending treasury address awaiting timelock expiry
    address public pendingTreasury;
    /// @notice Timestamp when pendingTreasury can be executed (0 = not queued)
    uint256 public pendingTreasuryTimestamp;
    /// @notice Pending multisig address awaiting timelock expiry
    address public pendingMultisig;
    /// @notice Timestamp when pendingMultisig can be executed (0 = not queued)
    uint256 public pendingMultisigTimestamp;
    /// @notice Pending cooldown period awaiting timelock expiry
    uint256 public pendingCooldownPeriod;
    /// @notice Timestamp when pendingCooldownPeriod can be executed (0 = not queued)
    uint256 public pendingCooldownTimestamp;

    // ============ Errors ============

    error OnlyOwner();
    error OnlyOperator();
    error ZeroAddress();
    error ZeroAmount();
    error ZeroShares();
    error Paused();
    error DepositsPaused();
    error WithdrawalsPaused();
    error ExceedsGlobalCap();
    error InsufficientShares();
    error InsufficientLiquidity();
    error InvalidFeeRate();
    error InvalidCooldown();
    error InvalidRequestId();
    error RequestAlreadyProcessed();
    error Unauthorized();
    error TooManyPendingRequests();
    error NotAContract();
    // Invariant violation errors (should never occur if code is correct)
    error EscrowBalanceMismatch();
    error SharesNotBurned();
    error QueueHeadRegression(); // I.5: FIFO ordering violated
    // Timelock errors
    error TimelockNotExpired();
    error NoPendingChange();
    // Yield reporting errors
    error YieldChangeTooLarge();
    error ReportTooSoon();
    // Transfer protection errors
    error CannotTransferToVault(); // V-2: Prevent accidental share loss

    // ============ Modifiers ============

    modifier onlyOwner() {
        if (msg.sender != roleManager.owner()) revert OnlyOwner();
        _;
    }

    modifier onlyOperator() {
        if (!roleManager.isOperator(msg.sender)) revert OnlyOperator();
        _;
    }

    /// @notice Modifier for functions callable by either owner or operator
    /// @dev Used for daily operations that need flexibility (yield reporting, buffer adjustments)
    modifier onlyOperatorOrOwner() {
        if (msg.sender != roleManager.owner() && !roleManager.isOperator(msg.sender)) {
            revert Unauthorized();
        }
        _;
    }

    modifier whenNotPaused() {
        if (roleManager.paused()) revert Paused();
        _;
    }

    modifier whenDepositsNotPaused() {
        if (roleManager.depositsPaused()) revert DepositsPaused();
        _;
    }

    modifier whenWithdrawalsNotPaused() {
        if (roleManager.withdrawalsPaused()) revert WithdrawalsPaused();
        _;
    }

    // ============ Constructor ============

    /**
     * @notice Initialize the vault
     * @param _usdc USDC token address
     * @param _roleManager RoleManager contract address
     * @param _multisig Multisig address for strategy funds
     * @param _treasury Treasury address for fees
     * @param _feeRate Initial fee rate (18 decimals)
     * @param _cooldownPeriod Initial cooldown period
     * @param _shareName Name for the vault share token (e.g., "LazyUSD")
     * @param _shareSymbol Symbol for the vault share token (e.g., "lazyUSD")
     */
    constructor(
        address _usdc,
        address _roleManager,
        address _multisig,
        address _treasury,
        uint256 _feeRate,
        uint256 _cooldownPeriod,
        string memory _shareName,
        string memory _shareSymbol
    ) ERC20(_shareName, _shareSymbol) {
        if (_usdc == address(0)) revert ZeroAddress();
        if (_roleManager == address(0)) revert ZeroAddress();
        if (_multisig == address(0)) revert ZeroAddress();
        if (_treasury == address(0)) revert ZeroAddress();
        if (_usdc.code.length == 0) revert NotAContract();
        if (_roleManager.code.length == 0) revert NotAContract();
        if (_feeRate > MAX_FEE_RATE) revert InvalidFeeRate();
        if (_cooldownPeriod < MIN_COOLDOWN || _cooldownPeriod > MAX_COOLDOWN) revert InvalidCooldown();

        usdc = IERC20(_usdc);
        roleManager = IRoleManager(_roleManager);

        multisig = _multisig;
        treasury = _treasury;
        feeRate = _feeRate;
        cooldownPeriod = _cooldownPeriod;
    }

    // ============ View Functions ============

    /**
     * @notice Get total assets (NAV) computed from deposits, withdrawals, and yield
     * @return Total assets in USDC (6 decimals)
     * @dev totalAssets = totalDeposited - totalWithdrawn + accumulatedYield
     * @dev Invariant I.3: This value applies uniformly to all shares
     */
    function totalAssets() public view returns (uint256) {
        int256 nav = int256(totalDeposited) - int256(totalWithdrawn) + accumulatedYield;

        // NAV cannot be negative (would mean more withdrawn than deposited + yield)
        // In practice this shouldn't happen, but we protect against it
        return nav > 0 ? uint256(nav) : 0;
    }

    /**
     * @notice Calculate current share price
     * @return price Share price scaled to 18 decimals
     * @dev Returns INITIAL_SHARE_PRICE (1e6) when no shares exist, meaning 1 USDC = 1 share
     * @dev With 18 decimal shares and 6 decimal USDC: price = (NAV * 1e18) / totalShares
     * @dev Invariant I.3: Price applies to ALL shares equally (user, escrowed, treasury)
     */
    function sharePrice() public view returns (uint256) {
        uint256 totalShareSupply = totalSupply();
        if (totalShareSupply == 0) {
            return INITIAL_SHARE_PRICE; // 1 USDC = 1 share initially
        }
        uint256 nav = totalAssets();
        return Math.mulDiv(nav, PRECISION, totalShareSupply);
    }

    /**
     * @notice Get total outstanding shares
     * @return Total share supply (includes escrowed shares)
     * @dev Invariant I.3: Escrowed shares are still part of totalSupply
     */
    function totalShares() external view returns (uint256) {
        return totalSupply();
    }

    /**
     * @notice Get pending withdrawal shares count (escrowed in vault)
     * @return Total shares held in escrow for pending withdrawals
     * @dev Invariant I.2: These shares are locked until fulfilled or cancelled
     */
    function pendingWithdrawals() external view returns (uint256) {
        return pendingWithdrawalShares;
    }

    /**
     * @notice Get withdrawal queue length (including processed)
     * @return Queue length
     */
    function withdrawalQueueLength() external view returns (uint256) {
        return withdrawalQueue.length;
    }

    /**
     * @notice Get withdrawal request details
     * @param requestId Request ID
     * @return Withdrawal request struct
     */
    function getWithdrawalRequest(uint256 requestId) external view returns (WithdrawalRequest memory) {
        if (requestId >= withdrawalQueue.length) revert InvalidRequestId();
        return withdrawalQueue[requestId];
    }

    /**
     * @notice Get vault's USDC balance (available for withdrawals)
     * @return Available USDC in vault
     */
    function availableLiquidity() public view returns (uint256) {
        return usdc.balanceOf(address(this));
    }

    /**
     * @notice Calculate USDC value of shares at current NAV
     * @param shareAmount Number of shares
     * @return USDC value
     * @dev Invariant I.1: This is the amount that would be paid out for burning shares
     */
    function sharesToUsdc(uint256 shareAmount) public view returns (uint256) {
        return Math.mulDiv(shareAmount, sharePrice(), PRECISION);
    }

    /**
     * @notice Calculate shares for USDC amount at current NAV
     * @param usdcAmount USDC amount
     * @return Number of shares
     */
    function usdcToShares(uint256 usdcAmount) public view returns (uint256) {
        uint256 price = sharePrice();
        if (price == 0) return 0;
        return Math.mulDiv(usdcAmount, PRECISION, price);
    }

    /**
     * @notice Get shares held in escrow by vault (for pending withdrawals)
     * @return Escrowed share balance
     */
    function escrowedShares() public view returns (uint256) {
        return balanceOf(address(this));
    }

    // ============ User Functions ============

    /**
     * @notice Deposit USDC and receive vault shares
     * @param usdcAmount Amount of USDC to deposit
     * @return sharesMinted Number of shares minted
     * @dev Invariant I.1: Shares minted = usdcAmount / sharePrice
     * @dev Deposits auto-update totalAssets via totalDeposited tracking
     */
    function deposit(uint256 usdcAmount)
        external
        nonReentrant
        whenNotPaused
        whenDepositsNotPaused
        returns (uint256 sharesMinted)
    {
        if (usdcAmount == 0) revert ZeroAmount();

        // Check global cap
        uint256 currentAssets = totalAssets();
        if (globalCap > 0) {
            if (currentAssets + usdcAmount > globalCap) {
                revert ExceedsGlobalCap();
            }
        }

        // Calculate shares to mint BEFORE updating totalDeposited
        // This ensures the price used is the pre-deposit price
        sharesMinted = usdcToShares(usdcAmount);

        // M-1 Fix: Ensure user receives at least 1 share
        if (sharesMinted == 0) revert ZeroShares();

        // Update deposit tracking (auto-updates NAV via totalAssets())
        totalDeposited += usdcAmount;

        // Mint shares to user
        _mint(msg.sender, sharesMinted);

        // Transfer USDC from user (SafeERC20 handles non-standard tokens)
        usdc.safeTransferFrom(msg.sender, address(this), usdcAmount);

        // Forward excess to multisig (keep buffer)
        _forwardToMultisig();

        emit Deposit(msg.sender, usdcAmount, sharesMinted);
    }

    /**
     * @notice Request a withdrawal of shares
     * @param shareAmount Number of shares to withdraw
     * @return requestId The withdrawal request ID
     * @dev Invariant I.2: Shares are transferred to vault (escrowed) immediately
     * @dev This prevents double-spending - shares cannot be transferred or used again
     */
    function requestWithdrawal(uint256 shareAmount)
        external
        nonReentrant
        whenNotPaused
        whenWithdrawalsNotPaused
        returns (uint256 requestId)
    {
        if (shareAmount == 0) revert ZeroAmount();
        if (balanceOf(msg.sender) < shareAmount) revert InsufficientShares();

        // M-1: Check per-user pending request limit
        if (userPendingRequests[msg.sender] >= MAX_PENDING_PER_USER) revert TooManyPendingRequests();

        // INVARIANT I.2: Escrow shares into vault
        // Shares are transferred FROM user TO vault, preventing double-spend
        _transfer(msg.sender, address(this), shareAmount);

        requestId = withdrawalQueue.length;

        withdrawalQueue.push(WithdrawalRequest({
            requester: msg.sender,
            shares: shareAmount,
            requestTimestamp: block.timestamp
        }));

        pendingWithdrawalShares += shareAmount;
        userPendingRequests[msg.sender]++;

        // INVARIANT I.2: Verify escrow balance matches pending shares
        if (balanceOf(address(this)) < pendingWithdrawalShares) revert EscrowBalanceMismatch();

        emit WithdrawalRequested(msg.sender, shareAmount, requestId);
    }

    // ============ Operator Functions ============

    /**
     * @notice Fulfill pending withdrawals from the queue (operator only)
     * @param count Maximum number of withdrawals to process
     * @return processed Number of withdrawals processed
     * @return usdcPaid Total USDC paid out
     * @dev Invariant I.1: Each fulfillment burns shares at current NAV
     * @dev Invariant I.5: FIFO order, graceful termination on low liquidity
     */
    function fulfillWithdrawals(uint256 count)
        external
        nonReentrant
        onlyOperator
        whenNotPaused
        whenWithdrawalsNotPaused
        returns (uint256 processed, uint256 usdcPaid)
    {
        uint256 available = availableLiquidity();
        uint256 head = withdrawalQueueHead;
        uint256 queueLen = withdrawalQueue.length;

        // Snapshot for invariant check
        uint256 sharesBefore = totalSupply();

        while (processed < count && head < queueLen) {
            WithdrawalRequest storage request = withdrawalQueue[head];

            // Skip if already processed (shares = 0)
            if (request.shares == 0) {
                head++;
                continue;
            }

            // H-2 Fix: If cooldown not met, stop processing (maintain FIFO)
            // Don't skip past immature requests - they should be processed first
            if (block.timestamp < request.requestTimestamp + cooldownPeriod) {
                break; // Stop here, wait for this request to mature
            }

            uint256 sharesToBurn = request.shares;

            // Calculate USDC to pay at current NAV
            // INVARIANT I.1: usdcOut = sharesToBurn * NAV / totalShares
            uint256 usdcOut = sharesToUsdc(sharesToBurn);

            // INVARIANT I.5: Graceful termination if insufficient liquidity
            if (usdcOut > available) {
                break; // Stop processing, don't revert
            }

            // INVARIANT I.1: Burn escrowed shares from vault
            _burn(address(this), sharesToBurn);

            // Update state
            pendingWithdrawalShares -= sharesToBurn;
            userPendingRequests[request.requester]--;
            request.shares = 0;

            // Track withdrawal for NAV calculation
            totalWithdrawn += usdcOut;

            // Transfer USDC to requester (SafeERC20 handles non-standard tokens)
            // INVARIANT I.1: USDC only exits when shares are burned
            usdc.safeTransfer(request.requester, usdcOut);

            available -= usdcOut;
            usdcPaid += usdcOut;
            processed++;
            head++;

            emit WithdrawalFulfilled(request.requester, sharesToBurn, usdcOut, head - 1);
        }

        // INVARIANT I.5: Queue head must only advance (FIFO ordering)
        if (head < withdrawalQueueHead) revert QueueHeadRegression();
        withdrawalQueueHead = head;

        // INVARIANT I.1: Conservation of value
        // If shares were burned, totalShares decreased proportionally to USDC paid
        if (processed > 0) {
            uint256 sharesAfter = totalSupply();
            // Verify: shares decreased when USDC exited
            if (sharesAfter >= sharesBefore && usdcPaid > 0) revert SharesNotBurned();
        }

        // INVARIANT I.2: Escrow balance covers pending shares
        // Note: Balance may exceed pending if shares were donated directly to vault
        // (orphaned shares can be recovered via recoverOrphanedShares)
        if (balanceOf(address(this)) < pendingWithdrawalShares) revert EscrowBalanceMismatch();
    }

    // ============ Owner Functions ============

    // ============ Timelocked Configuration Functions ============

    /**
     * @notice Queue a multisig address change (3-day timelock)
     * @param newMultisig New multisig address
     */
    function queueMultisig(address newMultisig) external onlyOwner {
        if (newMultisig == address(0)) revert ZeroAddress();
        pendingMultisig = newMultisig;
        pendingMultisigTimestamp = block.timestamp + TIMELOCK_MULTISIG;
        emit MultisigChangeQueued(newMultisig, pendingMultisigTimestamp);
    }

    /**
     * @notice Execute a queued multisig change after timelock expires
     */
    function executeMultisig() external onlyOwner {
        if (pendingMultisigTimestamp == 0) revert NoPendingChange();
        if (block.timestamp < pendingMultisigTimestamp) revert TimelockNotExpired();
        address oldMultisig = multisig;
        multisig = pendingMultisig;
        pendingMultisig = address(0);
        pendingMultisigTimestamp = 0;
        emit MultisigChangeExecuted(oldMultisig, multisig);
    }

    /**
     * @notice Cancel a pending multisig change
     */
    function cancelMultisig() external onlyOwner {
        if (pendingMultisigTimestamp == 0) revert NoPendingChange();
        address cancelled = pendingMultisig;
        pendingMultisig = address(0);
        pendingMultisigTimestamp = 0;
        emit MultisigChangeCancelled(cancelled);
    }

    /**
     * @notice Queue a treasury address change (2-day timelock)
     * @param newTreasury New treasury address
     */
    function queueTreasury(address newTreasury) external onlyOwner {
        if (newTreasury == address(0)) revert ZeroAddress();
        pendingTreasury = newTreasury;
        pendingTreasuryTimestamp = block.timestamp + TIMELOCK_TREASURY;
        emit TreasuryChangeQueued(newTreasury, pendingTreasuryTimestamp);
    }

    /**
     * @notice Execute a queued treasury change after timelock expires
     */
    function executeTreasury() external onlyOwner {
        if (pendingTreasuryTimestamp == 0) revert NoPendingChange();
        if (block.timestamp < pendingTreasuryTimestamp) revert TimelockNotExpired();
        address oldTreasury = treasury;
        treasury = pendingTreasury;
        pendingTreasury = address(0);
        pendingTreasuryTimestamp = 0;
        emit TreasuryChangeExecuted(oldTreasury, treasury);
    }

    /**
     * @notice Cancel a pending treasury change
     */
    function cancelTreasury() external onlyOwner {
        if (pendingTreasuryTimestamp == 0) revert NoPendingChange();
        address cancelled = pendingTreasury;
        pendingTreasury = address(0);
        pendingTreasuryTimestamp = 0;
        emit TreasuryChangeCancelled(cancelled);
    }

    /**
     * @notice Queue a fee rate change (1-day timelock)
     * @param newFeeRate New fee rate (18 decimals)
     * @dev Invariant I.4: Fee rate capped at MAX_FEE_RATE
     */
    function queueFeeRate(uint256 newFeeRate) external onlyOwner {
        if (newFeeRate > MAX_FEE_RATE) revert InvalidFeeRate();
        pendingFeeRate = newFeeRate;
        pendingFeeRateTimestamp = block.timestamp + TIMELOCK_FEE_RATE;
        emit FeeRateChangeQueued(newFeeRate, pendingFeeRateTimestamp);
    }

    /**
     * @notice Execute a queued fee rate change after timelock expires
     */
    function executeFeeRate() external onlyOwner {
        if (pendingFeeRateTimestamp == 0) revert NoPendingChange();
        if (block.timestamp < pendingFeeRateTimestamp) revert TimelockNotExpired();
        uint256 oldFeeRate = feeRate;
        feeRate = pendingFeeRate;
        pendingFeeRate = 0;
        pendingFeeRateTimestamp = 0;
        emit FeeRateChangeExecuted(oldFeeRate, feeRate);
    }

    /**
     * @notice Cancel a pending fee rate change
     */
    function cancelFeeRate() external onlyOwner {
        if (pendingFeeRateTimestamp == 0) revert NoPendingChange();
        uint256 cancelled = pendingFeeRate;
        pendingFeeRate = 0;
        pendingFeeRateTimestamp = 0;
        emit FeeRateChangeCancelled(cancelled);
    }

    /**
     * @notice Update global AUM cap
     * @param newCap New cap (0 = unlimited)
     */
    function setGlobalCap(uint256 newCap) external onlyOwner {
        emit GlobalCapUpdated(globalCap, newCap);
        globalCap = newCap;
    }

    /**
     * @notice Update withdrawal buffer
     * @param newBuffer New buffer amount
     * @dev Callable by owner or operator for operational flexibility
     */
    function setWithdrawalBuffer(uint256 newBuffer) external onlyOperatorOrOwner {
        emit WithdrawalBufferUpdated(withdrawalBuffer, newBuffer);
        withdrawalBuffer = newBuffer;
    }

    /**
     * @notice Queue a cooldown period change (1-day timelock)
     * @param newCooldown New cooldown in seconds
     * @dev IMPORTANT: This change affects ALL pending withdrawals, including existing ones.
     *      Increasing the cooldown will delay fulfillment of requests already in the queue.
     */
    function queueCooldown(uint256 newCooldown) external onlyOwner {
        if (newCooldown < MIN_COOLDOWN || newCooldown > MAX_COOLDOWN) revert InvalidCooldown();
        pendingCooldownPeriod = newCooldown;
        pendingCooldownTimestamp = block.timestamp + TIMELOCK_COOLDOWN;
        emit CooldownChangeQueued(newCooldown, pendingCooldownTimestamp);
    }

    /**
     * @notice Execute a queued cooldown change after timelock expires
     */
    function executeCooldown() external onlyOwner {
        if (pendingCooldownTimestamp == 0) revert NoPendingChange();
        if (block.timestamp < pendingCooldownTimestamp) revert TimelockNotExpired();
        uint256 oldCooldown = cooldownPeriod;
        cooldownPeriod = pendingCooldownPeriod;
        pendingCooldownPeriod = 0;
        pendingCooldownTimestamp = 0;
        emit CooldownChangeExecuted(oldCooldown, cooldownPeriod);
    }

    /**
     * @notice Cancel a pending cooldown change
     */
    function cancelCooldown() external onlyOwner {
        if (pendingCooldownTimestamp == 0) revert NoPendingChange();
        uint256 cancelled = pendingCooldownPeriod;
        pendingCooldownPeriod = 0;
        pendingCooldownTimestamp = 0;
        emit CooldownChangeCancelled(cancelled);
    }

    /**
     * @notice Force process a specific withdrawal (emergency, skips cooldown)
     * @param requestId Request ID to process
     * @dev Invariant I.1: Still burns shares at current NAV
     * @dev WARNING: Skips FIFO order - use only in emergencies
     * @dev Callable by owner or operator for operational flexibility
     */
    function forceProcessWithdrawal(uint256 requestId) external nonReentrant onlyOperatorOrOwner {
        if (requestId >= withdrawalQueue.length) revert InvalidRequestId();

        WithdrawalRequest storage request = withdrawalQueue[requestId];
        if (request.shares == 0) revert RequestAlreadyProcessed();

        uint256 sharesToBurn = request.shares;
        uint256 usdcOut = sharesToUsdc(sharesToBurn);

        if (usdcOut > availableLiquidity()) revert InsufficientLiquidity();

        // Burn escrowed shares from vault
        _burn(address(this), sharesToBurn);

        // Update state
        pendingWithdrawalShares -= sharesToBurn;
        userPendingRequests[request.requester]--;
        request.shares = 0;

        // Track withdrawal for NAV calculation
        totalWithdrawn += usdcOut;

        // Transfer USDC (SafeERC20 handles non-standard tokens)
        usdc.safeTransfer(request.requester, usdcOut);

        // INVARIANT I.2: Escrow balance covers pending shares
        if (balanceOf(address(this)) < pendingWithdrawalShares) revert EscrowBalanceMismatch();

        emit WithdrawalForced(request.requester, sharesToBurn, usdcOut, requestId);
    }

    /**
     * @notice Cancel a queued withdrawal (emergency, or by user within grace period)
     * @param requestId Request ID to cancel
     * @dev Invariant I.2: Returns escrowed shares to original requester
     * @dev H-3: Users can cancel within CANCELLATION_WINDOW, owner can cancel anytime
     */
    function cancelWithdrawal(uint256 requestId) external nonReentrant {
        if (requestId >= withdrawalQueue.length) revert InvalidRequestId();

        WithdrawalRequest storage request = withdrawalQueue[requestId];
        if (request.shares == 0) revert RequestAlreadyProcessed();

        // H-3: Allow owner always, or requester within cancellation window
        bool isOwner = msg.sender == roleManager.owner();
        bool isRequesterInWindow = msg.sender == request.requester &&
            block.timestamp < request.requestTimestamp + CANCELLATION_WINDOW;

        if (!isOwner && !isRequesterInWindow) revert Unauthorized();

        uint256 sharesToReturn = request.shares;
        address requester = request.requester;

        // Update state first
        pendingWithdrawalShares -= sharesToReturn;
        userPendingRequests[requester]--;
        request.shares = 0;

        // Return escrowed shares to requester
        _transfer(address(this), requester, sharesToReturn);

        // INVARIANT I.2: Escrow balance covers pending shares
        if (balanceOf(address(this)) < pendingWithdrawalShares) revert EscrowBalanceMismatch();

        emit WithdrawalCancelled(requester, sharesToReturn, requestId);
    }

    /**
     * @notice Report yield and collect fees atomically
     * @param yieldDelta Change in yield (positive for gains, negative for losses)
     * @dev This is the ONLY way to report yield and collect fees. Fees are:
     *      - Collected as a percentage of positive yield only
     *      - Paid via minting shares to treasury (no USDC transfer)
     *      - Applied at report time (simple, predictable)
     *
     * Fee model: fee = positiveYield * feeRate / PRECISION
     * This is simpler than HWM-based fees - every positive yield report triggers fees.
     *
     * Safety mechanisms:
     * - Enforces MIN_YIELD_REPORT_INTERVAL (1 day) between reports
     * - If maxYieldChangePercent is set, enforces bounds to prevent misreporting
     *
     * @dev Callable by owner or operator for daily operational flexibility.
     *      Safety is maintained via maxYieldChangePercent bounds (default 0.5% of NAV).
     */
    function reportYieldAndCollectFees(int256 yieldDelta) external onlyOperatorOrOwner {
        // Enforce minimum interval between reports (prevents compounding bypass)
        if (lastYieldReportTime > 0 && block.timestamp < lastYieldReportTime + MIN_YIELD_REPORT_INTERVAL) {
            revert ReportTooSoon();
        }

        // Check yield bounds if enabled
        if (maxYieldChangePercent > 0) {
            uint256 nav = totalAssets();
            // Only enforce if vault has assets (skip on first deposit or empty vault)
            if (nav > 0) {
                uint256 absoluteDelta = yieldDelta >= 0 ? uint256(yieldDelta) : uint256(-yieldDelta);
                uint256 maxAllowed = (nav * maxYieldChangePercent) / 1e18;
                if (absoluteDelta > maxAllowed) revert YieldChangeTooLarge();
            }
        }

        // Update accumulated yield
        accumulatedYield += yieldDelta;
        lastYieldReportTime = block.timestamp;

        emit YieldReported(yieldDelta, accumulatedYield, block.timestamp);

        // Collect fees directly from positive yield
        if (yieldDelta > 0 && feeRate > 0) {
            uint256 yield = uint256(yieldDelta);
            uint256 fee = Math.mulDiv(yield, feeRate, PRECISION);

            if (fee > 0) {
                // Convert fee to shares at current price (post-yield)
                uint256 feeShares = usdcToShares(fee);
                if (feeShares > 0) {
                    _mint(treasury, feeShares);
                    emit FeeCollected(feeShares, treasury);
                }
            }
        }
    }

    /**
     * @notice Set maximum yield change percentage (safety bounds)
     * @param _maxPercent Maximum yield change as percentage of NAV (18 decimals)
     * @dev Set to 0 to disable bounds checking. Only callable by owner.
     *      Default is 1% (0.01e18). Yield deltas exceeding this % of vault NAV will revert.
     */
    function setMaxYieldChangePercent(uint256 _maxPercent) external onlyOwner {
        emit MaxYieldChangeUpdated(maxYieldChangePercent, _maxPercent);
        maxYieldChangePercent = _maxPercent;
    }

    /**
     * @notice Recover orphaned shares sent directly to vault (H-2)
     * @dev If someone accidentally transfers shares to the vault (not via requestWithdrawal),
     *      those shares become stuck. This function burns them to prevent dilution.
     *      V-3 Fix: Defensive check prevents revert on corrupted state.
     * @return recovered Amount of orphaned shares burned
     */
    function recoverOrphanedShares() external onlyOwner returns (uint256 recovered) {
        uint256 vaultShareBalance = balanceOf(address(this));

        // V-3: Defensive check - if invariant is violated, return 0 instead of reverting
        if (vaultShareBalance <= pendingWithdrawalShares) {
            return 0;
        }

        recovered = vaultShareBalance - pendingWithdrawalShares;

        _burn(address(this), recovered);
        emit OrphanedSharesRecovered(recovered);
    }

    /**
     * @notice Purge processed withdrawal entries to reclaim storage (M-1)
     * @param count Maximum number of entries to purge
     * @return purged Number of entries purged
     * @dev Clears storage for processed entries (shares=0) up to withdrawalQueueHead.
     *      This reclaims storage slots and provides gas refunds.
     *      Note: Array length doesn't shrink, but storage is cleared.
     *
     *      PUBLICLY CALLABLE: This function has no access control by design.
     *      Anyone can call it to clean up processed entries and receive gas refunds.
     *      This is safe because it only deletes already-processed entries (shares=0)
     *      and cannot affect pending or unprocessed withdrawals.
     */
    function purgeProcessedWithdrawals(uint256 count) external returns (uint256 purged) {
        uint256 head = withdrawalQueueHead;
        uint256 toPurge = count < head ? count : head;

        for (uint256 i = head - toPurge; i < head && purged < count; i++) {
            // Only purge if already processed (shares = 0) and not already purged
            if (withdrawalQueue[i].requester != address(0)) {
                delete withdrawalQueue[i];
                purged++;
            }
        }

        if (purged > 0) {
            emit WithdrawalsPurged(purged);
        }
    }

    // ============ ERC20 Overrides ============

    /**
     * @notice Override transfer to prevent accidental share loss (V-2 fix)
     * @dev Users cannot transfer shares directly to the vault address.
     *      Use requestWithdrawal() instead to properly escrow shares.
     */
    function transfer(address to, uint256 amount) public override returns (bool) {
        if (to == address(this)) revert CannotTransferToVault();
        return super.transfer(to, amount);
    }

    /**
     * @notice Override transferFrom to prevent accidental share loss (V-2 fix)
     * @dev Users cannot transfer shares directly to the vault address.
     *      Use requestWithdrawal() instead to properly escrow shares.
     */
    function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
        if (to == address(this)) revert CannotTransferToVault();
        return super.transferFrom(from, to, amount);
    }

    // ============ Internal Functions ============

    /**
     * @notice Forward excess USDC to multisig for strategy deployment
     * @dev Called after deposits to send funds exceeding withdrawalBuffer to multisig.
     *      The multisig deploys these funds to external on-chain yield strategies.
     *      withdrawalBuffer is retained in vault for immediate withdrawal liquidity.
     *      If balance <= withdrawalBuffer, no transfer occurs.
     */
    function _forwardToMultisig() internal {
        uint256 balance = usdc.balanceOf(address(this));
        if (balance > withdrawalBuffer) {
            uint256 excess = balance - withdrawalBuffer;
            usdc.safeTransfer(multisig, excess);
            emit FundsForwardedToMultisig(excess);
        }
    }

}

// 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.5.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC-20
 * applications.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

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

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /// @inheritdoc IERC20
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /// @inheritdoc IERC20
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

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

    /// @inheritdoc IERC20
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

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

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation sets the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the `transferFrom` operation can force the flag to
     * true using the following override:
     *
     * ```solidity
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner`'s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance < type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.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 {
        if (!_safeTransfer(token, to, value, true)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 {
        if (!_safeTransferFrom(token, from, to, value, true)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 _safeTransfer(token, to, value, false);
    }

    /**
     * @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 _safeTransferFrom(token, from, to, value, false);
    }

    /**
     * @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 {
        if (!_safeApprove(token, spender, value, false)) {
            if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
            if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @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 relies 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 relies 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}.
     * Oppositely, 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 `token.transfer(to, value)` call, 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 to The recipient of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
        bytes4 selector = IERC20.transfer.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(to, shr(96, not(0))))
            mstore(0x24, value)
            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
        }
    }

    /**
     * @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, 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 from The sender of the tokens
     * @param to The recipient of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value,
        bool bubble
    ) private returns (bool success) {
        bytes4 selector = IERC20.transferFrom.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(from, shr(96, not(0))))
            mstore(0x24, and(to, shr(96, not(0))))
            mstore(0x44, value)
            success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
            mstore(0x60, 0)
        }
    }

    /**
     * @dev Imitates a Solidity `token.approve(spender, value)` call, 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 spender The spender of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
        bytes4 selector = IERC20.approve.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(spender, shr(96, not(0))))
            mstore(0x24, value)
            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
        }
    }
}

File 5 of 18 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Return the 512-bit addition of two uint256.
     *
     * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
     */
    function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        assembly ("memory-safe") {
            low := add(a, b)
            high := lt(low, a)
        }
    }

    /**
     * @dev Return the 512-bit multiplication of two uint256.
     *
     * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
     */
    function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
        // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
        // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
        // variables such that product = high * 2²⁵⁶ + low.
        assembly ("memory-safe") {
            let mm := mulmod(a, b, not(0))
            low := mul(a, b)
            high := sub(sub(mm, low), lt(mm, low))
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a + b;
            success = c >= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a - b;
            success = c <= a;
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            uint256 c = a * b;
            assembly ("memory-safe") {
                // Only true when the multiplication doesn't overflow
                // (c / a == b) || (a == 0)
                success := or(eq(div(c, a), b), iszero(a))
            }
            // equivalent to: success ? c : 0
            result = c * SafeCast.toUint(success);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `DIV` opcode returns zero when the denominator is 0.
                result := div(a, b)
            }
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
        unchecked {
            success = b > 0;
            assembly ("memory-safe") {
                // The `MOD` opcode returns zero when the denominator is 0.
                result := mod(a, b)
            }
        }
    }

    /**
     * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryAdd(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
     */
    function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
        (, uint256 result) = trySub(a, b);
        return result;
    }

    /**
     * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
     */
    function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
        (bool success, uint256 result) = tryMul(a, b);
        return ternary(success, result, type(uint256).max);
    }

    /**
     * @dev Branchless ternary evaluation for `condition ? a : b`. Gas costs are constant.
     *
     * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
     * However, the compiler may optimize Solidity ternary operations (i.e. `condition ? a : b`) to only compute
     * one branch when needed, making this function more expensive.
     */
    function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            // branchless ternary works because:
            // b ^ (a ^ b) == a
            // b ^ 0 == b
            return b ^ ((a ^ b) * SafeCast.toUint(condition));
        }
    }

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

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

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

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }

        // The following calculation ensures accurate ceiling division without overflow.
        // Since a is non-zero, (a - 1) / b will not overflow.
        // The largest possible result occurs when (a - 1) / b is type(uint256).max,
        // but the largest value we can obtain is type(uint256).max - 1, which happens
        // when a = type(uint256).max and b = 1.
        unchecked {
            return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
        }
    }

    /**
     * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     *
     * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);

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

            // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
            if (denominator <= high) {
                Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
            }

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

            // Make division exact by subtracting the remainder from [high low].
            uint256 remainder;
            assembly ("memory-safe") {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

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

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

            uint256 twos = denominator & (0 - denominator);
            assembly ("memory-safe") {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [high low] by twos.
                low := div(low, twos)

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

            // Shift in bits from high into low.
            low |= high * twos;

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

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
            inverse *= 2 - denominator * inverse; // inverse mod 2³²
            inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
            inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
            inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶

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

    /**
     * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
    }

    /**
     * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
     */
    function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
        unchecked {
            (uint256 high, uint256 low) = mul512(x, y);
            if (high >= 1 << n) {
                Panic.panic(Panic.UNDER_OVERFLOW);
            }
            return (high << (256 - n)) | (low >> n);
        }
    }

    /**
     * @dev Calculates x * y >> n with full precision, following the selected rounding direction.
     */
    function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
        return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
    }

    /**
     * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
     *
     * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
     * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
     *
     * If the input value is not inversible, 0 is returned.
     *
     * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
     * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
     */
    function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
        unchecked {
            if (n == 0) return 0;

            // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
            // Used to compute integers x and y such that: ax + ny = gcd(a, n).
            // When the gcd is 1, then the inverse of a modulo n exists and it's x.
            // ax + ny = 1
            // ax = 1 + (-y)n
            // ax ≡ 1 (mod n) # x is the inverse of a modulo n

            // If the remainder is 0 the gcd is n right away.
            uint256 remainder = a % n;
            uint256 gcd = n;

            // Therefore the initial coefficients are:
            // ax + ny = gcd(a, n) = n
            // 0a + 1n = n
            int256 x = 0;
            int256 y = 1;

            while (remainder != 0) {
                uint256 quotient = gcd / remainder;

                (gcd, remainder) = (
                    // The old remainder is the next gcd to try.
                    remainder,
                    // Compute the next remainder.
                    // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
                    // where gcd is at most n (capped to type(uint256).max)
                    gcd - remainder * quotient
                );

                (x, y) = (
                    // Increment the coefficient of a.
                    y,
                    // Decrement the coefficient of n.
                    // Can overflow, but the result is casted to uint256 so that the
                    // next value of y is "wrapped around" to a value between 0 and n - 1.
                    x - y * int256(quotient)
                );
            }

            if (gcd != 1) return 0; // No inverse exists.
            return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
        }
    }

    /**
     * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
     *
     * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
     * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
     * `a**(p-2)` is the modular multiplicative inverse of a in Fp.
     *
     * NOTE: this function does NOT check that `p` is a prime greater than `2`.
     */
    function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
        unchecked {
            return Math.modExp(a, p - 2, p);
        }
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
     *
     * Requirements:
     * - modulus can't be zero
     * - underlying staticcall to precompile must succeed
     *
     * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
     * sure the chain you're using it on supports the precompiled contract for modular exponentiation
     * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
     * the underlying function will succeed given the lack of a revert, but the result may be incorrectly
     * interpreted as 0.
     */
    function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
        (bool success, uint256 result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
     * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
     * to operate modulo 0 or if the underlying precompile reverted.
     *
     * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
     * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
     * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
     * of a revert, but the result may be incorrectly interpreted as 0.
     */
    function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
        if (m == 0) return (false, 0);
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            // | Offset    | Content    | Content (Hex)                                                      |
            // |-----------|------------|--------------------------------------------------------------------|
            // | 0x00:0x1f | size of b  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x20:0x3f | size of e  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x40:0x5f | size of m  | 0x0000000000000000000000000000000000000000000000000000000000000020 |
            // | 0x60:0x7f | value of b | 0x<.............................................................b> |
            // | 0x80:0x9f | value of e | 0x<.............................................................e> |
            // | 0xa0:0xbf | value of m | 0x<.............................................................m> |
            mstore(ptr, 0x20)
            mstore(add(ptr, 0x20), 0x20)
            mstore(add(ptr, 0x40), 0x20)
            mstore(add(ptr, 0x60), b)
            mstore(add(ptr, 0x80), e)
            mstore(add(ptr, 0xa0), m)

            // Given the result < m, it's guaranteed to fit in 32 bytes,
            // so we can use the memory scratch space located at offset 0.
            success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
            result := mload(0x00)
        }
    }

    /**
     * @dev Variant of {modExp} that supports inputs of arbitrary length.
     */
    function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
        (bool success, bytes memory result) = tryModExp(b, e, m);
        if (!success) {
            Panic.panic(Panic.DIVISION_BY_ZERO);
        }
        return result;
    }

    /**
     * @dev Variant of {tryModExp} that supports inputs of arbitrary length.
     */
    function tryModExp(
        bytes memory b,
        bytes memory e,
        bytes memory m
    ) internal view returns (bool success, bytes memory result) {
        if (_zeroBytes(m)) return (false, new bytes(0));

        uint256 mLen = m.length;

        // Encode call args in result and move the free memory pointer
        result = abi.encodePacked(b.length, e.length, mLen, b, e, m);

        assembly ("memory-safe") {
            let dataPtr := add(result, 0x20)
            // Write result on top of args to avoid allocating extra memory.
            success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
            // Overwrite the length.
            // result.length > returndatasize() is guaranteed because returndatasize() == m.length
            mstore(result, mLen)
            // Set the memory pointer after the returned data.
            mstore(0x40, add(dataPtr, mLen))
        }
    }

    /**
     * @dev Returns whether the provided byte array is zero.
     */
    function _zeroBytes(bytes memory buffer) private pure returns (bool) {
        uint256 chunk;
        for (uint256 i = 0; i < buffer.length; i += 0x20) {
            // See _unsafeReadBytesOffset from utils/Bytes.sol
            assembly ("memory-safe") {
                chunk := mload(add(add(buffer, 0x20), i))
            }
            if (chunk >> (8 * saturatingSub(i + 0x20, buffer.length)) != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * This method is based on Newton's method for computing square roots; the algorithm is restricted to only
     * using integer operations.
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        unchecked {
            // Take care of easy edge cases when a == 0 or a == 1
            if (a <= 1) {
                return a;
            }

            // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
            // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
            // the current value as `ε_n = | x_n - sqrt(a) |`.
            //
            // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
            // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
            // bigger than any uint256.
            //
            // By noticing that
            // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
            // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
            // to the msb function.
            uint256 aa = a;
            uint256 xn = 1;

            if (aa >= (1 << 128)) {
                aa >>= 128;
                xn <<= 64;
            }
            if (aa >= (1 << 64)) {
                aa >>= 64;
                xn <<= 32;
            }
            if (aa >= (1 << 32)) {
                aa >>= 32;
                xn <<= 16;
            }
            if (aa >= (1 << 16)) {
                aa >>= 16;
                xn <<= 8;
            }
            if (aa >= (1 << 8)) {
                aa >>= 8;
                xn <<= 4;
            }
            if (aa >= (1 << 4)) {
                aa >>= 4;
                xn <<= 2;
            }
            if (aa >= (1 << 2)) {
                xn <<= 1;
            }

            // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
            //
            // We can refine our estimation by noticing that the middle of that interval minimizes the error.
            // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
            // This is going to be our x_0 (and ε_0)
            xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)

            // From here, Newton's method give us:
            // x_{n+1} = (x_n + a / x_n) / 2
            //
            // One should note that:
            // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
            //              = ((x_n² + a) / (2 * x_n))² - a
            //              = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
            //              = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
            //              = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
            //              = (x_n² - a)² / (2 * x_n)²
            //              = ((x_n² - a) / (2 * x_n))²
            //              ≥ 0
            // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
            //
            // This gives us the proof of quadratic convergence of the sequence:
            // ε_{n+1} = | x_{n+1} - sqrt(a) |
            //         = | (x_n + a / x_n) / 2 - sqrt(a) |
            //         = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
            //         = | (x_n - sqrt(a))² / (2 * x_n) |
            //         = | ε_n² / (2 * x_n) |
            //         = ε_n² / | (2 * x_n) |
            //
            // For the first iteration, we have a special case where x_0 is known:
            // ε_1 = ε_0² / | (2 * x_0) |
            //     ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
            //     ≤ 2**(2*e-4) / (3 * 2**(e-1))
            //     ≤ 2**(e-3) / 3
            //     ≤ 2**(e-3-log2(3))
            //     ≤ 2**(e-4.5)
            //
            // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
            // ε_{n+1} = ε_n² / | (2 * x_n) |
            //         ≤ (2**(e-k))² / (2 * 2**(e-1))
            //         ≤ 2**(2*e-2*k) / 2**e
            //         ≤ 2**(e-2*k)
            xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5)  -- special case, see above
            xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9)    -- general case with k = 4.5
            xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18)   -- general case with k = 9
            xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36)   -- general case with k = 18
            xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72)   -- general case with k = 36
            xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144)  -- general case with k = 72

            // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
            // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
            // sqrt(a) or sqrt(a) + 1.
            return xn - SafeCast.toUint(xn > a / xn);
        }
    }

    /**
     * @dev Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // If upper 8 bits of 16-bit half set, add 8 to result
        r |= SafeCast.toUint((x >> r) > 0xff) << 3;
        // If upper 4 bits of 8-bit half set, add 4 to result
        r |= SafeCast.toUint((x >> r) > 0xf) << 2;

        // Shifts value right by the current result and use it as an index into this lookup table:
        //
        // | x (4 bits) |  index  | table[index] = MSB position |
        // |------------|---------|-----------------------------|
        // |    0000    |    0    |        table[0] = 0         |
        // |    0001    |    1    |        table[1] = 0         |
        // |    0010    |    2    |        table[2] = 1         |
        // |    0011    |    3    |        table[3] = 1         |
        // |    0100    |    4    |        table[4] = 2         |
        // |    0101    |    5    |        table[5] = 2         |
        // |    0110    |    6    |        table[6] = 2         |
        // |    0111    |    7    |        table[7] = 2         |
        // |    1000    |    8    |        table[8] = 3         |
        // |    1001    |    9    |        table[9] = 3         |
        // |    1010    |   10    |        table[10] = 3        |
        // |    1011    |   11    |        table[11] = 3        |
        // |    1100    |   12    |        table[12] = 3        |
        // |    1101    |   13    |        table[13] = 3        |
        // |    1110    |   14    |        table[14] = 3        |
        // |    1111    |   15    |        table[15] = 3        |
        //
        // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the first 16 bytes (most significant half).
        assembly ("memory-safe") {
            r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
        }
    }

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

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

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

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 x) internal pure returns (uint256 r) {
        // If value has upper 128 bits set, log2 result is at least 128
        r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
        // If upper 64 bits of 128-bit half set, add 64 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
        // If upper 32 bits of 64-bit half set, add 32 to result
        r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
        // If upper 16 bits of 32-bit half set, add 16 to result
        r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
        // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
        return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
    }

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

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }

    /**
     * @dev Counts the number of leading zero bits in a uint256.
     */
    function clz(uint256 x) internal pure returns (uint256) {
        return ternary(x == 0, 256, 255 - log2(x));
    }
}

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

/**
 * @title IVault
 * @notice Interface for the LazyUSD Vault
 * @dev Uses internal yield tracking and IRoleManager for access control
 */
interface IVault {
    // ============ Structs ============

    /// @notice Represents a pending withdrawal request in the queue
    /// @dev Stored in append-only array; processed entries have shares=0
    struct WithdrawalRequest {
        /// @notice Address that requested the withdrawal
        address requester;
        /// @notice Number of shares to be burned upon fulfillment
        uint256 shares;
        /// @notice Block timestamp when request was created (for cooldown)
        uint256 requestTimestamp;
    }

    // ============ Events ============

    /// @notice Emitted when a user deposits USDC and receives shares
    /// @param user Address of the depositor
    /// @param usdcAmount Amount of USDC deposited (6 decimals)
    /// @param sharesMinted Number of shares minted to user (18 decimals)
    event Deposit(address indexed user, uint256 usdcAmount, uint256 sharesMinted);
    /// @notice Emitted when a user requests a withdrawal
    /// @param user Address requesting withdrawal
    /// @param shares Number of shares escrowed for withdrawal
    /// @param requestId Index in the withdrawal queue
    event WithdrawalRequested(address indexed user, uint256 shares, uint256 requestId);
    /// @notice Emitted when a withdrawal is fulfilled
    /// @param user Address receiving USDC
    /// @param shares Number of shares burned
    /// @param usdcAmount Amount of USDC paid out
    /// @param requestId Index in the withdrawal queue
    event WithdrawalFulfilled(address indexed user, uint256 shares, uint256 usdcAmount, uint256 requestId);
    /// @notice Emitted when a withdrawal request is cancelled
    /// @param user Address whose withdrawal was cancelled
    /// @param shares Number of shares returned from escrow
    /// @param requestId Index in the withdrawal queue
    event WithdrawalCancelled(address indexed user, uint256 shares, uint256 requestId);
    /// @notice Emitted when protocol fees are collected
    /// @param feeShares Number of shares minted as fee
    /// @param treasury Address receiving the fee shares
    event FeeCollected(uint256 feeShares, address indexed treasury);
    /// @notice Emitted when excess USDC is forwarded to multisig
    /// @param amount Amount of USDC transferred
    event FundsForwardedToMultisig(uint256 amount);
    /// @notice Emitted when multisig address is updated
    event MultisigUpdated(address indexed oldMultisig, address indexed newMultisig);
    /// @notice Emitted when treasury address is updated
    event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);
    /// @notice Emitted when fee rate is updated
    event FeeRateUpdated(uint256 oldRate, uint256 newRate);
    /// @notice Emitted when global cap is updated
    event GlobalCapUpdated(uint256 oldCap, uint256 newCap);
    /// @notice Emitted when withdrawal buffer is updated
    event WithdrawalBufferUpdated(uint256 oldBuffer, uint256 newBuffer);
    /// @notice Emitted when cooldown period is updated
    event CooldownPeriodUpdated(uint256 oldPeriod, uint256 newPeriod);
    /// @notice Emitted when a withdrawal is force-processed (emergency)
    event WithdrawalForced(address indexed user, uint256 shares, uint256 usdcAmount, uint256 requestId);
    /// @notice Emitted when orphaned shares are recovered from vault
    event OrphanedSharesRecovered(uint256 amount);
    /// @notice Emitted when processed withdrawal entries are purged
    event WithdrawalsPurged(uint256 count);

    // Timelock events
    /// @notice Emitted when a fee rate change is queued
    event FeeRateChangeQueued(uint256 newRate, uint256 executionTime);
    /// @notice Emitted when a queued fee rate change is executed
    event FeeRateChangeExecuted(uint256 oldRate, uint256 newRate);
    /// @notice Emitted when a queued fee rate change is cancelled
    event FeeRateChangeCancelled(uint256 cancelledRate);
    /// @notice Emitted when a treasury change is queued
    event TreasuryChangeQueued(address newTreasury, uint256 executionTime);
    /// @notice Emitted when a queued treasury change is executed
    event TreasuryChangeExecuted(address oldTreasury, address newTreasury);
    /// @notice Emitted when a queued treasury change is cancelled
    event TreasuryChangeCancelled(address cancelledTreasury);
    /// @notice Emitted when a multisig change is queued
    event MultisigChangeQueued(address newMultisig, uint256 executionTime);
    /// @notice Emitted when a queued multisig change is executed
    event MultisigChangeExecuted(address oldMultisig, address newMultisig);
    /// @notice Emitted when a queued multisig change is cancelled
    event MultisigChangeCancelled(address cancelledMultisig);
    /// @notice Emitted when a cooldown change is queued
    event CooldownChangeQueued(uint256 newCooldown, uint256 executionTime);
    /// @notice Emitted when a queued cooldown change is executed
    event CooldownChangeExecuted(uint256 oldCooldown, uint256 newCooldown);
    /// @notice Emitted when a queued cooldown change is cancelled
    event CooldownChangeCancelled(uint256 cancelledCooldown);

    // Yield tracking events
    /// @notice Emitted when yield is reported
    /// @param yieldDelta Change in yield (positive or negative)
    /// @param newAccumulatedYield Updated cumulative yield
    /// @param timestamp Block timestamp of the report
    event YieldReported(int256 yieldDelta, int256 newAccumulatedYield, uint256 timestamp);
    /// @notice Emitted when max yield change percentage is updated
    /// @param oldValue Previous max percentage
    /// @param newValue New max percentage
    event MaxYieldChangeUpdated(uint256 oldValue, uint256 newValue);

    // ============ View Functions ============

    /**
     * @notice Calculate current share price
     * @return price Share price in USDC (18 decimal precision)
     */
    function sharePrice() external view returns (uint256);

    /**
     * @notice Get total outstanding shares
     * @return Total share supply
     */
    function totalShares() external view returns (uint256);

    /**
     * @notice Get accumulated yield from strategies
     * @return Net yield in USDC (6 decimals), can be negative
     */
    function accumulatedYield() external view returns (int256);

    /**
     * @notice Get timestamp of last yield report
     * @return Unix timestamp
     */
    function lastYieldReportTime() external view returns (uint256);

    /**
     * @notice Get maximum yield change percentage
     * @return Max percentage (18 decimals)
     */
    function maxYieldChangePercent() external view returns (uint256);

    /**
     * @notice Get pending withdrawal shares count
     * @return Total shares pending withdrawal
     */
    function pendingWithdrawals() external view returns (uint256);

    /**
     * @notice Get withdrawal queue length
     * @return Queue length
     */
    function withdrawalQueueLength() external view returns (uint256);

    /**
     * @notice Get withdrawal request details
     * @param requestId Request ID
     * @return Withdrawal request struct
     */
    function getWithdrawalRequest(uint256 requestId) external view returns (WithdrawalRequest memory);

    // ============ User Functions ============

    /**
     * @notice Deposit USDC and receive vault shares
     * @param usdcAmount Amount of USDC to deposit
     * @return sharesMinted Number of shares minted
     */
    function deposit(uint256 usdcAmount) external returns (uint256 sharesMinted);

    /**
     * @notice Request a withdrawal of shares
     * @param shares Number of shares to withdraw
     * @return requestId The withdrawal request ID
     */
    function requestWithdrawal(uint256 shares) external returns (uint256 requestId);

    // ============ Operator Functions ============

    /**
     * @notice Fulfill pending withdrawals from the queue (operator only)
     * @param count Maximum number of withdrawals to process
     * @return processed Number of withdrawals processed
     * @return usdcPaid Total USDC paid out
     */
    function fulfillWithdrawals(uint256 count) external returns (uint256 processed, uint256 usdcPaid);

    // ============ Owner Functions ============

    /**
     * @notice Queue a multisig address change (3-day timelock)
     * @param newMultisig New multisig address
     */
    function queueMultisig(address newMultisig) external;

    /**
     * @notice Execute a queued multisig change after timelock expires
     */
    function executeMultisig() external;

    /**
     * @notice Cancel a pending multisig change
     */
    function cancelMultisig() external;

    /**
     * @notice Queue a treasury address change (2-day timelock)
     * @param newTreasury New treasury address
     */
    function queueTreasury(address newTreasury) external;

    /**
     * @notice Execute a queued treasury change after timelock expires
     */
    function executeTreasury() external;

    /**
     * @notice Cancel a pending treasury change
     */
    function cancelTreasury() external;

    /**
     * @notice Queue a fee rate change (1-day timelock)
     * @param newFeeRate New fee rate (18 decimals)
     */
    function queueFeeRate(uint256 newFeeRate) external;

    /**
     * @notice Execute a queued fee rate change after timelock expires
     */
    function executeFeeRate() external;

    /**
     * @notice Cancel a pending fee rate change
     */
    function cancelFeeRate() external;

    /**
     * @notice Update global AUM cap
     * @param newCap New cap (0 = unlimited)
     */
    function setGlobalCap(uint256 newCap) external;

    /**
     * @notice Update withdrawal buffer
     * @param newBuffer New buffer amount
     */
    function setWithdrawalBuffer(uint256 newBuffer) external;

    /**
     * @notice Queue a cooldown period change (1-day timelock)
     * @param newCooldown New cooldown in seconds
     */
    function queueCooldown(uint256 newCooldown) external;

    /**
     * @notice Execute a queued cooldown change after timelock expires
     */
    function executeCooldown() external;

    /**
     * @notice Cancel a pending cooldown change
     */
    function cancelCooldown() external;

    /**
     * @notice Force fulfill a specific withdrawal (emergency)
     * @param requestId Request ID to process
     */
    function forceProcessWithdrawal(uint256 requestId) external;

    /**
     * @notice Cancel a queued withdrawal (emergency)
     * @param requestId Request ID to cancel
     */
    function cancelWithdrawal(uint256 requestId) external;

    /**
     * @notice Report yield and collect fees atomically
     * @param yieldDelta Change in yield (positive for gains, negative for losses)
     */
    function reportYieldAndCollectFees(int256 yieldDelta) external;

    /**
     * @notice Set maximum yield change percentage (safety bounds)
     * @param _maxPercent Maximum yield change as percentage of NAV (18 decimals)
     */
    function setMaxYieldChangePercent(uint256 _maxPercent) external;
}

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

/**
 * @title IRoleManager
 * @notice Interface for role management and pause control
 * @dev Centralizes access control for the vault ecosystem
 */
interface IRoleManager {
    // ============ Events ============

    /// @notice Emitted when an operator's status is updated
    /// @param operator Address being updated
    /// @param status True if granted operator role, false if revoked
    event OperatorUpdated(address indexed operator, bool status);
    /// @notice Emitted when all operations are paused
    /// @param by Address that triggered the pause
    event Paused(address indexed by);
    /// @notice Emitted when all operations are unpaused
    /// @param by Address that triggered the unpause
    event Unpaused(address indexed by);
    /// @notice Emitted when deposits are paused
    /// @param by Address that triggered the pause
    event DepositsPaused(address indexed by);
    /// @notice Emitted when deposits are unpaused
    /// @param by Address that triggered the unpause
    event DepositsUnpaused(address indexed by);
    /// @notice Emitted when withdrawals are paused
    /// @param by Address that triggered the pause
    event WithdrawalsPaused(address indexed by);
    /// @notice Emitted when withdrawals are unpaused
    /// @param by Address that triggered the unpause
    event WithdrawalsUnpaused(address indexed by);
    /// @notice Emitted when ownership transfer is initiated (two-step)
    /// @param previousOwner Current owner initiating transfer
    /// @param newOwner Address nominated to become new owner
    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    /// @notice Emitted when ownership transfer is completed
    /// @param previousOwner Former owner
    /// @param newOwner New owner who accepted the transfer
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    // ============ View Functions ============

    /**
     * @notice Check if the system is fully paused
     * @return True if paused
     */
    function paused() external view returns (bool);

    /**
     * @notice Check if deposits are paused
     * @return True if deposits paused
     */
    function depositsPaused() external view returns (bool);

    /**
     * @notice Check if withdrawals are paused
     * @return True if withdrawals paused
     */
    function withdrawalsPaused() external view returns (bool);

    /**
     * @notice Check if an address is an operator
     * @param account Address to check
     * @return True if operator
     */
    function isOperator(address account) external view returns (bool);

    /**
     * @notice Get the owner address
     * @return Owner address
     */
    function owner() external view returns (address);

    // ============ Operator Functions ============

    /**
     * @notice Pause all operations (operator or owner)
     */
    function pause() external;

    /**
     * @notice Pause deposits only (operator or owner)
     */
    function pauseDeposits() external;

    /**
     * @notice Pause withdrawals only (operator or owner)
     */
    function pauseWithdrawals() external;

    // ============ Owner Functions ============

    /**
     * @notice Unpause all operations (owner only)
     */
    function unpause() external;

    /**
     * @notice Unpause deposits (owner only)
     */
    function unpauseDeposits() external;

    /**
     * @notice Unpause withdrawals (owner only)
     */
    function unpauseWithdrawals() external;

    /**
     * @notice Set operator status for an address
     * @param operator Address to update
     * @param status New operator status
     */
    function setOperator(address operator, bool status) external;

    /**
     * @notice Start ownership transfer
     * @param newOwner New owner address
     */
    function transferOwnership(address newOwner) external;

    /**
     * @notice Accept ownership transfer
     */
    function acceptOwnership() external;
}

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

pragma solidity ^0.8.20;

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

/**
 * @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 EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * 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].
 *
 * IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
 * by the {ReentrancyGuardTransient} variant in v6.0.
 *
 * @custom:stateless
 */
abstract contract ReentrancyGuard {
    using StorageSlot for bytes32;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

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

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _reentrancyGuardStorageSlot().getUint256Slot().value = 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();
    }

    /**
     * @dev A `view` only version of {nonReentrant}. Use to block view functions
     * from being called, preventing reading from inconsistent contract state.
     *
     * CAUTION: This is a "view" modifier and does not change the reentrancy
     * status. Use it only on view functions. For payable or non-payable functions,
     * use the standard {nonReentrant} modifier instead.
     */
    modifier nonReentrantView() {
        _nonReentrantBeforeView();
        _;
    }

    function _nonReentrantBeforeView() private view {
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        _nonReentrantBeforeView();

        // Any calls to nonReentrant after this point will fail
        _reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _reentrancyGuardStorageSlot().getUint256Slot().value = 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 _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
    }

    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
        return REENTRANCY_GUARD_STORAGE;
    }
}

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (interfaces/draft-IERC6093.sol)

pragma solidity >=0.8.4;

/**
 * @dev Standard ERC-20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC-721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-721.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC-1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

// 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.1.0) (utils/Panic.sol)

pragma solidity ^0.8.20;

/**
 * @dev Helper library for emitting standardized panic codes.
 *
 * ```solidity
 * contract Example {
 *      using Panic for uint256;
 *
 *      // Use any of the declared internal constants
 *      function foo() { Panic.GENERIC.panic(); }
 *
 *      // Alternatively
 *      function foo() { Panic.panic(Panic.GENERIC); }
 * }
 * ```
 *
 * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
 *
 * _Available since v5.1._
 */
// slither-disable-next-line unused-state
library Panic {
    /// @dev generic / unspecified error
    uint256 internal constant GENERIC = 0x00;
    /// @dev used by the assert() builtin
    uint256 internal constant ASSERT = 0x01;
    /// @dev arithmetic underflow or overflow
    uint256 internal constant UNDER_OVERFLOW = 0x11;
    /// @dev division or modulo by zero
    uint256 internal constant DIVISION_BY_ZERO = 0x12;
    /// @dev enum conversion error
    uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
    /// @dev invalid encoding in storage
    uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
    /// @dev empty array pop
    uint256 internal constant EMPTY_ARRAY_POP = 0x31;
    /// @dev array out of bounds access
    uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
    /// @dev resource error (too large allocation or too large array)
    uint256 internal constant RESOURCE_ERROR = 0x41;
    /// @dev calling invalid internal function
    uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;

    /// @dev Reverts with a panic code. Recommended to use with
    /// the internal constants with predefined codes.
    function panic(uint256 code) internal pure {
        assembly ("memory-safe") {
            mstore(0x00, 0x4e487b71)
            mstore(0x20, code)
            revert(0x1c, 0x24)
        }
    }
}

File 14 of 18 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in a uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in a uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev A uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

File 16 of 18 : 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";

File 17 of 18 : 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";

// 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
{
  "remappings": [
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "forge-std/=lib/forge-std/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_roleManager","type":"address"},{"internalType":"address","name":"_multisig","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"uint256","name":"_feeRate","type":"uint256"},{"internalType":"uint256","name":"_cooldownPeriod","type":"uint256"},{"internalType":"string","name":"_shareName","type":"string"},{"internalType":"string","name":"_shareSymbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotTransferToVault","type":"error"},{"inputs":[],"name":"DepositsPaused","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EscrowBalanceMismatch","type":"error"},{"inputs":[],"name":"ExceedsGlobalCap","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientShares","type":"error"},{"inputs":[],"name":"InvalidCooldown","type":"error"},{"inputs":[],"name":"InvalidFeeRate","type":"error"},{"inputs":[],"name":"InvalidRequestId","type":"error"},{"inputs":[],"name":"NoPendingChange","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"OnlyOperator","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"QueueHeadRegression","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"ReportTooSoon","type":"error"},{"inputs":[],"name":"RequestAlreadyProcessed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SharesNotBurned","type":"error"},{"inputs":[],"name":"TimelockNotExpired","type":"error"},{"inputs":[],"name":"TooManyPendingRequests","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"WithdrawalsPaused","type":"error"},{"inputs":[],"name":"YieldChangeTooLarge","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cancelledCooldown","type":"uint256"}],"name":"CooldownChangeCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCooldown","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCooldown","type":"uint256"}],"name":"CooldownChangeExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCooldown","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"executionTime","type":"uint256"}],"name":"CooldownChangeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPeriod","type":"uint256"}],"name":"CooldownPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesMinted","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeShares","type":"uint256"},{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"FeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cancelledRate","type":"uint256"}],"name":"FeeRateChangeCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"FeeRateChangeExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"executionTime","type":"uint256"}],"name":"FeeRateChangeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsForwardedToMultisig","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"GlobalCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"MaxYieldChangeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cancelledMultisig","type":"address"}],"name":"MultisigChangeCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldMultisig","type":"address"},{"indexed":false,"internalType":"address","name":"newMultisig","type":"address"}],"name":"MultisigChangeExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newMultisig","type":"address"},{"indexed":false,"internalType":"uint256","name":"executionTime","type":"uint256"}],"name":"MultisigChangeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMultisig","type":"address"},{"indexed":true,"internalType":"address","name":"newMultisig","type":"address"}],"name":"MultisigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OrphanedSharesRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cancelledTreasury","type":"address"}],"name":"TreasuryChangeCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryChangeExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"},{"indexed":false,"internalType":"uint256","name":"executionTime","type":"uint256"}],"name":"TreasuryChangeQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":true,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBuffer","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBuffer","type":"uint256"}],"name":"WithdrawalBufferUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"WithdrawalCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"WithdrawalForced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"WithdrawalFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"WithdrawalRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"WithdrawalsPurged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"yieldDelta","type":"int256"},{"indexed":false,"internalType":"int256","name":"newAccumulatedYield","type":"int256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"YieldReported","type":"event"},{"inputs":[],"name":"CANCELLATION_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INITIAL_SHARE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_COOLDOWN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PENDING_PER_USER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_COOLDOWN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_YIELD_REPORT_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_COOLDOWN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_FEE_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_MULTISIG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_TREASURY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulatedYield","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"availableLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelMultisig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"cancelWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldownPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"sharesMinted","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"escrowedShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"executeCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executeFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executeMultisig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executeTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"forceProcessWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"fulfillWithdrawals","outputs":[{"internalType":"uint256","name":"processed","type":"uint256"},{"internalType":"uint256","name":"usdcPaid","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"getWithdrawalRequest","outputs":[{"components":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"requestTimestamp","type":"uint256"}],"internalType":"struct IVault.WithdrawalRequest","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastYieldReportTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxYieldChangePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multisig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingCooldownPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingCooldownTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingFeeRateTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingMultisig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingMultisigTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingTreasuryTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingWithdrawalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingWithdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"purgeProcessedWithdrawals","outputs":[{"internalType":"uint256","name":"purged","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCooldown","type":"uint256"}],"name":"queueCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"queueFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMultisig","type":"address"}],"name":"queueMultisig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"queueTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverOrphanedShares","outputs":[{"internalType":"uint256","name":"recovered","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"yieldDelta","type":"int256"}],"name":"reportYieldAndCollectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"requestWithdrawal","outputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"roleManager","outputs":[{"internalType":"contract IRoleManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"setGlobalCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPercent","type":"uint256"}],"name":"setMaxYieldChangePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newBuffer","type":"uint256"}],"name":"setWithdrawalBuffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"sharesToUsdc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWithdrawn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"usdcToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userPendingRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawalQueue","outputs":[{"internalType":"address","name":"requester","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"requestTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalQueueHead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60c06040526611c37937e08000600f553480156200001b575f80fd5b506040516200442c3803806200442c8339810160408190526200003e9162000319565b818160036200004e838262000466565b5060046200005d828262000466565b505050600162000079620000766200021860201b60201c565b90565b556001600160a01b038816620000a25760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038716620000ca5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038616620000f25760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0385166200011a5760405163d92e233d60e01b815260040160405180910390fd5b876001600160a01b03163b5f0362000145576040516309ee12d560e01b815260040160405180910390fd5b866001600160a01b03163b5f0362000170576040516309ee12d560e01b815260040160405180910390fd5b6706f05b59d3b200008411156200019a57604051630adad23360e31b815260040160405180910390fd5b62015180831080620001ae575062278d0083115b15620001cd57604051637475d84d60e11b815260040160405180910390fd5b50506001600160a01b0395861660805293851660a052600580549386166001600160a01b031994851617905560068054929095169190921617909255600791909155600a5562000532565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0090565b80516001600160a01b038116811462000253575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126200027c575f80fd5b81516001600160401b038082111562000299576200029962000258565b604051601f8301601f19908116603f01168101908282118183101715620002c457620002c462000258565b8160405283815260209250866020858801011115620002e1575f80fd5b5f91505b83821015620003045785820183015181830184015290820190620002e5565b5f602085830101528094505050505092915050565b5f805f805f805f80610100898b03121562000332575f80fd5b6200033d896200023c565b97506200034d60208a016200023c565b96506200035d60408a016200023c565b95506200036d60608a016200023c565b60808a015160a08b015160c08c015192975090955093506001600160401b038082111562000399575f80fd5b620003a78c838d016200026c565b935060e08b0151915080821115620003bd575f80fd5b50620003cc8b828c016200026c565b9150509295985092959890939650565b600181811c90821680620003f157607f821691505b6020821081036200041057634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200046157805f5260205f20601f840160051c810160208510156200043d5750805b601f840160051c820191505b818110156200045e575f815560010162000449565b50505b505050565b81516001600160401b0381111562000482576200048262000258565b6200049a81620004938454620003dc565b8462000416565b602080601f831160018114620004d0575f8415620004b85750858301515b5f19600386901b1c1916600185901b1785556200052a565b5f85815260208120601f198616915b828110156200050057888601518255948401946001909101908401620004df565b50858210156200051e57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b60805160a051613de3620006495f395f818161046c01528181610a2b01528181610bae01528181610d2a01528181610ead0152818161107f015281816111bf015281816112ec0152818161139b0152818161172e015281816117be0152818161185c01528181611c3d01528181611d4f01528181611eaf01528181611f5e01528181612074015281816121cf0152818161226d01528181612505015281816125b40152818161280c0152818161293401528181612b0a01528181612ba801528181612d8101528181612ee10152818161300f0152818161312c015261327101525f81816105960152818161154401528181611a2301528181611bca01528181612cfd0152818161360c01526136ac0152613de35ff3fe608060405234801561000f575f80fd5b5060043610610463575f3560e01c80638f1d4a7b1161024d578063beca03d511610140578063db007793116100bf578063f714cb4411610084578063f714cb44146106b1578063f8c3bf741461091c578063fca4a5281461092f578063fcdfd5c514610938578063ff50abdc14610941575f80fd5b8063db007793146108b6578063dd62ed3e146108bf578063dec5db62146108f7578063e6ef6a10146108ff578063e7ab124714610912575f80fd5b8063c9edbe5411610105578063c9edbe541461089b578063ca2b06df146106b1578063cd975bf3146106b1578063d8bc5248146108a5578063d9e2bc89146108ae575f80fd5b8063beca03d514610836578063c0c639cd1461083e578063c36f9e9414610847578063c6b05a8e1461085a578063c822adda14610863575f80fd5b8063a1626fb5116101cc578063acf0044b11610191578063acf0044b146107b5578063ae485651146107d4578063b2ece25a14610812578063b6b55f251461081b578063bb2a46d91461082e575f80fd5b8063a1626fb51461075a578063a70afa211461076d578063a71f6f5f14610780578063a9059cbb14610793578063aaf5eb68146107a6575f80fd5b806395d89b411161021257806395d89b411461071a578063978bbdb91461072257806399a2af751461072b5780639ee679e8146107345780639fe430b114610747575f80fd5b80638f1d4a7b146106e857806392a57fca146106f157806392f6576e146106fa57806393bcd8581461070957806394ce88b014610711575f80fd5b80634479d97b1161036557806361d027b3116102e457806377fc89d9116102a957806377fc89d9146106b15780637cae59ce146106bb5780637dbe20bf146106c357806387269729146106d65780638b41d35f146106de575f80fd5b806361d027b314610673578063704743ee1461068657806370a082311461068e57806374375359146106a15780637674e44e146106a9575f80fd5b80634d19e5ce1161032a5780634d19e5ce146106155780634fd72c5a1461061d5780635a4eacfa146106305780635eff4fb614610638578063606225d01461064b575f80fd5b80634479d97b146105d35780634675c3ce146105dd5780634783c35b146105f05780634a27cc16146106035780634b3197131461060c575f80fd5b8063235a9058116103f15780633a98ef39116103b65780633a98ef39146105815780633c4da553146105895780633e413bee146105915780633efcfda4146105b857806342e1a6a2146105cb575f80fd5b8063235a90581461053a57806323b872dd146105435780632c31ab9a146105565780632ed6b75d1461055f578063313ce56714610572575f80fd5b8063095ea7b311610437578063095ea7b3146104df5780630d04e7cc146105025780630e9921651461050c57806318160ddd1461051f5780631e00d17c14610527575f80fd5b8062435da51461046757806301e1d114146104ab57806304646a49146104c157806306fdde03146104ca575b5f80fd5b61048e7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6104b361094a565b6040519081526020016104a2565b6104b3600a5481565b6104d2610980565b6040516104a29190613aa7565b6104f26104ed366004613b07565b610a10565b60405190151581526020016104a2565b61050a610a29565b005b6104b361051a366004613b31565b610b77565b6002546104b3565b61050a610535366004613b31565b610bac565b6104b360155481565b6104f2610551366004613b48565b610cdc565b6104b3600f5481565b60165461048e906001600160a01b031681565b604051601281526020016104a2565b6104b3610d19565b61050a610d28565b61048e7f000000000000000000000000000000000000000000000000000000000000000081565b61050a6105c6366004613b31565b610e3a565b61050a61107d565b6104b36203f48081565b6104b36105eb366004613b31565b6111a2565b60055461048e906001600160a01b031681565b6104b360095481565b6104b3600c5481565b61050a6111bd565b61050a61062b366004613b31565b6112e2565b6010546104b3565b6104b3610646366004613b31565b611600565b61065e610659366004613b31565b61170f565b604080519283526020830191909152016104a2565b60065461048e906001600160a01b031681565b6104b3611b93565b6104b361069c366004613b86565b611b99565b6104b3611bb3565b61050a611c3b565b6104b36201518081565b61050a611d4d565b61050a6106d1366004613b31565b611ead565b6104b361202f565b6104b362278d0081565b6104b3601a5481565b6104b3610e1081565b6104b36706f05b59d3b2000081565b61050a612072565b6104b360115481565b6104d26121b5565b6104b360075481565b6104b360085481565b6104b3610742366004613b31565b6121c4565b61050a610755366004613b31565b612503565b60185461048e906001600160a01b031681565b61050a61077b366004613b31565b61280a565b61050a61078e366004613b31565b612932565b6104f26107a1366004613b07565b612a24565b6104b3670de0b6b3a764000081565b6104b36107c3366004613b86565b60136020525f908152604090205481565b6107e76107e2366004613b31565b612a58565b6040805182516001600160a01b031681526020808401519082015291810151908201526060016104a2565b6104b360145481565b6104b3610829366004613b31565b612aff565b61050a612d7f565b6012546104b3565b6104b360195481565b61050a610855366004613b31565b612edf565b6104b3600e5481565b610876610871366004613b31565b612fd1565b604080516001600160a01b0390941684526020840192909252908201526060016104a2565b6104b36202a30081565b6104b360125481565b6104b361300c565b6104b3601b5481565b6104b36108cd366004613ba1565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6104b3600a81565b61050a61090d366004613b86565b61312a565b6104b3620f424081565b61050a61092a366004613b86565b61326f565b6104b360175481565b6104b3600d5481565b6104b3600b5481565b5f80600d54600c54600b5461095f9190613bec565b6109699190613c12565b90505f8113610978575f61097a565b805b91505090565b60606003805461098f90613c39565b80601f01602080910402602001604051908101604052809291908181526020018280546109bb90613c39565b8015610a065780601f106109dd57610100808354040283529160200191610a06565b820191905f5260205f20905b8154815290600101906020018083116109e957829003601f168201915b5050505050905090565b5f33610a1d8185856133b4565b60019150505b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a85573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa99190613c71565b6001600160a01b0316336001600160a01b031614610ada57604051635fc483c560e01b815260040160405180910390fd5b6015545f03610afc5760405163147fde5f60e31b815260040160405180910390fd5b601554421015610b1f5760405163621e25c360e01b815260040160405180910390fd5b6007805460148054928390555f9081905560155560405190917ff72f04fc9409cd022500502ca5432e863ca1639c0c45c93e088b7f2c7739014991610b6c91848252602082015260400190565b60405180910390a150565b5f80610b8161202f565b9050805f03610b9257505f92915050565b610ba583670de0b6b3a7640000836133c1565b9392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c2c9190613c71565b6001600160a01b0316336001600160a01b031614610c5d57604051635fc483c560e01b815260040160405180910390fd5b62015180811080610c70575062278d0081115b15610c8e57604051637475d84d60e11b815260040160405180910390fd5b601a819055610ca06201518042613c8c565b601b8190556040805183815260208101929092527fee33372736c25189da85e528ea12a40da0ffbd8e44b0ad50b9c6ad4253a574b89101610b6c565b5f306001600160a01b03841603610d0657604051639dba6a7560e01b815260040160405180910390fd5b610d11848484613471565b949350505050565b5f610d2360025490565b905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d84573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610da89190613c71565b6001600160a01b0316336001600160a01b031614610dd957604051635fc483c560e01b815260040160405180910390fd5b6015545f03610dfb5760405163147fde5f60e31b815260040160405180910390fd5b601480545f918290556015919091556040518181527f2f63fface0c217bc5e86e7f6a6678b072541ab88b7c0d0461330cb46dc7ebfd990602001610b6c565b610e42613494565b6010548110610e64576040516302e8145360e61b815260040160405180910390fd5b5f60108281548110610e7857610e78613c9f565b905f5260205f209060030201905080600101545f03610eaa576040516329af1d3160e21b815260040160405180910390fd5b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f07573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f2b9190613c71565b8254336001600160a01b03928316811493505f9291909116148015610f605750610e108360020154610f5d9190613c8c565b42105b905081158015610f6e575080155b15610f8b576040516282b42960e81b815260040160405180910390fd5b60018301548354601280546001600160a01b03909216918391905f90610fb2908490613cb3565b90915550506001600160a01b0381165f908152601360205260408120805491610fda83613cc6565b90915550505f6001860155610ff03082846134af565b601254610ffc30611b99565b101561101b5760405163a96cafcf60e01b815260040160405180910390fd5b60408051838152602081018890526001600160a01b038316917f609802616efe88a6b73a266ced98c5dfd07c25e64549e620527605107ea30e81910160405180910390a2505050505061107a60015f80516020613d8e83398151915255565b50565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fd9190613c71565b6001600160a01b0316336001600160a01b03161461112e57604051635fc483c560e01b815260040160405180910390fd5b6019545f036111505760405163147fde5f60e31b815260040160405180910390fd5b601880546001600160a01b031981169091555f6019556040516001600160a01b03909116808252907fda5afaff97c9faa24797017603a9dc4e94ce84e634318f89fbd7f1e4c5e06b1090602001610b6c565b5f610a23826111af61202f565b670de0b6b3a76400006133c1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611219573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123d9190613c71565b6001600160a01b0316336001600160a01b03161461126e57604051635fc483c560e01b815260040160405180910390fd5b6017545f036112905760405163147fde5f60e31b815260040160405180910390fd5b601680546001600160a01b031981169091555f6017556040516001600160a01b03909116808252907f126edc9f10a40adff641028274713504fd84689745c30ee6ce1a196cc5259bc190602001610b6c565b6112ea613494565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611346573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136a9190613c71565b6001600160a01b0316336001600160a01b03161415801561140e57506040516336b87bd760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636d70f7ae90602401602060405180830381865afa1580156113e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061140c9190613cdb565b155b1561142b576040516282b42960e81b815260040160405180910390fd5b601054811061144d576040516302e8145360e61b815260040160405180910390fd5b5f6010828154811061146157611461613c9f565b905f5260205f209060030201905080600101545f03611493576040516329af1d3160e21b815260040160405180910390fd5b60018101545f6114a2826111a2565b90506114ac611bb3565b8111156114cc5760405163bb55fd2760e01b815260040160405180910390fd5b6114d63083613511565b8160125f8282546114e79190613cb3565b909155505082546001600160a01b03165f90815260136020526040812080549161151083613cc6565b91905055505f836001018190555080600c5f82825461152f9190613c8c565b9091555050825461156d906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613549565b60125461157930611b99565b10156115985760405163a96cafcf60e01b815260040160405180910390fd5b825460408051848152602081018490529081018690526001600160a01b03909116907f52116ae7b80e5a7bb0e54313880222bf045ab870f1ad862ff7b14b880227e0749060600160405180910390a250505061107a60015f80516020613d8e83398151915255565b6011545f90818184106116135781611615565b835b90505f6116228284613cb3565b90505b828110801561163357508484105b156116cd575f6001600160a01b03166010828154811061165557611655613c9f565b5f9182526020909120600390910201546001600160a01b0316146116bb576010818154811061168657611686613c9f565b5f9182526020822060039091020180546001600160a01b03191681556001810182905560020155836116b781613cfa565b9450505b806116c581613cfa565b915050611625565b508215611708576040518381527f3a263c878c42a4c5bb7061c3f733d72c3fab05ac016e0c29744864f768fba29b9060200160405180910390a15b5050919050565b5f80611719613494565b6040516336b87bd760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636d70f7ae90602401602060405180830381865afa15801561177b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061179f9190613cdb565b6117bc576040516327e1f1e560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611818573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061183c9190613cdb565b1561185a576040516313d0ff5960e31b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e9f2838e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118da9190613cdb565b156118f857604051636022a9e760e01b815260040160405180910390fd5b5f611901611bb3565b601154601054919250905f61191560025490565b90505b868610801561192657508183105b15611ae0575f6010848154811061193f5761193f613c9f565b905f5260205f209060030201905080600101545f0361196b578361196281613cfa565b94505050611918565b600a54816002015461197d9190613c8c565b42101561198a5750611ae0565b60018101545f611999826111a2565b9050868111156119ab57505050611ae0565b6119b53083613511565b8160125f8282546119c69190613cb3565b909155505082546001600160a01b03165f9081526013602052604081208054916119ef83613cc6565b91905055505f836001018190555080600c5f828254611a0e9190613c8c565b90915550508254611a4c906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613549565b611a568188613cb3565b9650611a628189613c8c565b975088611a6e81613cfa565b9950508580611a7c90613cfa565b84549097506001600160a01b031690507f567289124f980c60ab6be9d631895db98cf8d567e8ef80f55d8be6474ad2d0a68383611aba60018b613cb3565b6040805193845260208401929092529082015260600160405180910390a2505050611918565b601154831015611b035760405163179204d960e21b815260040160405180910390fd5b60118390558515611b49575f611b1860025490565b9050818110158015611b2957505f86115b15611b475760405163ef08ba6f60e01b815260040160405180910390fd5b505b601254611b5530611b99565b1015611b745760405163a96cafcf60e01b815260040160405180910390fd5b50505050611b8e60015f80516020613d8e83398151915255565b915091565b5f610d23305b6001600160a01b03165f9081526020819052604090205490565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611c17573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d239190613d12565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cbb9190613c71565b6001600160a01b0316336001600160a01b031614611cec57604051635fc483c560e01b815260040160405180910390fd5b601b545f03611d0e5760405163147fde5f60e31b815260040160405180910390fd5b601a80545f91829055601b919091556040518181527f274eb4b4d7e9d2cc6bbe84034d73372024a36e9dc602a19a9fa861d73093946a90602001610b6c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611da9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dcd9190613c71565b6001600160a01b0316336001600160a01b031614611dfe57604051635fc483c560e01b815260040160405180910390fd5b6019545f03611e205760405163147fde5f60e31b815260040160405180910390fd5b601954421015611e435760405163621e25c360e01b815260040160405180910390fd5b60058054601880546001600160a01b038082166001600160a01b03198086168217909655949091169091555f601955604080519190921680825260208201939093527f884b533c458a616d544d78d1ba29d108f2928ac4d80b9644e2678544fc79c9ef9101610b6c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f09573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2d9190613c71565b6001600160a01b0316336001600160a01b031614158015611fd157506040516336b87bd760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636d70f7ae90602401602060405180830381865afa158015611fab573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fcf9190613cdb565b155b15611fee576040516282b42960e81b815260040160405180910390fd5b60095460408051918252602082018390527f15afce63833e6bc6e7a8cdd982aede09fc7da372fc07601c6587b2beb8dfaf88910160405180910390a1600955565b5f8061203a60025490565b9050805f0361204d57620f424091505090565b5f61205661094a565b905061206b81670de0b6b3a7640000846133c1565b9250505090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120f29190613c71565b6001600160a01b0316336001600160a01b03161461212357604051635fc483c560e01b815260040160405180910390fd5b601b545f036121455760405163147fde5f60e31b815260040160405180910390fd5b601b544210156121685760405163621e25c360e01b815260040160405180910390fd5b600a8054601a8054928390555f90819055601b5560405190917f8302dc0780ea08ed5fc2063db00696bd339b8c94525c278216fa79045e2d4f5a91610b6c91848252602082015260400190565b60606004805461098f90613c39565b5f6121cd613494565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612229573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061224d9190613cdb565b1561226b576040516313d0ff5960e31b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e9f2838e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122eb9190613cdb565b1561230957604051636022a9e760e01b815260040160405180910390fd5b815f0361232957604051631f2a200560e01b815260040160405180910390fd5b8161233333611b99565b101561235257604051633999656760e01b815260040160405180910390fd5b335f90815260136020526040902054600a1161238157604051638bf0a57960e01b815260040160405180910390fd5b61238c3330846134af565b50601080546040805160608101825233815260208101858152429282019283526001840185555f94855290517f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6726003850290810180546001600160a01b0319166001600160a01b039093169290921790915590517f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae67382015590517f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae67490910155601280549192849261245e908490613c8c565b9091555050335f90815260136020526040812080549161247d83613cfa565b919050555060125461248e30611b99565b10156124ad5760405163a96cafcf60e01b815260040160405180910390fd5b604080518381526020810183905233917f24b91f4f47caf44230a57777a9be744924e82bf666f2d5702faf97df35e60f9f910160405180910390a26124fe60015f80516020613d8e83398151915255565b919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561255f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125839190613c71565b6001600160a01b0316336001600160a01b03161415801561262757506040516336b87bd760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636d70f7ae90602401602060405180830381865afa158015612601573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126259190613cdb565b155b15612644576040516282b42960e81b815260040160405180910390fd5b5f600e54118015612664575062015180600e546126619190613c8c565b42105b15612682576040516319f6f4d960e21b815260040160405180910390fd5b600f5415612700575f61269361094a565b905080156126fe575f808312156126b2576126ad83613d29565b6126b4565b825b90505f670de0b6b3a7640000600f54846126ce9190613d43565b6126d89190613d6e565b9050808211156126fb576040516365012ae960e01b815260040160405180910390fd5b50505b505b80600d5f8282546127119190613c12565b909155505042600e819055600d546040805184815260208101929092528101919091527f0477f1367664ed3cdd6a829e889b321efcc865439db8ef0975ef3fa5e684d8579060600160405180910390a15f8113801561277157505f600754115b1561107a575f8190505f61279082600754670de0b6b3a76400006133c1565b90508015612805575f6127a282610b77565b90508015612803576006546127c0906001600160a01b03168261357e565b6006546040518281526001600160a01b03909116907ff10cda68996dfb656d49ab0db3c62cc5f0849710633671a337171c3ad92551869060200160405180910390a25b505b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612866573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288a9190613c71565b6001600160a01b0316336001600160a01b0316146128bb57604051635fc483c560e01b815260040160405180910390fd5b6706f05b59d3b200008111156128e457604051630adad23360e31b815260040160405180910390fd5b60148190556128f66201518042613c8c565b60158190556040805183815260208101929092527f353b3642b8afdf028473744ee9a601be2fceeb9622fad485f4005fb78dc3b7bf9101610b6c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561298e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129b29190613c71565b6001600160a01b0316336001600160a01b0316146129e357604051635fc483c560e01b815260040160405180910390fd5b60085460408051918252602082018390527fd1c624d58866d65b5a86de09e962c4fea0fa806c6d868cc2281397aa3524e16f910160405180910390a1600855565b5f306001600160a01b03841603612a4e57604051639dba6a7560e01b815260040160405180910390fd5b610ba583836135b2565b612a8260405180606001604052805f6001600160a01b031681526020015f81526020015f81525090565b6010548210612aa4576040516302e8145360e61b815260040160405180910390fd5b60108281548110612ab757612ab7613c9f565b5f91825260209182902060408051606081018252600390930290910180546001600160a01b031683526001810154938301939093526002909201549181019190915292915050565b5f612b08613494565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b889190613cdb565b15612ba6576040516313d0ff5960e31b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166360da3e836040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c02573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c269190613cdb565b15612c445760405163deeb694360e01b815260040160405180910390fd5b815f03612c6457604051631f2a200560e01b815260040160405180910390fd5b5f612c6d61094a565b60085490915015612ca457600854612c858483613c8c565b1115612ca4576040516373ae684760e01b815260040160405180910390fd5b612cad83610b77565b9150815f03612ccf57604051639811e0c760e01b815260040160405180910390fd5b82600b5f828254612ce09190613c8c565b90915550612cf09050338361357e565b612d256001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163330866135bf565b612d2d6135f5565b604080518481526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a2506124fe60015f80516020613d8e83398151915255565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ddb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612dff9190613c71565b6001600160a01b0316336001600160a01b031614612e3057604051635fc483c560e01b815260040160405180910390fd5b6017545f03612e525760405163147fde5f60e31b815260040160405180910390fd5b601754421015612e755760405163621e25c360e01b815260040160405180910390fd5b60068054601680546001600160a01b038082166001600160a01b03198086168217909655949091169091555f601755604080519190921680825260208201939093527fa6ae278281297c6c7bca891c70bcccd72d64c19819f00fa898896bc26bb53d2f9101610b6c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5f9190613c71565b6001600160a01b0316336001600160a01b031614612f9057604051635fc483c560e01b815260040160405180910390fd5b600f5460408051918252602082018390527f0b4aa6ab0a4ee9989cc22f2d1a48033543ee0155d920ddf026a93629342432f7910160405180910390a1600f55565b60108181548110612fe0575f80fd5b5f9182526020909120600390910201805460018201546002909201546001600160a01b03909116925083565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613069573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061308d9190613c71565b6001600160a01b0316336001600160a01b0316146130be57604051635fc483c560e01b815260040160405180910390fd5b5f6130c830611b99565b905060125481116130da575f91505090565b6012546130e79082613cb3565b91506130f33083613511565b6040518281527f4adff76c597b12657368e4fa4d34091975c4165dec971b9951563bcb8fb4ac5a9060200160405180910390a15090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613186573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131aa9190613c71565b6001600160a01b0316336001600160a01b0316146131db57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166132025760405163d92e233d60e01b815260040160405180910390fd5b601680546001600160a01b0319166001600160a01b03831617905561322a6202a30042613c8c565b6017819055604080516001600160a01b038416815260208101929092527f982aac784cef4158ccb29de8199a3fd790f0c4c9228f192cd980360c200ea13d9101610b6c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132ef9190613c71565b6001600160a01b0316336001600160a01b03161461332057604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166133475760405163d92e233d60e01b815260040160405180910390fd5b601880546001600160a01b0319166001600160a01b03831617905561336f6203f48042613c8c565b6019819055604080516001600160a01b038416815260208101929092527f5d2d20215fdd0243b3174d686a58b24d814ec266ab3c26f2ab39b52404d8c7569101610b6c565b612805838383600161370c565b5f805f6133ce86866137de565b91509150815f036133f2578381816133e8576133e8613d5a565b0492505050610ba5565b8184116134095761340960038515026011186137fa565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010185841190960395909502919093039390930492909217029150509392505050565b5f3361347e85828561380b565b6134898585856134af565b506001949350505050565b61349c613881565b60025f80516020613d8e83398151915255565b6001600160a01b0383166134dd57604051634b637e8f60e11b81525f60048201526024015b60405180910390fd5b6001600160a01b0382166135065760405163ec442f0560e01b81525f60048201526024016134d4565b6128058383836138b2565b6001600160a01b03821661353a57604051634b637e8f60e11b81525f60048201526024016134d4565b613545825f836138b2565b5050565b61355683838360016139d8565b61280557604051635274afe760e01b81526001600160a01b03841660048201526024016134d4565b6001600160a01b0382166135a75760405163ec442f0560e01b81525f60048201526024016134d4565b6135455f83836138b2565b5f33610a1d8185856134af565b6135cd848484846001613a3a565b61280357604051635274afe760e01b81526001600160a01b03851660048201526024016134d4565b6040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613659573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061367d9190613d12565b905060095481111561107a575f600954826136989190613cb3565b6005549091506136d5906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911683613549565b6040518181527fc186a4ce19f2dc43bb888f6f906d3ca91f090f5ae3394135296bb2cb16bd8f459060200160405180910390a15050565b6001600160a01b0384166137355760405163e602df0560e01b81525f60048201526024016134d4565b6001600160a01b03831661375e57604051634a1406b160e11b81525f60048201526024016134d4565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561280357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516137d091815260200190565b60405180910390a350505050565b5f805f1983850993909202808410938190039390930393915050565b634e487b715f52806020526024601cfd5b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f19811015612803578181101561387357604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016134d4565b61280384848484035f61370c565b5f80516020613d8e833981519152546002036138b057604051633ee5aeb560e01b815260040160405180910390fd5b565b6001600160a01b0383166138dc578060025f8282546138d19190613c8c565b9091555061394c9050565b6001600160a01b0383165f908152602081905260409020548181101561392e5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016134d4565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661396857600280548290039055613986565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516139cb91815260200190565b60405180910390a3505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316613a2e578383151615613a22573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f51148316613a96578383151615613a8a573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f602080835283518060208501525f5b81811015613ad357858101830151858201604001528201613ab7565b505f604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b038116811461107a575f80fd5b5f8060408385031215613b18575f80fd5b8235613b2381613af3565b946020939093013593505050565b5f60208284031215613b41575f80fd5b5035919050565b5f805f60608486031215613b5a575f80fd5b8335613b6581613af3565b92506020840135613b7581613af3565b929592945050506040919091013590565b5f60208284031215613b96575f80fd5b8135610ba581613af3565b5f8060408385031215613bb2575f80fd5b8235613bbd81613af3565b91506020830135613bcd81613af3565b809150509250929050565b634e487b7160e01b5f52601160045260245ffd5b8181035f831280158383131683831282161715613c0b57613c0b613bd8565b5092915050565b8082018281125f831280158216821582161715613c3157613c31613bd8565b505092915050565b600181811c90821680613c4d57607f821691505b602082108103613c6b57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215613c81575f80fd5b8151610ba581613af3565b80820180821115610a2357610a23613bd8565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610a2357610a23613bd8565b5f81613cd457613cd4613bd8565b505f190190565b5f60208284031215613ceb575f80fd5b81518015158114610ba5575f80fd5b5f60018201613d0b57613d0b613bd8565b5060010190565b5f60208284031215613d22575f80fd5b5051919050565b5f600160ff1b8201613d3d57613d3d613bd8565b505f0390565b8082028115828204841417610a2357610a23613bd8565b634e487b7160e01b5f52601260045260245ffd5b5f82613d8857634e487b7160e01b5f52601260045260245ffd5b50049056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212206ed5e07b9acecc366e1acd12227d4750e4631a09e1f610c4c15c57f7dc71118e64736f6c63430008180033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d0000000000000000000000000fbce7f3678467f7f7313fcb2c9d1603431ad6660000000000000000000000000fbce7f3678467f7f7313fcb2c9d1603431ad66600000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000074c617a795553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076c617a7955534400000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561000f575f80fd5b5060043610610463575f3560e01c80638f1d4a7b1161024d578063beca03d511610140578063db007793116100bf578063f714cb4411610084578063f714cb44146106b1578063f8c3bf741461091c578063fca4a5281461092f578063fcdfd5c514610938578063ff50abdc14610941575f80fd5b8063db007793146108b6578063dd62ed3e146108bf578063dec5db62146108f7578063e6ef6a10146108ff578063e7ab124714610912575f80fd5b8063c9edbe5411610105578063c9edbe541461089b578063ca2b06df146106b1578063cd975bf3146106b1578063d8bc5248146108a5578063d9e2bc89146108ae575f80fd5b8063beca03d514610836578063c0c639cd1461083e578063c36f9e9414610847578063c6b05a8e1461085a578063c822adda14610863575f80fd5b8063a1626fb5116101cc578063acf0044b11610191578063acf0044b146107b5578063ae485651146107d4578063b2ece25a14610812578063b6b55f251461081b578063bb2a46d91461082e575f80fd5b8063a1626fb51461075a578063a70afa211461076d578063a71f6f5f14610780578063a9059cbb14610793578063aaf5eb68146107a6575f80fd5b806395d89b411161021257806395d89b411461071a578063978bbdb91461072257806399a2af751461072b5780639ee679e8146107345780639fe430b114610747575f80fd5b80638f1d4a7b146106e857806392a57fca146106f157806392f6576e146106fa57806393bcd8581461070957806394ce88b014610711575f80fd5b80634479d97b1161036557806361d027b3116102e457806377fc89d9116102a957806377fc89d9146106b15780637cae59ce146106bb5780637dbe20bf146106c357806387269729146106d65780638b41d35f146106de575f80fd5b806361d027b314610673578063704743ee1461068657806370a082311461068e57806374375359146106a15780637674e44e146106a9575f80fd5b80634d19e5ce1161032a5780634d19e5ce146106155780634fd72c5a1461061d5780635a4eacfa146106305780635eff4fb614610638578063606225d01461064b575f80fd5b80634479d97b146105d35780634675c3ce146105dd5780634783c35b146105f05780634a27cc16146106035780634b3197131461060c575f80fd5b8063235a9058116103f15780633a98ef39116103b65780633a98ef39146105815780633c4da553146105895780633e413bee146105915780633efcfda4146105b857806342e1a6a2146105cb575f80fd5b8063235a90581461053a57806323b872dd146105435780632c31ab9a146105565780632ed6b75d1461055f578063313ce56714610572575f80fd5b8063095ea7b311610437578063095ea7b3146104df5780630d04e7cc146105025780630e9921651461050c57806318160ddd1461051f5780631e00d17c14610527575f80fd5b8062435da51461046757806301e1d114146104ab57806304646a49146104c157806306fdde03146104ca575b5f80fd5b61048e7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d81565b6040516001600160a01b0390911681526020015b60405180910390f35b6104b361094a565b6040519081526020016104a2565b6104b3600a5481565b6104d2610980565b6040516104a29190613aa7565b6104f26104ed366004613b07565b610a10565b60405190151581526020016104a2565b61050a610a29565b005b6104b361051a366004613b31565b610b77565b6002546104b3565b61050a610535366004613b31565b610bac565b6104b360155481565b6104f2610551366004613b48565b610cdc565b6104b3600f5481565b60165461048e906001600160a01b031681565b604051601281526020016104a2565b6104b3610d19565b61050a610d28565b61048e7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b61050a6105c6366004613b31565b610e3a565b61050a61107d565b6104b36203f48081565b6104b36105eb366004613b31565b6111a2565b60055461048e906001600160a01b031681565b6104b360095481565b6104b3600c5481565b61050a6111bd565b61050a61062b366004613b31565b6112e2565b6010546104b3565b6104b3610646366004613b31565b611600565b61065e610659366004613b31565b61170f565b604080519283526020830191909152016104a2565b60065461048e906001600160a01b031681565b6104b3611b93565b6104b361069c366004613b86565b611b99565b6104b3611bb3565b61050a611c3b565b6104b36201518081565b61050a611d4d565b61050a6106d1366004613b31565b611ead565b6104b361202f565b6104b362278d0081565b6104b3601a5481565b6104b3610e1081565b6104b36706f05b59d3b2000081565b61050a612072565b6104b360115481565b6104d26121b5565b6104b360075481565b6104b360085481565b6104b3610742366004613b31565b6121c4565b61050a610755366004613b31565b612503565b60185461048e906001600160a01b031681565b61050a61077b366004613b31565b61280a565b61050a61078e366004613b31565b612932565b6104f26107a1366004613b07565b612a24565b6104b3670de0b6b3a764000081565b6104b36107c3366004613b86565b60136020525f908152604090205481565b6107e76107e2366004613b31565b612a58565b6040805182516001600160a01b031681526020808401519082015291810151908201526060016104a2565b6104b360145481565b6104b3610829366004613b31565b612aff565b61050a612d7f565b6012546104b3565b6104b360195481565b61050a610855366004613b31565b612edf565b6104b3600e5481565b610876610871366004613b31565b612fd1565b604080516001600160a01b0390941684526020840192909252908201526060016104a2565b6104b36202a30081565b6104b360125481565b6104b361300c565b6104b3601b5481565b6104b36108cd366004613ba1565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b6104b3600a81565b61050a61090d366004613b86565b61312a565b6104b3620f424081565b61050a61092a366004613b86565b61326f565b6104b360175481565b6104b3600d5481565b6104b3600b5481565b5f80600d54600c54600b5461095f9190613bec565b6109699190613c12565b90505f8113610978575f61097a565b805b91505090565b60606003805461098f90613c39565b80601f01602080910402602001604051908101604052809291908181526020018280546109bb90613c39565b8015610a065780601f106109dd57610100808354040283529160200191610a06565b820191905f5260205f20905b8154815290600101906020018083116109e957829003601f168201915b5050505050905090565b5f33610a1d8185856133b4565b60019150505b92915050565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a85573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa99190613c71565b6001600160a01b0316336001600160a01b031614610ada57604051635fc483c560e01b815260040160405180910390fd5b6015545f03610afc5760405163147fde5f60e31b815260040160405180910390fd5b601554421015610b1f5760405163621e25c360e01b815260040160405180910390fd5b6007805460148054928390555f9081905560155560405190917ff72f04fc9409cd022500502ca5432e863ca1639c0c45c93e088b7f2c7739014991610b6c91848252602082015260400190565b60405180910390a150565b5f80610b8161202f565b9050805f03610b9257505f92915050565b610ba583670de0b6b3a7640000836133c1565b9392505050565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c08573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c2c9190613c71565b6001600160a01b0316336001600160a01b031614610c5d57604051635fc483c560e01b815260040160405180910390fd5b62015180811080610c70575062278d0081115b15610c8e57604051637475d84d60e11b815260040160405180910390fd5b601a819055610ca06201518042613c8c565b601b8190556040805183815260208101929092527fee33372736c25189da85e528ea12a40da0ffbd8e44b0ad50b9c6ad4253a574b89101610b6c565b5f306001600160a01b03841603610d0657604051639dba6a7560e01b815260040160405180910390fd5b610d11848484613471565b949350505050565b5f610d2360025490565b905090565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d84573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610da89190613c71565b6001600160a01b0316336001600160a01b031614610dd957604051635fc483c560e01b815260040160405180910390fd5b6015545f03610dfb5760405163147fde5f60e31b815260040160405180910390fd5b601480545f918290556015919091556040518181527f2f63fface0c217bc5e86e7f6a6678b072541ab88b7c0d0461330cb46dc7ebfd990602001610b6c565b610e42613494565b6010548110610e64576040516302e8145360e61b815260040160405180910390fd5b5f60108281548110610e7857610e78613c9f565b905f5260205f209060030201905080600101545f03610eaa576040516329af1d3160e21b815260040160405180910390fd5b5f7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f07573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f2b9190613c71565b8254336001600160a01b03928316811493505f9291909116148015610f605750610e108360020154610f5d9190613c8c565b42105b905081158015610f6e575080155b15610f8b576040516282b42960e81b815260040160405180910390fd5b60018301548354601280546001600160a01b03909216918391905f90610fb2908490613cb3565b90915550506001600160a01b0381165f908152601360205260408120805491610fda83613cc6565b90915550505f6001860155610ff03082846134af565b601254610ffc30611b99565b101561101b5760405163a96cafcf60e01b815260040160405180910390fd5b60408051838152602081018890526001600160a01b038316917f609802616efe88a6b73a266ced98c5dfd07c25e64549e620527605107ea30e81910160405180910390a2505050505061107a60015f80516020613d8e83398151915255565b50565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110fd9190613c71565b6001600160a01b0316336001600160a01b03161461112e57604051635fc483c560e01b815260040160405180910390fd5b6019545f036111505760405163147fde5f60e31b815260040160405180910390fd5b601880546001600160a01b031981169091555f6019556040516001600160a01b03909116808252907fda5afaff97c9faa24797017603a9dc4e94ce84e634318f89fbd7f1e4c5e06b1090602001610b6c565b5f610a23826111af61202f565b670de0b6b3a76400006133c1565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611219573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061123d9190613c71565b6001600160a01b0316336001600160a01b03161461126e57604051635fc483c560e01b815260040160405180910390fd5b6017545f036112905760405163147fde5f60e31b815260040160405180910390fd5b601680546001600160a01b031981169091555f6017556040516001600160a01b03909116808252907f126edc9f10a40adff641028274713504fd84689745c30ee6ce1a196cc5259bc190602001610b6c565b6112ea613494565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611346573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136a9190613c71565b6001600160a01b0316336001600160a01b03161415801561140e57506040516336b87bd760e11b81523360048201527f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b031690636d70f7ae90602401602060405180830381865afa1580156113e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061140c9190613cdb565b155b1561142b576040516282b42960e81b815260040160405180910390fd5b601054811061144d576040516302e8145360e61b815260040160405180910390fd5b5f6010828154811061146157611461613c9f565b905f5260205f209060030201905080600101545f03611493576040516329af1d3160e21b815260040160405180910390fd5b60018101545f6114a2826111a2565b90506114ac611bb3565b8111156114cc5760405163bb55fd2760e01b815260040160405180910390fd5b6114d63083613511565b8160125f8282546114e79190613cb3565b909155505082546001600160a01b03165f90815260136020526040812080549161151083613cc6565b91905055505f836001018190555080600c5f82825461152f9190613c8c565b9091555050825461156d906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488116911683613549565b60125461157930611b99565b10156115985760405163a96cafcf60e01b815260040160405180910390fd5b825460408051848152602081018490529081018690526001600160a01b03909116907f52116ae7b80e5a7bb0e54313880222bf045ab870f1ad862ff7b14b880227e0749060600160405180910390a250505061107a60015f80516020613d8e83398151915255565b6011545f90818184106116135781611615565b835b90505f6116228284613cb3565b90505b828110801561163357508484105b156116cd575f6001600160a01b03166010828154811061165557611655613c9f565b5f9182526020909120600390910201546001600160a01b0316146116bb576010818154811061168657611686613c9f565b5f9182526020822060039091020180546001600160a01b03191681556001810182905560020155836116b781613cfa565b9450505b806116c581613cfa565b915050611625565b508215611708576040518381527f3a263c878c42a4c5bb7061c3f733d72c3fab05ac016e0c29744864f768fba29b9060200160405180910390a15b5050919050565b5f80611719613494565b6040516336b87bd760e11b81523360048201527f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b031690636d70f7ae90602401602060405180830381865afa15801561177b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061179f9190613cdb565b6117bc576040516327e1f1e560e01b815260040160405180910390fd5b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611818573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061183c9190613cdb565b1561185a576040516313d0ff5960e31b815260040160405180910390fd5b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b031663e9f2838e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118da9190613cdb565b156118f857604051636022a9e760e01b815260040160405180910390fd5b5f611901611bb3565b601154601054919250905f61191560025490565b90505b868610801561192657508183105b15611ae0575f6010848154811061193f5761193f613c9f565b905f5260205f209060030201905080600101545f0361196b578361196281613cfa565b94505050611918565b600a54816002015461197d9190613c8c565b42101561198a5750611ae0565b60018101545f611999826111a2565b9050868111156119ab57505050611ae0565b6119b53083613511565b8160125f8282546119c69190613cb3565b909155505082546001600160a01b03165f9081526013602052604081208054916119ef83613cc6565b91905055505f836001018190555080600c5f828254611a0e9190613c8c565b90915550508254611a4c906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488116911683613549565b611a568188613cb3565b9650611a628189613c8c565b975088611a6e81613cfa565b9950508580611a7c90613cfa565b84549097506001600160a01b031690507f567289124f980c60ab6be9d631895db98cf8d567e8ef80f55d8be6474ad2d0a68383611aba60018b613cb3565b6040805193845260208401929092529082015260600160405180910390a2505050611918565b601154831015611b035760405163179204d960e21b815260040160405180910390fd5b60118390558515611b49575f611b1860025490565b9050818110158015611b2957505f86115b15611b475760405163ef08ba6f60e01b815260040160405180910390fd5b505b601254611b5530611b99565b1015611b745760405163a96cafcf60e01b815260040160405180910390fd5b50505050611b8e60015f80516020613d8e83398151915255565b915091565b5f610d23305b6001600160a01b03165f9081526020819052604090205490565b6040516370a0823160e01b81523060048201525f907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015611c17573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d239190613d12565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cbb9190613c71565b6001600160a01b0316336001600160a01b031614611cec57604051635fc483c560e01b815260040160405180910390fd5b601b545f03611d0e5760405163147fde5f60e31b815260040160405180910390fd5b601a80545f91829055601b919091556040518181527f274eb4b4d7e9d2cc6bbe84034d73372024a36e9dc602a19a9fa861d73093946a90602001610b6c565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611da9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611dcd9190613c71565b6001600160a01b0316336001600160a01b031614611dfe57604051635fc483c560e01b815260040160405180910390fd5b6019545f03611e205760405163147fde5f60e31b815260040160405180910390fd5b601954421015611e435760405163621e25c360e01b815260040160405180910390fd5b60058054601880546001600160a01b038082166001600160a01b03198086168217909655949091169091555f601955604080519190921680825260208201939093527f884b533c458a616d544d78d1ba29d108f2928ac4d80b9644e2678544fc79c9ef9101610b6c565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f09573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2d9190613c71565b6001600160a01b0316336001600160a01b031614158015611fd157506040516336b87bd760e11b81523360048201527f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b031690636d70f7ae90602401602060405180830381865afa158015611fab573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fcf9190613cdb565b155b15611fee576040516282b42960e81b815260040160405180910390fd5b60095460408051918252602082018390527f15afce63833e6bc6e7a8cdd982aede09fc7da372fc07601c6587b2beb8dfaf88910160405180910390a1600955565b5f8061203a60025490565b9050805f0361204d57620f424091505090565b5f61205661094a565b905061206b81670de0b6b3a7640000846133c1565b9250505090565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120ce573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120f29190613c71565b6001600160a01b0316336001600160a01b03161461212357604051635fc483c560e01b815260040160405180910390fd5b601b545f036121455760405163147fde5f60e31b815260040160405180910390fd5b601b544210156121685760405163621e25c360e01b815260040160405180910390fd5b600a8054601a8054928390555f90819055601b5560405190917f8302dc0780ea08ed5fc2063db00696bd339b8c94525c278216fa79045e2d4f5a91610b6c91848252602082015260400190565b60606004805461098f90613c39565b5f6121cd613494565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612229573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061224d9190613cdb565b1561226b576040516313d0ff5960e31b815260040160405180910390fd5b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b031663e9f2838e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122eb9190613cdb565b1561230957604051636022a9e760e01b815260040160405180910390fd5b815f0361232957604051631f2a200560e01b815260040160405180910390fd5b8161233333611b99565b101561235257604051633999656760e01b815260040160405180910390fd5b335f90815260136020526040902054600a1161238157604051638bf0a57960e01b815260040160405180910390fd5b61238c3330846134af565b50601080546040805160608101825233815260208101858152429282019283526001840185555f94855290517f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6726003850290810180546001600160a01b0319166001600160a01b039093169290921790915590517f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae67382015590517f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae67490910155601280549192849261245e908490613c8c565b9091555050335f90815260136020526040812080549161247d83613cfa565b919050555060125461248e30611b99565b10156124ad5760405163a96cafcf60e01b815260040160405180910390fd5b604080518381526020810183905233917f24b91f4f47caf44230a57777a9be744924e82bf666f2d5702faf97df35e60f9f910160405180910390a26124fe60015f80516020613d8e83398151915255565b919050565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561255f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125839190613c71565b6001600160a01b0316336001600160a01b03161415801561262757506040516336b87bd760e11b81523360048201527f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b031690636d70f7ae90602401602060405180830381865afa158015612601573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126259190613cdb565b155b15612644576040516282b42960e81b815260040160405180910390fd5b5f600e54118015612664575062015180600e546126619190613c8c565b42105b15612682576040516319f6f4d960e21b815260040160405180910390fd5b600f5415612700575f61269361094a565b905080156126fe575f808312156126b2576126ad83613d29565b6126b4565b825b90505f670de0b6b3a7640000600f54846126ce9190613d43565b6126d89190613d6e565b9050808211156126fb576040516365012ae960e01b815260040160405180910390fd5b50505b505b80600d5f8282546127119190613c12565b909155505042600e819055600d546040805184815260208101929092528101919091527f0477f1367664ed3cdd6a829e889b321efcc865439db8ef0975ef3fa5e684d8579060600160405180910390a15f8113801561277157505f600754115b1561107a575f8190505f61279082600754670de0b6b3a76400006133c1565b90508015612805575f6127a282610b77565b90508015612803576006546127c0906001600160a01b03168261357e565b6006546040518281526001600160a01b03909116907ff10cda68996dfb656d49ab0db3c62cc5f0849710633671a337171c3ad92551869060200160405180910390a25b505b505050565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612866573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288a9190613c71565b6001600160a01b0316336001600160a01b0316146128bb57604051635fc483c560e01b815260040160405180910390fd5b6706f05b59d3b200008111156128e457604051630adad23360e31b815260040160405180910390fd5b60148190556128f66201518042613c8c565b60158190556040805183815260208101929092527f353b3642b8afdf028473744ee9a601be2fceeb9622fad485f4005fb78dc3b7bf9101610b6c565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561298e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129b29190613c71565b6001600160a01b0316336001600160a01b0316146129e357604051635fc483c560e01b815260040160405180910390fd5b60085460408051918252602082018390527fd1c624d58866d65b5a86de09e962c4fea0fa806c6d868cc2281397aa3524e16f910160405180910390a1600855565b5f306001600160a01b03841603612a4e57604051639dba6a7560e01b815260040160405180910390fd5b610ba583836135b2565b612a8260405180606001604052805f6001600160a01b031681526020015f81526020015f81525090565b6010548210612aa4576040516302e8145360e61b815260040160405180910390fd5b60108281548110612ab757612ab7613c9f565b5f91825260209182902060408051606081018252600390930290910180546001600160a01b031683526001810154938301939093526002909201549181019190915292915050565b5f612b08613494565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b889190613cdb565b15612ba6576040516313d0ff5960e31b815260040160405180910390fd5b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b03166360da3e836040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c02573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c269190613cdb565b15612c445760405163deeb694360e01b815260040160405180910390fd5b815f03612c6457604051631f2a200560e01b815260040160405180910390fd5b5f612c6d61094a565b60085490915015612ca457600854612c858483613c8c565b1115612ca4576040516373ae684760e01b815260040160405180910390fd5b612cad83610b77565b9150815f03612ccf57604051639811e0c760e01b815260040160405180910390fd5b82600b5f828254612ce09190613c8c565b90915550612cf09050338361357e565b612d256001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48163330866135bf565b612d2d6135f5565b604080518481526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a2506124fe60015f80516020613d8e83398151915255565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ddb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612dff9190613c71565b6001600160a01b0316336001600160a01b031614612e3057604051635fc483c560e01b815260040160405180910390fd5b6017545f03612e525760405163147fde5f60e31b815260040160405180910390fd5b601754421015612e755760405163621e25c360e01b815260040160405180910390fd5b60068054601680546001600160a01b038082166001600160a01b03198086168217909655949091169091555f601755604080519190921680825260208201939093527fa6ae278281297c6c7bca891c70bcccd72d64c19819f00fa898896bc26bb53d2f9101610b6c565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5f9190613c71565b6001600160a01b0316336001600160a01b031614612f9057604051635fc483c560e01b815260040160405180910390fd5b600f5460408051918252602082018390527f0b4aa6ab0a4ee9989cc22f2d1a48033543ee0155d920ddf026a93629342432f7910160405180910390a1600f55565b60108181548110612fe0575f80fd5b5f9182526020909120600390910201805460018201546002909201546001600160a01b03909116925083565b5f7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613069573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061308d9190613c71565b6001600160a01b0316336001600160a01b0316146130be57604051635fc483c560e01b815260040160405180910390fd5b5f6130c830611b99565b905060125481116130da575f91505090565b6012546130e79082613cb3565b91506130f33083613511565b6040518281527f4adff76c597b12657368e4fa4d34091975c4165dec971b9951563bcb8fb4ac5a9060200160405180910390a15090565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613186573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906131aa9190613c71565b6001600160a01b0316336001600160a01b0316146131db57604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166132025760405163d92e233d60e01b815260040160405180910390fd5b601680546001600160a01b0319166001600160a01b03831617905561322a6202a30042613c8c565b6017819055604080516001600160a01b038416815260208101929092527f982aac784cef4158ccb29de8199a3fd790f0c4c9228f192cd980360c200ea13d9101610b6c565b7f00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132ef9190613c71565b6001600160a01b0316336001600160a01b03161461332057604051635fc483c560e01b815260040160405180910390fd5b6001600160a01b0381166133475760405163d92e233d60e01b815260040160405180910390fd5b601880546001600160a01b0319166001600160a01b03831617905561336f6203f48042613c8c565b6019819055604080516001600160a01b038416815260208101929092527f5d2d20215fdd0243b3174d686a58b24d814ec266ab3c26f2ab39b52404d8c7569101610b6c565b612805838383600161370c565b5f805f6133ce86866137de565b91509150815f036133f2578381816133e8576133e8613d5a565b0492505050610ba5565b8184116134095761340960038515026011186137fa565b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010185841190960395909502919093039390930492909217029150509392505050565b5f3361347e85828561380b565b6134898585856134af565b506001949350505050565b61349c613881565b60025f80516020613d8e83398151915255565b6001600160a01b0383166134dd57604051634b637e8f60e11b81525f60048201526024015b60405180910390fd5b6001600160a01b0382166135065760405163ec442f0560e01b81525f60048201526024016134d4565b6128058383836138b2565b6001600160a01b03821661353a57604051634b637e8f60e11b81525f60048201526024016134d4565b613545825f836138b2565b5050565b61355683838360016139d8565b61280557604051635274afe760e01b81526001600160a01b03841660048201526024016134d4565b6001600160a01b0382166135a75760405163ec442f0560e01b81525f60048201526024016134d4565b6135455f83836138b2565b5f33610a1d8185856134af565b6135cd848484846001613a3a565b61280357604051635274afe760e01b81526001600160a01b03851660048201526024016134d4565b6040516370a0823160e01b81523060048201525f907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015613659573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061367d9190613d12565b905060095481111561107a575f600954826136989190613cb3565b6005549091506136d5906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488116911683613549565b6040518181527fc186a4ce19f2dc43bb888f6f906d3ca91f090f5ae3394135296bb2cb16bd8f459060200160405180910390a15050565b6001600160a01b0384166137355760405163e602df0560e01b81525f60048201526024016134d4565b6001600160a01b03831661375e57604051634a1406b160e11b81525f60048201526024016134d4565b6001600160a01b038085165f908152600160209081526040808320938716835292905220829055801561280357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516137d091815260200190565b60405180910390a350505050565b5f805f1983850993909202808410938190039390930393915050565b634e487b715f52806020526024601cfd5b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f19811015612803578181101561387357604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016134d4565b61280384848484035f61370c565b5f80516020613d8e833981519152546002036138b057604051633ee5aeb560e01b815260040160405180910390fd5b565b6001600160a01b0383166138dc578060025f8282546138d19190613c8c565b9091555061394c9050565b6001600160a01b0383165f908152602081905260409020548181101561392e5760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016134d4565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661396857600280548290039055613986565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516139cb91815260200190565b60405180910390a3505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316613a2e578383151615613a22573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f51148316613a96578383151615613a8a573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f602080835283518060208501525f5b81811015613ad357858101830151858201604001528201613ab7565b505f604082860101526040601f19601f8301168501019250505092915050565b6001600160a01b038116811461107a575f80fd5b5f8060408385031215613b18575f80fd5b8235613b2381613af3565b946020939093013593505050565b5f60208284031215613b41575f80fd5b5035919050565b5f805f60608486031215613b5a575f80fd5b8335613b6581613af3565b92506020840135613b7581613af3565b929592945050506040919091013590565b5f60208284031215613b96575f80fd5b8135610ba581613af3565b5f8060408385031215613bb2575f80fd5b8235613bbd81613af3565b91506020830135613bcd81613af3565b809150509250929050565b634e487b7160e01b5f52601160045260245ffd5b8181035f831280158383131683831282161715613c0b57613c0b613bd8565b5092915050565b8082018281125f831280158216821582161715613c3157613c31613bd8565b505092915050565b600181811c90821680613c4d57607f821691505b602082108103613c6b57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215613c81575f80fd5b8151610ba581613af3565b80820180821115610a2357610a23613bd8565b634e487b7160e01b5f52603260045260245ffd5b81810381811115610a2357610a23613bd8565b5f81613cd457613cd4613bd8565b505f190190565b5f60208284031215613ceb575f80fd5b81518015158114610ba5575f80fd5b5f60018201613d0b57613d0b613bd8565b5060010190565b5f60208284031215613d22575f80fd5b5051919050565b5f600160ff1b8201613d3d57613d3d613bd8565b505f0390565b8082028115828204841417610a2357610a23613bd8565b634e487b7160e01b5f52601260045260245ffd5b5f82613d8857634e487b7160e01b5f52601260045260245ffd5b50049056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a26469706673582212206ed5e07b9acecc366e1acd12227d4750e4631a09e1f610c4c15c57f7dc71118e64736f6c63430008180033

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

000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d0000000000000000000000000fbce7f3678467f7f7313fcb2c9d1603431ad6660000000000000000000000000fbce7f3678467f7f7313fcb2c9d1603431ad66600000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000074c617a795553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076c617a7955534400000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _usdc (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _roleManager (address): 0x02f8836bbF41e579Ae66B981F538BC015Cd12C7D
Arg [2] : _multisig (address): 0x0FBCe7F3678467f7F7313fcB2C9D1603431Ad666
Arg [3] : _treasury (address): 0x0FBCe7F3678467f7F7313fcB2C9D1603431Ad666
Arg [4] : _feeRate (uint256): 200000000000000000
Arg [5] : _cooldownPeriod (uint256): 86400
Arg [6] : _shareName (string): LazyUSD
Arg [7] : _shareSymbol (string): lazyUSD

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 00000000000000000000000002f8836bbf41e579ae66b981f538bc015cd12c7d
Arg [2] : 0000000000000000000000000fbce7f3678467f7f7313fcb2c9d1603431ad666
Arg [3] : 0000000000000000000000000fbce7f3678467f7f7313fcb2c9d1603431ad666
Arg [4] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [9] : 4c617a7955534400000000000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [11] : 6c617a7955534400000000000000000000000000000000000000000000000000


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

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