false
true
0

Contract Address Details

0x1a2E39B54f153dc3582615fBb8544a3CBC22d94f

Contract Name
MerkleDistributor
Creator
0xca5093–c8dee0 at 0x80d491–ec58e1
Balance
463,984,188.342356079652995387 PLS ( )
Tokens
Fetching tokens...
Transactions
661 Transactions
Transfers
0 Transfers
Gas Used
0
Last Balance Update
26153055
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
MerkleDistributor




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




Optimization runs
200
EVM Version
shanghai




Verified at
2025-12-09T18:51:53.336791Z

contracts/MerkleDistributor.sol

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

import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
 * @title MerkleDistributor
 * @author Fee Distributor Team
 * @notice Distributes native tokens (ETH/PLS) to users via Merkle proofs
 * @dev Features:
 *   - Cumulative claims: Users claim the difference between proof amount and already-claimed
 *   - Epoch system: Each sweep starts a new epoch, resetting claim tracking
 *   - Emergency pause: Owner can pause claims
 *   - Whitelist: Multiple addresses can set merkle roots
 *   - Owner sweep: Owner can reclaim unclaimed funds anytime
 *
 * Security features:
 *   - Merkle root invalidated on sweep to prevent stale proof attacks
 *   - ReentrancyGuard on claim function
 *   - CEI pattern (Checks-Effects-Interactions)
 *   - Zero address validation
 */
contract MerkleDistributor is ReentrancyGuard {
    using SafeERC20 for IERC20;

    // ============================================
    // STATE VARIABLES
    // ============================================

    /// @notice Contract owner
    address public owner;

    /// @notice Pending owner for 2-step transfer
    address public pendingOwner;

    /// @notice Current merkle root for proof verification
    bytes32 public merkleRoot;

    /// @notice Current distribution epoch (increments on sweep)
    uint256 public epoch;

    /// @notice Timestamp when merkle root was last set
    uint256 public lastRootTimestamp;

    /// @notice Whether claims are paused
    bool public paused;

    /// @notice Whitelist of addresses that can set merkle root
    mapping(address => bool) public whitelist;

    /// @notice Tracks claimed amounts: epoch => user => claimed amount
    mapping(uint256 => mapping(address => uint256)) public claimed;

    /// @notice List of V3 pools to collect fees from
    address[] public pools;

    /// @notice Quick lookup for pool existence
    mapping(address => bool) public isPool;

    // ============================================
    // EVENTS
    // ============================================

    event Claimed(address indexed account, uint256 indexed epoch, uint256 amount);
    event MerkleRootSet(bytes32 indexed root, uint256 indexed epoch, uint256 timestamp);
    event MerkleRootInvalidated(uint256 indexed epoch);
    event EpochAdvanced(uint256 indexed oldEpoch, uint256 indexed newEpoch);
    event Swept(address indexed to, uint256 indexed epoch, uint256 amount);
    event WhitelistUpdated(address indexed account, bool indexed status);
    event PauseUpdated(bool indexed paused);
    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    event ERC20Rescued(address indexed token, address indexed to, uint256 amount);
    event Deposited(address indexed from, uint256 amount);
    event EmergencyWithdraw(address indexed to, uint256 amount);
    event PoolAdded(address indexed pool);
    event PoolRemoved(address indexed pool);
    event PoolsCleared();

    // ============================================
    // ERRORS
    // ============================================

    error NotOwner();
    error NotWhitelisted();
    error ContractPaused();
    error InvalidProof();
    error NothingToClaim();
    error TransferFailed();
    error ZeroAddress();
    error InvalidMerkleRoot();
    error InsufficientBalance();
    error NoRootSet();
    error NotPendingOwner();
    error NoPendingOwner();
    error NotPausedForEmergency();
    error PoolAlreadyExists();
    error PoolNotFound();

    // ============================================
    // MODIFIERS
    // ============================================

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

    modifier onlyWhitelisted() {
        _checkWhitelisted();
        _;
    }

    modifier whenNotPaused() {
        _checkNotPaused();
        _;
    }

    // ============================================
    // CONSTRUCTOR
    // ============================================

    constructor() {
        owner = msg.sender;
        whitelist[msg.sender] = true;
        epoch = 1;

        emit OwnershipTransferred(address(0), msg.sender);
        emit WhitelistUpdated(msg.sender, true);
    }

    // ============================================
    // EXTERNAL FUNCTIONS
    // ============================================

    /**
     * @notice Claim native tokens using a Merkle proof
     * @param cumulativeAmount Total amount user is entitled to (cumulative across rounds)
     * @param merkleProof Proof that (msg.sender, cumulativeAmount) is in the tree
     * @dev Follows CEI pattern. Updates state before transfer.
     */
    function claim(
        uint256 cumulativeAmount,
        bytes32[] calldata merkleProof
    ) external nonReentrant whenNotPaused {
        // Check merkle root is set
        if (merkleRoot == bytes32(0)) {
            revert NoRootSet();
        }

        // Verify the proof
        bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender, cumulativeAmount))));
        if (!MerkleProof.verify(merkleProof, merkleRoot, leaf)) {
            revert InvalidProof();
        }

        // Calculate claimable amount (cumulative - already claimed this epoch)
        uint256 alreadyClaimed = claimed[epoch][msg.sender];
        if (cumulativeAmount <= alreadyClaimed) {
            revert NothingToClaim();
        }

        uint256 claimable = cumulativeAmount - alreadyClaimed;

        // Check sufficient balance
        if (address(this).balance < claimable) {
            revert InsufficientBalance();
        }

        // Update claimed amount BEFORE transfer (CEI pattern)
        claimed[epoch][msg.sender] = cumulativeAmount;

        // Transfer native token
        (bool success, ) = msg.sender.call{value: claimable}("");
        if (!success) revert TransferFailed();

        emit Claimed(msg.sender, epoch, claimable);
    }

    /**
     * @notice Set a new merkle root (whitelisted addresses only)
     * @param _merkleRoot New merkle root (must be non-zero)
     */
    function setMerkleRoot(bytes32 _merkleRoot) external onlyWhitelisted {
        if (_merkleRoot == bytes32(0)) {
            revert InvalidMerkleRoot();
        }

        merkleRoot = _merkleRoot;
        lastRootTimestamp = block.timestamp;

        emit MerkleRootSet(_merkleRoot, epoch, block.timestamp);
    }

    /**
     * @notice Advance to a new epoch (owner only)
     * @dev Resets claim tracking AND invalidates root to prevent double-claims.
     *      A new merkle root must be set before users can claim again.
     */
    function newEpoch() external onlyOwner {
        uint256 oldEpoch = epoch;
        
        // SECURITY: Invalidate root to prevent double-claim attack
        // Without this, users could claim again after epoch change with same proof
        merkleRoot = bytes32(0);
        
        // Using unchecked is safe: would take 10^70 years at 1 epoch/second
        unchecked {
            epoch = oldEpoch + 1;
        }

        emit MerkleRootInvalidated(oldEpoch);
        emit EpochAdvanced(oldEpoch, epoch);
    }

    /**
     * @notice Sweep unclaimed funds to specified address (owner only)
     * @param to Address to send funds to
     * @dev Owner can sweep anytime. Invalidates merkle root to prevent stale proof attacks.
     */
    function sweep(address to) external onlyOwner {
        if (to == address(0)) revert ZeroAddress();

        uint256 balance = address(this).balance;
        uint256 currentEpoch = epoch;

        // CRITICAL: Invalidate merkle root to prevent stale proof attacks
        // After sweep, old proofs must not be usable against new deposits
        merkleRoot = bytes32(0);

        // Advance epoch (resets claim tracking)
        unchecked {
            epoch = currentEpoch + 1;
        }

        // Reset timestamp
        lastRootTimestamp = 0;

        emit MerkleRootInvalidated(currentEpoch);
        emit EpochAdvanced(currentEpoch, epoch);

        // Transfer all funds (do last - CEI pattern)
        if (balance > 0) {
            (bool success, ) = to.call{value: balance}("");
            if (!success) revert TransferFailed();
        }

        emit Swept(to, currentEpoch, balance);
    }

    /**
     * @notice Pause or unpause claims (owner only)
     * @param _paused New pause state
     */
    function setPaused(bool _paused) external onlyOwner {
        paused = _paused;
        emit PauseUpdated(_paused);
    }

    /**
     * @notice Update whitelist status for an address (owner only)
     * @param account Address to update
     * @param status New whitelist status
     */
    function setWhitelist(address account, bool status) external onlyOwner {
        if (account == address(0)) revert ZeroAddress();
        whitelist[account] = status;
        emit WhitelistUpdated(account, status);
    }

    /**
     * @notice Start 2-step ownership transfer (owner only)
     * @param newOwner New owner address
     * @dev New owner must call acceptOwnership() to complete transfer
     */
    function transferOwnership(address newOwner) external onlyOwner {
        if (newOwner == address(0)) revert ZeroAddress();
        pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner, newOwner);
    }

    /**
     * @notice Accept ownership (pending owner only)
     * @dev Completes the 2-step ownership transfer
     */
    function acceptOwnership() external {
        if (pendingOwner == address(0)) revert NoPendingOwner();
        if (msg.sender != pendingOwner) revert NotPendingOwner();

        address oldOwner = owner;
        owner = pendingOwner;
        pendingOwner = address(0);

        emit OwnershipTransferred(oldOwner, msg.sender);
    }

    /**
     * @notice Cancel pending ownership transfer (owner only)
     */
    function cancelOwnershipTransfer() external onlyOwner {
        pendingOwner = address(0);
    }

    /**
     * @notice Emergency withdraw when contract is paused (owner only)
     * @param to Recipient address
     * @dev Can only be called when paused. Use for critical bugs.
     *      SECURITY: Invalidates root to prevent stale proof attacks after withdrawal.
     */
    function emergencyWithdraw(address to) external onlyOwner {
        if (!paused) revert NotPausedForEmergency();
        if (to == address(0)) revert ZeroAddress();

        uint256 balance = address(this).balance;
        uint256 currentEpoch = epoch;

        // SECURITY: Invalidate root to prevent stale proof attacks
        // After emergency withdrawal, old proofs must not work against new deposits
        merkleRoot = bytes32(0);

        if (balance > 0) {
            (bool success, ) = to.call{value: balance}("");
            if (!success) revert TransferFailed();
        }

        emit MerkleRootInvalidated(currentEpoch);
        emit EmergencyWithdraw(to, balance);
    }

    /**
     * @notice Rescue ERC20 tokens accidentally sent to this contract
     * @param token ERC20 token address
     * @param to Recipient address
     * @param amount Amount to rescue
     * @dev Only owner can call. Cannot rescue native tokens (use sweep instead).
     */
    function rescueERC20(
        address token,
        address to,
        uint256 amount
    ) external onlyOwner {
        if (token == address(0)) revert ZeroAddress();
        if (to == address(0)) revert ZeroAddress();

        IERC20(token).safeTransfer(to, amount);
        emit ERC20Rescued(token, to, amount);
    }

    // ============================================
    // POOL MANAGEMENT
    // ============================================

    /**
     * @notice Add a pool to the collection list (owner only)
     * @param pool Pool address to add
     */
    function addPool(address pool) external onlyOwner {
        if (pool == address(0)) revert ZeroAddress();
        if (isPool[pool]) revert PoolAlreadyExists();

        pools.push(pool);
        isPool[pool] = true;

        emit PoolAdded(pool);
    }

    /**
     * @notice Add multiple pools at once (owner only)
     * @param _pools Array of pool addresses
     */
    function addPools(address[] calldata _pools) external onlyOwner {
        for (uint256 i = 0; i < _pools.length; i++) {
            address pool = _pools[i];
            if (pool == address(0)) revert ZeroAddress();
            if (isPool[pool]) revert PoolAlreadyExists();

            pools.push(pool);
            isPool[pool] = true;

            emit PoolAdded(pool);
        }
    }

    /**
     * @notice Remove a pool from the collection list (owner only)
     * @param pool Pool address to remove
     */
    function removePool(address pool) external onlyOwner {
        if (!isPool[pool]) revert PoolNotFound();

        // Find and remove from array
        for (uint256 i = 0; i < pools.length; i++) {
            if (pools[i] == pool) {
                // Swap with last element and pop
                pools[i] = pools[pools.length - 1];
                pools.pop();
                break;
            }
        }

        isPool[pool] = false;
        emit PoolRemoved(pool);
    }

    /**
     * @notice Clear all pools (owner only)
     * @dev Use before setting a new list of pools
     */
    function clearPools() external onlyOwner {
        for (uint256 i = 0; i < pools.length; i++) {
            isPool[pools[i]] = false;
        }
        delete pools;
        emit PoolsCleared();
    }

    /**
     * @notice Replace all pools with a new list (owner only)
     * @param _pools New array of pool addresses
     */
    function setPools(address[] calldata _pools) external onlyOwner {
        // Clear existing
        for (uint256 i = 0; i < pools.length; i++) {
            isPool[pools[i]] = false;
        }
        delete pools;

        // Add new
        for (uint256 i = 0; i < _pools.length; i++) {
            address pool = _pools[i];
            if (pool == address(0)) revert ZeroAddress();
            if (isPool[pool]) revert PoolAlreadyExists();

            pools.push(pool);
            isPool[pool] = true;
        }

        emit PoolsCleared();
    }

    /**
     * @notice Get all pools
     * @return Array of pool addresses
     */
    function getPools() external view returns (address[] memory) {
        return pools;
    }

    /**
     * @notice Get number of pools
     * @return Pool count
     */
    function getPoolCount() external view returns (uint256) {
        return pools.length;
    }

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

    /**
     * @notice Get amount claimed by user in current epoch
     * @param account User address
     * @return Amount claimed in current epoch
     */
    function getClaimedAmount(address account) external view returns (uint256) {
        return claimed[epoch][account];
    }

    /**
     * @notice Get amount claimed by user in a specific epoch
     * @param _epoch Epoch number
     * @param account User address
     * @return Amount claimed in specified epoch
     */
    function getClaimedAmountForEpoch(
        uint256 _epoch,
        address account
    ) external view returns (uint256) {
        return claimed[_epoch][account];
    }

    /**
     * @notice Calculate claimable amount for a user
     * @param account User address
     * @param cumulativeAmount User's cumulative amount from proof
     * @return claimable Amount user can claim
     */
    function getClaimableAmount(
        address account,
        uint256 cumulativeAmount
    ) external view returns (uint256 claimable) {
        uint256 alreadyClaimed = claimed[epoch][account];
        if (cumulativeAmount > alreadyClaimed) {
            claimable = cumulativeAmount - alreadyClaimed;
        }
    }

    /**
     * @notice Check if sweep is available (owner can always sweep)
     * @return True - owner can sweep anytime
     */
    function canSweep() external pure returns (bool) {
        return true;
    }

    /**
     * @notice Check if a merkle root is set and valid
     * @return True if root is non-zero
     */
    function hasValidRoot() external view returns (bool) {
        return merkleRoot != bytes32(0);
    }

    /**
     * @notice Get contract's native token balance
     * @return Contract balance
     */
    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }

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

    function _checkOwner() internal view {
        if (msg.sender != owner) revert NotOwner();
    }

    function _checkWhitelisted() internal view {
        if (!whitelist[msg.sender] && msg.sender != owner) revert NotWhitelisted();
    }

    function _checkNotPaused() internal view {
        if (paused) revert ContractPaused();
    }

    // ============================================
    // RECEIVE
    // ============================================

    /// @notice Accept native token deposits
    receive() external payable {
        emit Deposited(msg.sender, msg.value);
    }
}
        

lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol

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

lib/openzeppelin-contracts/contracts/interfaces/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";
          

lib/openzeppelin-contracts/contracts/interfaces/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";
          

lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol

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

lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol

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

lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol

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

lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol

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

lib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sol

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

pragma solidity ^0.8.20;

/**
 * @dev Library of standard hash functions.
 *
 * _Available since v5.1._
 */
library Hashes {
    /**
     * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.
     *
     * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
     */
    function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
        return a < b ? efficientKeccak256(a, b) : efficientKeccak256(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function efficientKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32 value) {
        assembly ("memory-safe") {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}
          

lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol

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

pragma solidity ^0.8.20;

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

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 *
 * IMPORTANT: Consider memory side-effects when using custom hashing functions
 * that access memory in an unsafe way.
 *
 * NOTE: This library supports proof verification for merkle trees built using
 * custom _commutative_ hashing functions (i.e. `H(a, b) == H(b, a)`). Proving
 * leaf inclusion in trees built using non-commutative hashing functions requires
 * additional logic that is not supported by this library.
 */
library MerkleProof {
    /**
     *@dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     *
     * This version handles proofs in memory with the default hashing function.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in memory with the default hashing function.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     *
     * This version handles proofs in memory with a custom hashing function.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processProof(proof, leaf, hasher) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in memory with a custom hashing function.
     */
    function processProof(
        bytes32[] memory proof,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = hasher(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     *
     * This version handles proofs in calldata with the default hashing function.
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in calldata with the default hashing function.
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     *
     * This version handles proofs in calldata with a custom hashing function.
     */
    function verifyCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processProofCalldata(proof, leaf, hasher) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leaves & pre-images are assumed to be sorted.
     *
     * This version handles proofs in calldata with a custom hashing function.
     */
    function processProofCalldata(
        bytes32[] calldata proof,
        bytes32 leaf,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = hasher(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * This version handles multiproofs in memory with the default hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProof}.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * This version handles multiproofs in memory with the default hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](proofFlagsLen);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = Hashes.commutativeKeccak256(a, b);
        }

        if (proofFlagsLen > 0) {
            if (proofPos != proof.length) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[proofFlagsLen - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * This version handles multiproofs in memory with a custom hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProof}.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processMultiProof(proof, proofFlags, leaves, hasher) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * This version handles multiproofs in memory with a custom hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](proofFlagsLen);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = hasher(a, b);
        }

        if (proofFlagsLen > 0) {
            if (proofPos != proof.length) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[proofFlagsLen - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * This version handles multiproofs in calldata with the default hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProofCalldata}.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * This version handles multiproofs in calldata with the default hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](proofFlagsLen);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = Hashes.commutativeKeccak256(a, b);
        }

        if (proofFlagsLen > 0) {
            if (proofPos != proof.length) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[proofFlagsLen - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * This version handles multiproofs in calldata with a custom hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     *
     * NOTE: Consider the case where `root == proof[0] && leaves.length == 0` as it will return `true`.
     * The `leaves` must be validated independently. See {processMultiProofCalldata}.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves, hasher) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * This version handles multiproofs in calldata with a custom hashing function.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     *
     * NOTE: The _empty set_ (i.e. the case where `proof.length == 1 && leaves.length == 0`) is considered a no-op,
     * and therefore a valid multiproof (i.e. it returns `proof[0]`). Consider disallowing this case if you're not
     * validating the leaves elsewhere.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves,
        function(bytes32, bytes32) view returns (bytes32) hasher
    ) internal view returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofFlagsLen = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proof.length != proofFlagsLen + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](proofFlagsLen);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < proofFlagsLen; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = hasher(a, b);
        }

        if (proofFlagsLen > 0) {
            if (proofPos != proof.length) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[proofFlagsLen - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }
}
          

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

Compiler Settings

{"viaIR":false,"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/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/"],"outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.bytecode.sourceMap","evm.bytecode.linkReferences","evm.deployedBytecode.object","evm.deployedBytecode.sourceMap","evm.deployedBytecode.linkReferences","evm.deployedBytecode.immutableReferences","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"shanghai"}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"error","name":"ContractPaused","inputs":[]},{"type":"error","name":"InsufficientBalance","inputs":[]},{"type":"error","name":"InvalidMerkleRoot","inputs":[]},{"type":"error","name":"InvalidProof","inputs":[]},{"type":"error","name":"NoPendingOwner","inputs":[]},{"type":"error","name":"NoRootSet","inputs":[]},{"type":"error","name":"NotOwner","inputs":[]},{"type":"error","name":"NotPausedForEmergency","inputs":[]},{"type":"error","name":"NotPendingOwner","inputs":[]},{"type":"error","name":"NotWhitelisted","inputs":[]},{"type":"error","name":"NothingToClaim","inputs":[]},{"type":"error","name":"PoolAlreadyExists","inputs":[]},{"type":"error","name":"PoolNotFound","inputs":[]},{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]},{"type":"error","name":"SafeERC20FailedOperation","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"TransferFailed","inputs":[]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"event","name":"Claimed","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"uint256","name":"epoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Deposited","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ERC20Rescued","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EmergencyWithdraw","inputs":[{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EpochAdvanced","inputs":[{"type":"uint256","name":"oldEpoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"newEpoch","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"MerkleRootInvalidated","inputs":[{"type":"uint256","name":"epoch","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"MerkleRootSet","inputs":[{"type":"bytes32","name":"root","internalType":"bytes32","indexed":true},{"type":"uint256","name":"epoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferStarted","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PauseUpdated","inputs":[{"type":"bool","name":"paused","internalType":"bool","indexed":true}],"anonymous":false},{"type":"event","name":"PoolAdded","inputs":[{"type":"address","name":"pool","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PoolRemoved","inputs":[{"type":"address","name":"pool","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PoolsCleared","inputs":[],"anonymous":false},{"type":"event","name":"Swept","inputs":[{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"epoch","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WhitelistUpdated","inputs":[{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"bool","name":"status","internalType":"bool","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addPool","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addPools","inputs":[{"type":"address[]","name":"_pools","internalType":"address[]"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"canSweep","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelOwnershipTransfer","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[{"type":"uint256","name":"cumulativeAmount","internalType":"uint256"},{"type":"bytes32[]","name":"merkleProof","internalType":"bytes32[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"claimed","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"clearPools","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyWithdraw","inputs":[{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"epoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBalance","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"claimable","internalType":"uint256"}],"name":"getClaimableAmount","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"cumulativeAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getClaimedAmount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getClaimedAmountForEpoch","inputs":[{"type":"uint256","name":"_epoch","internalType":"uint256"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPoolCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getPools","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasValidRoot","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPool","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastRootTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"merkleRoot","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"newEpoch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pendingOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"pools","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removePool","inputs":[{"type":"address","name":"pool","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMerkleRoot","inputs":[{"type":"bytes32","name":"_merkleRoot","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPaused","inputs":[{"type":"bool","name":"_paused","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPools","inputs":[{"type":"address[]","name":"_pools","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setWhitelist","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"status","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sweep","inputs":[{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"whitelist","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
              

Contract Creation Code

0x608060405234801561000f575f80fd5b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00555f80546001600160a01b03191633908117825580825260066020526040808320805460ff19166001908117909155600355519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a360405160019033907ff93f9a76c1bf3444d22400a00cb9fe990e6abe9dbb333fda48859cfee864543d905f90a3611b16806100c85f395ff3fe6080604052600436106101f4575f3560e01c80636ff1c9bc116101085780639b19251a1161009d578063b3743f601161006d578063b3743f60146105d4578063c83eec91146105f3578063d914cd4b14610606578063e30c397814610625578063f2fde38b14610644575f80fd5b80639b19251a14610549578063ac4afa3814610577578063b2118a8d14610596578063b36a4ab1146105b5575f80fd5b80638da5cb5b116100d85780638da5cb5b146104a85780638df40be8146104de5780638eec5d7014610520578063900cf0cf14610534575f80fd5b80636ff1c9bc1461043757806379ba5097146104565780637cb647591461046a5780638544c53b14610489575f80fd5b80632dd9135f116101895780633b7d0946116101595780633b7d09461461039157806353d6fd59146103b05780635b16ebb7146103cf5780635c975abb146103fd578063673a2a1f14610416575f80fd5b80632dd9135f146103295780632eb4a7ab146103485780632ee3e20b1461035d5780632f52ebb714610372575f80fd5b806316c38b3c116101c457806316c38b3c146102c05780631e8b1135146102df57806323452b9c146102f35780632c45728014610307575f80fd5b806301681a621461023457806310f95fbe1461025557806312065fe014610269578063120aa8771461028a575f80fd5b366102305760405134815233907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c49060200160405180910390a2005b5f80fd5b34801561023f575f80fd5b5061025361024e366004611853565b610663565b005b348015610260575f80fd5b506102536107c1565b348015610274575f80fd5b50475b6040519081526020015b60405180910390f35b348015610295575f80fd5b506102776102a436600461186c565b600760209081525f928352604080842090915290825290205481565b3480156102cb575f80fd5b506102536102da3660046118a5565b610835565b3480156102ea575f80fd5b50610253610879565b3480156102fe575f80fd5b5061025361091f565b348015610312575f80fd5b5060025415155b6040519015158152602001610281565b348015610334575f80fd5b5061027761034336600461186c565b610939565b348015610353575f80fd5b5061027760025481565b348015610368575f80fd5b5061027760045481565b34801561037d575f80fd5b5061025361038c366004611906565b610962565b34801561039c575f80fd5b506102536103ab366004611853565b610b8c565b3480156103bb575f80fd5b506102536103ca36600461194e565b610d15565b3480156103da575f80fd5b506103196103e9366004611853565b60096020525f908152604090205460ff1681565b348015610408575f80fd5b506005546103199060ff1681565b348015610421575f80fd5b5061042a610d97565b6040516102819190611976565b348015610442575f80fd5b50610253610451366004611853565b610df7565b348015610461575f80fd5b50610253610f3c565b348015610475575f80fd5b506102536104843660046119c2565b610fe9565b348015610494575f80fd5b506102536104a33660046119d9565b611056565b3480156104b3575f80fd5b505f546104c6906001600160a01b031681565b6040516001600160a01b039091168152602001610281565b3480156104e9575f80fd5b506102776104f8366004611853565b6003545f9081526007602090815260408083206001600160a01b039094168352929052205490565b34801561052b575f80fd5b50600854610277565b34801561053f575f80fd5b5061027760035481565b348015610554575f80fd5b50610319610563366004611853565b60066020525f908152604090205460ff1681565b348015610582575f80fd5b506104c66105913660046119c2565b611209565b3480156105a1575f80fd5b506102536105b0366004611a18565b611231565b3480156105c0575f80fd5b506102536105cf3660046119d9565b6112e0565b3480156105df575f80fd5b506102776105ee366004611a51565b61141a565b3480156105fe575f80fd5b506001610319565b348015610611575f80fd5b50610253610620366004611853565b61145b565b348015610630575f80fd5b506001546104c6906001600160a01b031681565b34801561064f575f80fd5b5061025361065e366004611853565b611551565b61066b6115d0565b6001600160a01b0381166106925760405163d92e233d60e01b815260040160405180910390fd5b600380545f6002819055600182019092556004829055604051479282917f6f0e8124492339de1992bb885ea32b474e8622264f8d5ad915f82c358d0ee1879190a260035460405182907facfa06cebbab8226f9a388bff9f5fcf4569298028d939f4765958dc57dbb330b905f90a38115610778575f836001600160a01b0316836040515f6040518083038185875af1925050503d805f811461074f576040519150601f19603f3d011682016040523d82523d5f602084013e610754565b606091505b5050905080610776576040516312171d8360e31b815260040160405180910390fd5b505b80836001600160a01b03167f8a89918ff5a1192aacedc279940d66eec9c0a1c2c6490aea91350ff42981c1a9846040516107b491815260200190565b60405180910390a3505050565b6107c96115d0565b600380545f600281905560018201909255604051909182917f6f0e8124492339de1992bb885ea32b474e8622264f8d5ad915f82c358d0ee1879190a260035460405182907facfa06cebbab8226f9a388bff9f5fcf4569298028d939f4765958dc57dbb330b905f90a350565b61083d6115d0565b6005805460ff19168215159081179091556040517f77860e247ab9186dbe64e5bd0e0b93273cc4273e01818420e788f500078886f5905f90a250565b6108816115d0565b5f5b6008548110156108e9575f60095f600884815481106108a4576108a4611a79565b5f918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055806108e181611aa1565b915050610883565b506108f560085f611802565b6040517fba5af8d05396412592ad39670c8400c2d53710beccd60480a5df682505d84b49905f90a1565b6109276115d0565b600180546001600160a01b0319169055565b5f8281526007602090815260408083206001600160a01b03851684529091529020545b92915050565b61096a6115fc565b61097261162a565b60025461099257604051636bda6a5f60e11b815260040160405180910390fd5b604080513360208201529081018490525f9060600160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610a1c8383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050600254915084905061164e565b610a39576040516309bde33960e01b815260040160405180910390fd5b6003545f908152600760209081526040808320338452909152902054808511610a75576040516312d37ee560e31b815260040160405180910390fd5b5f610a808287611ab9565b905080471015610aa357604051631e9acf1760e31b815260040160405180910390fd5b6003545f9081526007602090815260408083203380855292528083208990555183908381818185875af1925050503d805f8114610afb576040519150601f19603f3d011682016040523d82523d5f602084013e610b00565b606091505b5050905080610b22576040516312171d8360e31b815260040160405180910390fd5b60035460405183815233907f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a9060200160405180910390a350505050610b8760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b610b946115d0565b6001600160a01b0381165f9081526009602052604090205460ff16610bcc576040516301dbb3ff60e61b815260040160405180910390fd5b5f5b600854811015610ccc57816001600160a01b031660088281548110610bf557610bf5611a79565b5f918252602090912001546001600160a01b031603610cba5760088054610c1e90600190611ab9565b81548110610c2e57610c2e611a79565b5f91825260209091200154600880546001600160a01b039092169183908110610c5957610c59611a79565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506008805480610c9557610c95611acc565b5f8281526020902081015f1990810180546001600160a01b0319169055019055610ccc565b80610cc481611aa1565b915050610bce565b506001600160a01b0381165f81815260096020526040808220805460ff19169055517f4106dfdaa577573db51c0ca93f766dbedfa0758faa2e7f5bcdb7c142be803c3f9190a250565b610d1d6115d0565b6001600160a01b038216610d445760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382165f81815260066020526040808220805460ff191685151590811790915590519092917ff93f9a76c1bf3444d22400a00cb9fe990e6abe9dbb333fda48859cfee864543d91a35050565b60606008805480602002602001604051908101604052809291908181526020018280548015610ded57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610dcf575b5050505050905090565b610dff6115d0565b60055460ff16610e2257604051637f5c1fcb60e11b815260040160405180910390fd5b6001600160a01b038116610e495760405163d92e233d60e01b815260040160405180910390fd5b6003545f60025547908115610eca575f836001600160a01b0316836040515f6040518083038185875af1925050503d805f8114610ea1576040519150601f19603f3d011682016040523d82523d5f602084013e610ea6565b606091505b5050905080610ec8576040516312171d8360e31b815260040160405180910390fd5b505b60405181907f6f0e8124492339de1992bb885ea32b474e8622264f8d5ad915f82c358d0ee187905f90a2826001600160a01b03167f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd969583604051610f2f91815260200190565b60405180910390a2505050565b6001546001600160a01b0316610f6557604051633e31d61b60e11b815260040160405180910390fd5b6001546001600160a01b03163314610f9057604051630614e5c760e21b815260040160405180910390fd5b5f8054600180546001600160a01b03198084166001600160a01b038381169190911786559116909155604051911691339183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610ff1611663565b8061100f57604051639dd854d360e01b815260040160405180910390fd5b60028190554260048190556003546040519182529082907fc7ce8037cbac8a577b7d8edd9340b4dbb1e691f2eb699b97f5c7576b0e9ede049060200160405180910390a350565b61105e6115d0565b5f5b6008548110156110c6575f60095f6008848154811061108157611081611a79565b5f918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055806110be81611aa1565b915050611060565b506110d260085f611802565b5f5b818110156111dc575f8383838181106110ef576110ef611a79565b90506020020160208101906111049190611853565b90506001600160a01b03811661112d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526009602052604090205460ff161561116657604051630188c99160e11b815260040160405180910390fd5b6008805460018181019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b039093166001600160a01b0319909316831790555f91825260096020526040909120805460ff19169091179055806111d481611aa1565b9150506110d4565b506040517fba5af8d05396412592ad39670c8400c2d53710beccd60480a5df682505d84b49905f90a15050565b60088181548110611218575f80fd5b5f918252602090912001546001600160a01b0316905081565b6112396115d0565b6001600160a01b0383166112605760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382166112875760405163d92e233d60e01b815260040160405180910390fd5b61129b6001600160a01b03841683836116aa565b816001600160a01b0316836001600160a01b03167f8bbfbb5d7fcacf6fc74005cdede0635561638507f576c95f7f294c22141be2e5836040516107b491815260200190565b6112e86115d0565b5f5b81811015610b87575f83838381811061130557611305611a79565b905060200201602081019061131a9190611853565b90506001600160a01b0381166113435760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526009602052604090205460ff161561137c57604051630188c99160e11b815260040160405180910390fd5b6008805460018082019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0384169081179091555f81815260096020526040808220805460ff1916909417909355915190917f73cca62ab1b520c9715bf4e6c71e3e518c754e7148f65102f43289a7df0efea691a2508061141281611aa1565b9150506112ea565b6003545f9081526007602090815260408083206001600160a01b038616845290915281205480831115611454576114518184611ab9565b91505b5092915050565b6114636115d0565b6001600160a01b03811661148a5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526009602052604090205460ff16156114c357604051630188c99160e11b815260040160405180910390fd5b6008805460018082019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0384169081179091555f81815260096020526040808220805460ff1916909417909355915190917f73cca62ab1b520c9715bf4e6c71e3e518c754e7148f65102f43289a7df0efea691a250565b6115596115d0565b6001600160a01b0381166115805760405163d92e233d60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b038381169182179092555f8054604051929316917f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227009190a350565b5f546001600160a01b031633146115fa576040516330cd747160e01b815260040160405180910390fd5b565b6116046116e3565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60055460ff16156115fa5760405163ab35696f60e01b815260040160405180910390fd5b5f8261165a8584611725565b14949350505050565b335f9081526006602052604090205460ff1615801561168c57505f546001600160a01b03163314155b156115fa57604051630b094f2760e31b815260040160405180910390fd5b6116b78383836001611771565b610b8757604051635274afe760e01b81526001600160a01b038416600482015260240160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00546002036115fa57604051633ee5aeb560e01b815260040160405180910390fd5b5f81815b8451811015611769576117558286838151811061174857611748611a79565b60200260200101516117d3565b91508061176181611aa1565b915050611729565b509392505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166117c75783831516156117bb573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b5f8183106117ed575f8281526020849052604090206117fb565b5f8381526020839052604090205b9392505050565b5080545f8255905f5260205f209081019061181d9190611820565b50565b5b80821115611834575f8155600101611821565b5090565b80356001600160a01b038116811461184e575f80fd5b919050565b5f60208284031215611863575f80fd5b6117fb82611838565b5f806040838503121561187d575f80fd5b8235915061188d60208401611838565b90509250929050565b8035801515811461184e575f80fd5b5f602082840312156118b5575f80fd5b6117fb82611896565b5f8083601f8401126118ce575f80fd5b50813567ffffffffffffffff8111156118e5575f80fd5b6020830191508360208260051b85010111156118ff575f80fd5b9250929050565b5f805f60408486031215611918575f80fd5b83359250602084013567ffffffffffffffff811115611935575f80fd5b611941868287016118be565b9497909650939450505050565b5f806040838503121561195f575f80fd5b61196883611838565b915061188d60208401611896565b602080825282518282018190525f9190848201906040850190845b818110156119b65783516001600160a01b031683529284019291840191600101611991565b50909695505050505050565b5f602082840312156119d2575f80fd5b5035919050565b5f80602083850312156119ea575f80fd5b823567ffffffffffffffff811115611a00575f80fd5b611a0c858286016118be565b90969095509350505050565b5f805f60608486031215611a2a575f80fd5b611a3384611838565b9250611a4160208501611838565b9150604084013590509250925092565b5f8060408385031215611a62575f80fd5b611a6b83611838565b946020939093013593505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60018201611ab257611ab2611a8d565b5060010190565b8181038181111561095c5761095c611a8d565b634e487b7160e01b5f52603160045260245ffdfea264697066735822122021bfc34f8e389bc8064c0436092981f540562d2a66de471e21af63931b8ba20364736f6c63430008140033

Deployed ByteCode

0x6080604052600436106101f4575f3560e01c80636ff1c9bc116101085780639b19251a1161009d578063b3743f601161006d578063b3743f60146105d4578063c83eec91146105f3578063d914cd4b14610606578063e30c397814610625578063f2fde38b14610644575f80fd5b80639b19251a14610549578063ac4afa3814610577578063b2118a8d14610596578063b36a4ab1146105b5575f80fd5b80638da5cb5b116100d85780638da5cb5b146104a85780638df40be8146104de5780638eec5d7014610520578063900cf0cf14610534575f80fd5b80636ff1c9bc1461043757806379ba5097146104565780637cb647591461046a5780638544c53b14610489575f80fd5b80632dd9135f116101895780633b7d0946116101595780633b7d09461461039157806353d6fd59146103b05780635b16ebb7146103cf5780635c975abb146103fd578063673a2a1f14610416575f80fd5b80632dd9135f146103295780632eb4a7ab146103485780632ee3e20b1461035d5780632f52ebb714610372575f80fd5b806316c38b3c116101c457806316c38b3c146102c05780631e8b1135146102df57806323452b9c146102f35780632c45728014610307575f80fd5b806301681a621461023457806310f95fbe1461025557806312065fe014610269578063120aa8771461028a575f80fd5b366102305760405134815233907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c49060200160405180910390a2005b5f80fd5b34801561023f575f80fd5b5061025361024e366004611853565b610663565b005b348015610260575f80fd5b506102536107c1565b348015610274575f80fd5b50475b6040519081526020015b60405180910390f35b348015610295575f80fd5b506102776102a436600461186c565b600760209081525f928352604080842090915290825290205481565b3480156102cb575f80fd5b506102536102da3660046118a5565b610835565b3480156102ea575f80fd5b50610253610879565b3480156102fe575f80fd5b5061025361091f565b348015610312575f80fd5b5060025415155b6040519015158152602001610281565b348015610334575f80fd5b5061027761034336600461186c565b610939565b348015610353575f80fd5b5061027760025481565b348015610368575f80fd5b5061027760045481565b34801561037d575f80fd5b5061025361038c366004611906565b610962565b34801561039c575f80fd5b506102536103ab366004611853565b610b8c565b3480156103bb575f80fd5b506102536103ca36600461194e565b610d15565b3480156103da575f80fd5b506103196103e9366004611853565b60096020525f908152604090205460ff1681565b348015610408575f80fd5b506005546103199060ff1681565b348015610421575f80fd5b5061042a610d97565b6040516102819190611976565b348015610442575f80fd5b50610253610451366004611853565b610df7565b348015610461575f80fd5b50610253610f3c565b348015610475575f80fd5b506102536104843660046119c2565b610fe9565b348015610494575f80fd5b506102536104a33660046119d9565b611056565b3480156104b3575f80fd5b505f546104c6906001600160a01b031681565b6040516001600160a01b039091168152602001610281565b3480156104e9575f80fd5b506102776104f8366004611853565b6003545f9081526007602090815260408083206001600160a01b039094168352929052205490565b34801561052b575f80fd5b50600854610277565b34801561053f575f80fd5b5061027760035481565b348015610554575f80fd5b50610319610563366004611853565b60066020525f908152604090205460ff1681565b348015610582575f80fd5b506104c66105913660046119c2565b611209565b3480156105a1575f80fd5b506102536105b0366004611a18565b611231565b3480156105c0575f80fd5b506102536105cf3660046119d9565b6112e0565b3480156105df575f80fd5b506102776105ee366004611a51565b61141a565b3480156105fe575f80fd5b506001610319565b348015610611575f80fd5b50610253610620366004611853565b61145b565b348015610630575f80fd5b506001546104c6906001600160a01b031681565b34801561064f575f80fd5b5061025361065e366004611853565b611551565b61066b6115d0565b6001600160a01b0381166106925760405163d92e233d60e01b815260040160405180910390fd5b600380545f6002819055600182019092556004829055604051479282917f6f0e8124492339de1992bb885ea32b474e8622264f8d5ad915f82c358d0ee1879190a260035460405182907facfa06cebbab8226f9a388bff9f5fcf4569298028d939f4765958dc57dbb330b905f90a38115610778575f836001600160a01b0316836040515f6040518083038185875af1925050503d805f811461074f576040519150601f19603f3d011682016040523d82523d5f602084013e610754565b606091505b5050905080610776576040516312171d8360e31b815260040160405180910390fd5b505b80836001600160a01b03167f8a89918ff5a1192aacedc279940d66eec9c0a1c2c6490aea91350ff42981c1a9846040516107b491815260200190565b60405180910390a3505050565b6107c96115d0565b600380545f600281905560018201909255604051909182917f6f0e8124492339de1992bb885ea32b474e8622264f8d5ad915f82c358d0ee1879190a260035460405182907facfa06cebbab8226f9a388bff9f5fcf4569298028d939f4765958dc57dbb330b905f90a350565b61083d6115d0565b6005805460ff19168215159081179091556040517f77860e247ab9186dbe64e5bd0e0b93273cc4273e01818420e788f500078886f5905f90a250565b6108816115d0565b5f5b6008548110156108e9575f60095f600884815481106108a4576108a4611a79565b5f918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055806108e181611aa1565b915050610883565b506108f560085f611802565b6040517fba5af8d05396412592ad39670c8400c2d53710beccd60480a5df682505d84b49905f90a1565b6109276115d0565b600180546001600160a01b0319169055565b5f8281526007602090815260408083206001600160a01b03851684529091529020545b92915050565b61096a6115fc565b61097261162a565b60025461099257604051636bda6a5f60e11b815260040160405180910390fd5b604080513360208201529081018490525f9060600160408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610a1c8383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525050600254915084905061164e565b610a39576040516309bde33960e01b815260040160405180910390fd5b6003545f908152600760209081526040808320338452909152902054808511610a75576040516312d37ee560e31b815260040160405180910390fd5b5f610a808287611ab9565b905080471015610aa357604051631e9acf1760e31b815260040160405180910390fd5b6003545f9081526007602090815260408083203380855292528083208990555183908381818185875af1925050503d805f8114610afb576040519150601f19603f3d011682016040523d82523d5f602084013e610b00565b606091505b5050905080610b22576040516312171d8360e31b815260040160405180910390fd5b60035460405183815233907f987d620f307ff6b94d58743cb7a7509f24071586a77759b77c2d4e29f75a2f9a9060200160405180910390a350505050610b8760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b610b946115d0565b6001600160a01b0381165f9081526009602052604090205460ff16610bcc576040516301dbb3ff60e61b815260040160405180910390fd5b5f5b600854811015610ccc57816001600160a01b031660088281548110610bf557610bf5611a79565b5f918252602090912001546001600160a01b031603610cba5760088054610c1e90600190611ab9565b81548110610c2e57610c2e611a79565b5f91825260209091200154600880546001600160a01b039092169183908110610c5957610c59611a79565b905f5260205f20015f6101000a8154816001600160a01b0302191690836001600160a01b031602179055506008805480610c9557610c95611acc565b5f8281526020902081015f1990810180546001600160a01b0319169055019055610ccc565b80610cc481611aa1565b915050610bce565b506001600160a01b0381165f81815260096020526040808220805460ff19169055517f4106dfdaa577573db51c0ca93f766dbedfa0758faa2e7f5bcdb7c142be803c3f9190a250565b610d1d6115d0565b6001600160a01b038216610d445760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382165f81815260066020526040808220805460ff191685151590811790915590519092917ff93f9a76c1bf3444d22400a00cb9fe990e6abe9dbb333fda48859cfee864543d91a35050565b60606008805480602002602001604051908101604052809291908181526020018280548015610ded57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311610dcf575b5050505050905090565b610dff6115d0565b60055460ff16610e2257604051637f5c1fcb60e11b815260040160405180910390fd5b6001600160a01b038116610e495760405163d92e233d60e01b815260040160405180910390fd5b6003545f60025547908115610eca575f836001600160a01b0316836040515f6040518083038185875af1925050503d805f8114610ea1576040519150601f19603f3d011682016040523d82523d5f602084013e610ea6565b606091505b5050905080610ec8576040516312171d8360e31b815260040160405180910390fd5b505b60405181907f6f0e8124492339de1992bb885ea32b474e8622264f8d5ad915f82c358d0ee187905f90a2826001600160a01b03167f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd969583604051610f2f91815260200190565b60405180910390a2505050565b6001546001600160a01b0316610f6557604051633e31d61b60e11b815260040160405180910390fd5b6001546001600160a01b03163314610f9057604051630614e5c760e21b815260040160405180910390fd5b5f8054600180546001600160a01b03198084166001600160a01b038381169190911786559116909155604051911691339183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610ff1611663565b8061100f57604051639dd854d360e01b815260040160405180910390fd5b60028190554260048190556003546040519182529082907fc7ce8037cbac8a577b7d8edd9340b4dbb1e691f2eb699b97f5c7576b0e9ede049060200160405180910390a350565b61105e6115d0565b5f5b6008548110156110c6575f60095f6008848154811061108157611081611a79565b5f918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055806110be81611aa1565b915050611060565b506110d260085f611802565b5f5b818110156111dc575f8383838181106110ef576110ef611a79565b90506020020160208101906111049190611853565b90506001600160a01b03811661112d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526009602052604090205460ff161561116657604051630188c99160e11b815260040160405180910390fd5b6008805460018181019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b039093166001600160a01b0319909316831790555f91825260096020526040909120805460ff19169091179055806111d481611aa1565b9150506110d4565b506040517fba5af8d05396412592ad39670c8400c2d53710beccd60480a5df682505d84b49905f90a15050565b60088181548110611218575f80fd5b5f918252602090912001546001600160a01b0316905081565b6112396115d0565b6001600160a01b0383166112605760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0382166112875760405163d92e233d60e01b815260040160405180910390fd5b61129b6001600160a01b03841683836116aa565b816001600160a01b0316836001600160a01b03167f8bbfbb5d7fcacf6fc74005cdede0635561638507f576c95f7f294c22141be2e5836040516107b491815260200190565b6112e86115d0565b5f5b81811015610b87575f83838381811061130557611305611a79565b905060200201602081019061131a9190611853565b90506001600160a01b0381166113435760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526009602052604090205460ff161561137c57604051630188c99160e11b815260040160405180910390fd5b6008805460018082019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0384169081179091555f81815260096020526040808220805460ff1916909417909355915190917f73cca62ab1b520c9715bf4e6c71e3e518c754e7148f65102f43289a7df0efea691a2508061141281611aa1565b9150506112ea565b6003545f9081526007602090815260408083206001600160a01b038616845290915281205480831115611454576114518184611ab9565b91505b5092915050565b6114636115d0565b6001600160a01b03811661148a5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0381165f9081526009602052604090205460ff16156114c357604051630188c99160e11b815260040160405180910390fd5b6008805460018082019092557ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30180546001600160a01b0319166001600160a01b0384169081179091555f81815260096020526040808220805460ff1916909417909355915190917f73cca62ab1b520c9715bf4e6c71e3e518c754e7148f65102f43289a7df0efea691a250565b6115596115d0565b6001600160a01b0381166115805760405163d92e233d60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b038381169182179092555f8054604051929316917f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227009190a350565b5f546001600160a01b031633146115fa576040516330cd747160e01b815260040160405180910390fd5b565b6116046116e3565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60055460ff16156115fa5760405163ab35696f60e01b815260040160405180910390fd5b5f8261165a8584611725565b14949350505050565b335f9081526006602052604090205460ff1615801561168c57505f546001600160a01b03163314155b156115fa57604051630b094f2760e31b815260040160405180910390fd5b6116b78383836001611771565b610b8757604051635274afe760e01b81526001600160a01b038416600482015260240160405180910390fd5b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00546002036115fa57604051633ee5aeb560e01b815260040160405180910390fd5b5f81815b8451811015611769576117558286838151811061174857611748611a79565b60200260200101516117d3565b91508061176181611aa1565b915050611729565b509392505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166117c75783831516156117bb573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b5f8183106117ed575f8281526020849052604090206117fb565b5f8381526020839052604090205b9392505050565b5080545f8255905f5260205f209081019061181d9190611820565b50565b5b80821115611834575f8155600101611821565b5090565b80356001600160a01b038116811461184e575f80fd5b919050565b5f60208284031215611863575f80fd5b6117fb82611838565b5f806040838503121561187d575f80fd5b8235915061188d60208401611838565b90509250929050565b8035801515811461184e575f80fd5b5f602082840312156118b5575f80fd5b6117fb82611896565b5f8083601f8401126118ce575f80fd5b50813567ffffffffffffffff8111156118e5575f80fd5b6020830191508360208260051b85010111156118ff575f80fd5b9250929050565b5f805f60408486031215611918575f80fd5b83359250602084013567ffffffffffffffff811115611935575f80fd5b611941868287016118be565b9497909650939450505050565b5f806040838503121561195f575f80fd5b61196883611838565b915061188d60208401611896565b602080825282518282018190525f9190848201906040850190845b818110156119b65783516001600160a01b031683529284019291840191600101611991565b50909695505050505050565b5f602082840312156119d2575f80fd5b5035919050565b5f80602083850312156119ea575f80fd5b823567ffffffffffffffff811115611a00575f80fd5b611a0c858286016118be565b90969095509350505050565b5f805f60608486031215611a2a575f80fd5b611a3384611838565b9250611a4160208501611838565b9150604084013590509250925092565b5f8060408385031215611a62575f80fd5b611a6b83611838565b946020939093013593505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60018201611ab257611ab2611a8d565b5060010190565b8181038181111561095c5761095c611a8d565b634e487b7160e01b5f52603160045260245ffdfea264697066735822122021bfc34f8e389bc8064c0436092981f540562d2a66de471e21af63931b8ba20364736f6c63430008140033