ChildIndexVault

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "viaIR": true,
    "remappings": []
  },
  "sources": {
    "contracts/ChildIndexVault.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {AccessControlManager} from "./AccessControlManager.sol";

/**
 * @title ChildIndexVault
 * @notice Improved child vault for managing portfolio operations on non-base chains
 * @dev Executes swaps and bridges based on MasterVault instructions
 */
contract ChildIndexVault is
    Initializable,
    ReentrancyGuardUpgradeable,
    PausableUpgradeable
{
    using SafeERC20 for IERC20;

    // ═══════════════════════════════════════════════════════════════════════════
    // CONSTANTS
    // ═══════════════════════════════════════════════════════════════════════════

    uint256 public constant MIN_REBALANCE_INTERVAL = 5 minutes;
    uint256 public constant OPERATION_EXPIRY = 1 hours;

    // Role identifiers
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant ALLOCATOR_ROLE = keccak256("ALLOCATOR_ROLE");

    // ═══════════════════════════════════════════════════════════════════════════
    // STRUCTS (Matching MasterVault for consistency)
    // ═══════════════════════════════════════════════════════════════════════════

    /// @notice Represents a vault on another chain
    struct RemoteVault {
        uint256 chainId;
        string vaultAddress; // String to support non-EVM addresses
        string usdcAddress; // String to support non-EVM addresses
        bool isActive;
        uint256 lastUpdateTime;
    }

    /// @notice Local swap operation
    struct SwapOperation {
        string operationId;
        address tokenIn;
        address tokenOut;
        uint256 amountIn;
        uint256 minAmountOut;
        bytes swapData; // LiFi encoded swap data
    }

    /// @notice Cross-chain operation
    struct CrossChainOperation {
        string operationId;
        string bridgeId;
        uint256 sourceChain;
        uint256 targetChain;
        address tokenIn;
        uint256 amountIn;
        uint256 minAmountOut;
        bytes bridgeData; // LiFi encoded bridge data
    }

    /// @notice Rebalancing plan for a specific chain
    struct RebalancingPlan {
        uint256 chainId;
        string batchId;
        SwapOperation[] swapOperations;
    }

    /// @notice Bridge receipt for tracking incoming funds
    struct BridgeReceipt {
        string bridgeId;
        uint256 amount;
        uint256 sourceChain;
        uint256 timestamp;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // STATE VARIABLES
    // ═══════════════════════════════════════════════════════════════════════════

    // Core components
    address public USDC;
    address public MASTER_VAULT;
    uint256 public BASE_CHAIN;
    AccessControlManager public accessControlManager;
    address public lifiRouter;

    // Remote vault registry
    mapping(uint256 => RemoteVault) public remoteVaults;
    uint256[] public supportedChains;

    // Operation tracking
    mapping(string => bool) public completedOperations;
    mapping(string => uint256) public operationTimestamps;
    uint256 public lastRebalanceTime;

    // ═══════════════════════════════════════════════════════════════════════════
    // EVENTS (Matching MasterVault structure)
    // ═══════════════════════════════════════════════════════════════════════════

    // System events
    event VaultInitialized(
        address indexed usdc,
        address indexed masterVault,
        uint256 indexed baseChain
    );
    event RemoteVaultUpdated(
        uint256 indexed chainId,
        string vaultAddress,
        string usdcAddress,
        bool isActive
    );
    event ConfigurationUpdated(
        string parameter,
        address oldValue,
        address newValue
    );

    // Operation events
    event SwapExecuted(
        string indexed operationId,
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOut
    );
    event CrossChainInitiated(
        string indexed bridgeId,
        uint256 sourceChain,
        uint256 targetChain,
        uint256 amount
    );
    event BridgeReceived(
        string indexed bridgeId,
        uint256 amount,
        uint256 sourceChain
    );
    event BridgeReceiptsProcessed(uint256 totalAmount, uint256 receiptCount);
    event BatchCompleted(string indexed batchId, uint256 operations);
    event RebalanceExecuted(string indexed rebalanceId, uint256 operations);

    // ═══════════════════════════════════════════════════════════════════════════
    // ERRORS
    // ═══════════════════════════════════════════════════════════════════════════

    error InvalidAddress();
    error InvalidAmount();
    error InvalidChain();
    error InvalidOperation();
    error OperationExpired();
    error OperationCompleted();
    error InsufficientBalance();
    error ExcessiveSlippage();
    error UnauthorizedCaller();
    error RebalanceTooSoon();
    error InvalidConfiguration();

    // ═══════════════════════════════════════════════════════════════════════════
    // MODIFIERS
    // ═══════════════════════════════════════════════════════════════════════════

    modifier onlyRole(bytes32 role) {
        if (!accessControlManager.hasRole(role, msg.sender)) {
            revert UnauthorizedCaller();
        }
        _;
    }

    modifier validOperation(string calldata operationId) {
        if (bytes(operationId).length == 0) revert InvalidOperation();
        if (completedOperations[operationId]) revert OperationCompleted();
        _;
    }

    modifier rateLimited() {
        if (block.timestamp < lastRebalanceTime + MIN_REBALANCE_INTERVAL) {
            revert RebalanceTooSoon();
        }
        lastRebalanceTime = block.timestamp;
        _;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // INITIALIZATION
    // ═══════════════════════════════════════════════════════════════════════════

    function initialize(
        address _usdc,
        address _masterVault,
        uint256 _baseChain,
        address _accessControlManager,
        address _lifiRouter
    ) external initializer {
        if (_usdc == address(0)) revert InvalidAddress();
        if (_masterVault == address(0)) revert InvalidAddress();
        if (_baseChain == 0) revert InvalidChain();
        if (_accessControlManager == address(0)) revert InvalidAddress();
        if (_lifiRouter == address(0)) revert InvalidAddress();

        __ReentrancyGuard_init();
        __Pausable_init();

        USDC = _usdc;
        MASTER_VAULT = _masterVault;
        BASE_CHAIN = _baseChain;
        accessControlManager = AccessControlManager(_accessControlManager);
        lifiRouter = _lifiRouter;

        emit VaultInitialized(_usdc, _masterVault, _baseChain);
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // MAIN FUNCTIONS
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * @notice Executes local swaps on current chain
     * @param batchId Unique identifier for the swap batch
     * @param swapOperations Array of swap operations to execute
     */
    function executeLocalSwaps(
        string calldata batchId,
        SwapOperation[] calldata swapOperations
    )
        external
        onlyRole(ALLOCATOR_ROLE)
        validOperation(batchId)
        nonReentrant
        whenNotPaused
    {
        if (swapOperations.length == 0) revert InvalidOperation();

        uint256 executedOps = _executeSwapBatch(swapOperations);

        completedOperations[batchId] = true;
        operationTimestamps[batchId] = block.timestamp;

        emit BatchCompleted(batchId, executedOps);
    }

    /**
     * @notice Executes cross-chain operations
     * @param batchId Unique identifier for the cross-chain batch
     * @param crossChainOperations Array of cross-chain operations to execute
     */
    function executeCrossChainOperations(
        string calldata batchId,
        CrossChainOperation[] calldata crossChainOperations
    )
        external
        onlyRole(ALLOCATOR_ROLE)
        validOperation(batchId)
        nonReentrant
        whenNotPaused
    {
        if (crossChainOperations.length == 0) revert InvalidOperation();

        for (uint256 i = 0; i < crossChainOperations.length; i++) {
            _executeCrossChainOperation(crossChainOperations[i]);
        }

        completedOperations[batchId] = true;
        operationTimestamps[batchId] = block.timestamp;

        emit BatchCompleted(batchId, crossChainOperations.length);
    }

    /**
     * @notice Receives and processes bridge receipts with total balance validation
     * @param receipts Array of bridge receipts to process
     * @return totalReceived Total amount received from all receipts
     */
    function processBridgeReceipts(
        BridgeReceipt[] calldata receipts
    )
        external
        onlyRole(ALLOCATOR_ROLE)
        nonReentrant
        whenNotPaused
        returns (uint256 totalReceived)
    {
        if (receipts.length == 0) revert InvalidOperation();

        // Calculate total expected amount from all receipts
        uint256 totalExpected = 0;
        for (uint256 i = 0; i < receipts.length; i++) {
            BridgeReceipt calldata receipt = receipts[i];

            if (bytes(receipt.bridgeId).length == 0) revert InvalidOperation();
            if (completedOperations[receipt.bridgeId]) revert OperationCompleted();
            if (receipt.amount == 0) revert InvalidAmount();
            if (receipt.sourceChain == 0) revert InvalidChain();

            totalExpected += receipt.amount;
        }

        // Validate contract has sufficient balance for all receipts combined
        uint256 contractBalance = IERC20(USDC).balanceOf(address(this));
        if (contractBalance < totalExpected) revert InsufficientBalance();

        // Process each receipt after validation
        for (uint256 i = 0; i < receipts.length; i++) {
            BridgeReceipt calldata receipt = receipts[i];

            completedOperations[receipt.bridgeId] = true;
            totalReceived += receipt.amount;

            emit BridgeReceived(
                receipt.bridgeId,
                receipt.amount,
                receipt.sourceChain
            );
        }

        // Emit batch processing event
        emit BridgeReceiptsProcessed(totalReceived, receipts.length);

        return totalReceived;
    }

    /**
     * @notice Unified rebalancing function (matching MasterVault structure)
     */
    function rebalance(
        string calldata rebalanceId,
        RebalancingPlan[] calldata plans,
        CrossChainOperation[] calldata crossChainOps
    )
        external
        onlyRole(ALLOCATOR_ROLE)
        validOperation(rebalanceId)
        nonReentrant
        whenNotPaused
        rateLimited
    {
        if (plans.length == 0 && crossChainOps.length == 0)
            revert InvalidOperation();

        uint256 totalOperations = 0;

        // Execute local operations for this chain
        for (uint256 i = 0; i < plans.length; i++) {
            if (plans[i].chainId == block.chainid) {
                totalOperations += _executeSwapBatch(plans[i].swapOperations);
            }
        }

        // Execute cross-chain operations
        for (uint256 i = 0; i < crossChainOps.length; i++) {
            if (crossChainOps[i].sourceChain == block.chainid) {
                _executeCrossChainOperation(crossChainOps[i]);
                totalOperations++;
            }
        }

        completedOperations[rebalanceId] = true;
        operationTimestamps[rebalanceId] = block.timestamp;
        emit RebalanceExecuted(rebalanceId, totalOperations);
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // INTERNAL FUNCTIONS
    // ═══════════════════════════════════════════════════════════════════════════

    function _executeSwapBatch(
        SwapOperation[] memory swaps
    ) internal returns (uint256) {
        uint256 executed = 0;

        for (uint256 i = 0; i < swaps.length; i++) {
            _executeSwap(swaps[i]);
            executed++;
        }

        return executed;
    }

    function _executeSwap(
        SwapOperation memory swap
    ) internal returns (uint256) {
        // Validate
        if (swap.amountIn == 0) revert InvalidAmount();
        if (swap.minAmountOut == 0) revert InvalidAmount();

        // Check balance
        uint256 balanceBefore = IERC20(swap.tokenOut).balanceOf(address(this));

        // Approve router
        IERC20(swap.tokenIn).safeIncreaseAllowance(lifiRouter, swap.amountIn);

        // Execute swap
        (bool success, ) = lifiRouter.call(swap.swapData);
        if (!success) revert InvalidOperation();

        // Reset approval
        IERC20(swap.tokenIn).safeDecreaseAllowance(lifiRouter, 0);

        // Calculate output
        uint256 balanceAfter = IERC20(swap.tokenOut).balanceOf(address(this));
        uint256 amountOut = balanceAfter - balanceBefore;

        // Validate slippage
        if (amountOut < swap.minAmountOut) revert ExcessiveSlippage();

        emit SwapExecuted(
            swap.operationId,
            swap.tokenIn,
            swap.tokenOut,
            swap.amountIn,
            amountOut
        );

        return amountOut;
    }

    function _executeCrossChainOperation(
        CrossChainOperation memory op
    ) internal {
        if (op.sourceChain != block.chainid) revert InvalidChain();
        if (op.amountIn == 0) revert InvalidAmount();

        // Approve router
        IERC20(op.tokenIn).safeIncreaseAllowance(lifiRouter, op.amountIn);

        // Execute bridge
        (bool success, ) = lifiRouter.call(op.bridgeData);
        if (!success) revert InvalidOperation();

        // Reset approval
        IERC20(op.tokenIn).safeDecreaseAllowance(lifiRouter, 0);

        emit CrossChainInitiated(
            op.bridgeId,
            op.sourceChain,
            op.targetChain,
            op.amountIn
        );
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // ADMIN FUNCTIONS
    // ═══════════════════════════════════════════════════════════════════════════

    function updateRemoteVault(
        uint256 chainId,
        string calldata vaultAddress,
        string calldata usdcAddress,
        bool isActive
    ) external onlyRole(ADMIN_ROLE) {
        if (chainId == 0) revert InvalidChain();

        remoteVaults[chainId] = RemoteVault({
            chainId: chainId,
            vaultAddress: vaultAddress,
            usdcAddress: usdcAddress,
            isActive: isActive,
            lastUpdateTime: block.timestamp
        });

        // Update supported chains array
        if (isActive && !_isChainSupported(chainId)) {
            supportedChains.push(chainId);
        }

        emit RemoteVaultUpdated(chainId, vaultAddress, usdcAddress, isActive);
    }

    function setLiFiRouter(address _newRouter) external onlyRole(ADMIN_ROLE) {
        if (_newRouter == address(0)) revert InvalidAddress();

        address oldRouter = lifiRouter;
        lifiRouter = _newRouter;

        emit ConfigurationUpdated("lifiRouter", oldRouter, _newRouter);
    }

    function setMasterVault(
        address _newMasterVault
    ) external onlyRole(ADMIN_ROLE) {
        if (_newMasterVault == address(0)) revert InvalidAddress();

        address oldMaster = MASTER_VAULT;
        MASTER_VAULT = _newMasterVault;

        emit ConfigurationUpdated("masterVault", oldMaster, _newMasterVault);
    }

    function pause() external onlyRole(ADMIN_ROLE) {
        _pause();
    }

    function unpause() external onlyRole(ADMIN_ROLE) {
        _unpause();
    }

    function resetRebalanceCooldown() external onlyRole(ADMIN_ROLE) {
        lastRebalanceTime = 0;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // VIEW FUNCTIONS
    // ═══════════════════════════════════════════════════════════════════════════

    function getRemoteVault(
        uint256 chainId
    ) external view returns (RemoteVault memory) {
        return remoteVaults[chainId];
    }

    function getSupportedChains() external view returns (uint256[] memory) {
        return supportedChains;
    }

    function getTokenBalance(address token) external view returns (uint256) {
        return IERC20(token).balanceOf(address(this));
    }

    function canRebalance() external view returns (bool) {
        return block.timestamp >= lastRebalanceTime + MIN_REBALANCE_INTERVAL;
    }

    function isOperationCompleted(
        string calldata operationId
    ) external view returns (bool) {
        return completedOperations[operationId];
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // INTERNAL VIEW FUNCTIONS
    // ═══════════════════════════════════════════════════════════════════════════

    function _isChainSupported(uint256 chainId) internal view returns (bool) {
        for (uint256 i = 0; i < supportedChains.length; i++) {
            if (supportedChains[i] == chainId) return true;
        }
        return false;
    }

    function emergencyTokensWithdrawal(
        address[] calldata tokens
    ) external onlyRole(ADMIN_ROLE) {
        for (uint256 i = 0; i < tokens.length; i++) {
            IERC20(tokens[i]).safeTransfer(msg.sender, IERC20(tokens[i]).balanceOf(address(this)));
        }
    }
}"
    },
    "contracts/AccessControlManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/**
 * @title AccessControlManager
 * @notice Manages centralized role-based access control for the AI Indices ecosystem.
 * @dev Only addresses with GOVERNANCE_ROLE can grant/revoke roles.
 * Designed to integrate with vaults, bridges, and validators.
 */
contract AccessControlManager is
    Initializable,
    AccessControlUpgradeable,
    PausableUpgradeable
{
    /* ========== ROLES ========== */

    /// @notice Role for entities allowed to manage other roles (e.g., multisig or DAO)
    bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE");

    /// @notice Role for authorized rebalancers or executors (e.g., bot, backend service)
    bytes32 public constant ALLOCATOR_ROLE = keccak256("ALLOCATOR_ROLE");

    /// @notice Role for emergency operators allowed to pause contracts
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");

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

    /**
     * @notice Emitted when the contract is paused by a PAUSER_ROLE account
     * @param caller The address that paused the contract
     */
    event EmergencyPaused(address indexed caller);

    /**
     * @notice Emitted when the contract is unpaused by a PAUSER_ROLE account
     * @param caller The address that unpaused the contract
     */
    event EmergencyUnpaused(address indexed caller);

    /* ========== CONSTRUCTOR ========== */

    function initialize(
        address governance,
        address allocator,
        address pauser
    ) public initializer {
        require(governance != address(0), "Zero governance");
        require(allocator != address(0), "Zero allocator");
        require(pauser != address(0), "Zero pauser");

        __AccessControl_init();
        __Pausable_init();

        _grantRole(DEFAULT_ADMIN_ROLE, governance);
        _grantRole(GOVERNANCE_ROLE, governance);
        _grantRole(ALLOCATOR_ROLE, allocator);
        _grantRole(PAUSER_ROLE, pauser);
    }

    /* ========== ROLE MANAGEMENT ========== */

    /**
     * @notice Grants a specific role to an account
     * @dev Only GOVERNANCE_ROLE can call this
     * @param role The role to be granted
     * @param account The address to receive the role
     */
    function grantRole(
        bytes32 role,
        address account
    ) public override onlyRole(GOVERNANCE_ROLE) {
        require(account != address(0), "Zero address");
        super.grantRole(role, account);
    }

    /**
     * @notice Revokes a specific role from an account
     * @dev Only GOVERNANCE_ROLE can call this
     * @param role The role to be revoked
     * @param account The address losing the role
     */
    function revokeRole(
        bytes32 role,
        address account
    ) public override onlyRole(GOVERNANCE_ROLE) {
        require(account != address(0), "Zero address");
        super.revokeRole(role, account);
    }

    /**
     * @notice Allows an account to renounce its own role
     * @param role The role to renounce
     * @param account The calling address (must match msg.sender)
     */
    function renounceRole(bytes32 role, address account) public override {
        require(account == msg.sender, "Can only renounce self");
        super.renounceRole(role, account);
    }

    /* ========== EMERGENCY CONTROLS ========== */

    /**
     * @notice Pauses all integrated contracts that rely on this access manager
     * @dev Only callable by PAUSER_ROLE accounts
     */
    function pause() external onlyRole(PAUSER_ROLE) {
        _pause();
        emit EmergencyPaused(msg.sender);
    }

    /**
     * @notice Unpauses the system to resume operation
     * @dev Only callable by PAUSER_ROLE accounts
     */
    function unpause() external onlyRole(PAUSER_ROLE) {
        _unpause();
        emit EmergencyUnpaused(msg.sender);
    }

    /* ========== VIEW HELPERS ========== */

    /**
     * @notice Checks if a given address holds a specific role
     * @param role The role to check
     * @param account The address to verify
     * @return True if the account has the role, false otherwise
     */
    function hasAccess(
        bytes32 role,
        address account
    ) external view returns (bool) {
        return hasRole(role, account);
    }
}"
    },
    "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

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

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

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

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

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

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

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}
"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

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

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

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

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

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

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        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.
     */
    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.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

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

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

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

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

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}
"
    },
    "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable
    struct PausableStorage {
        bool _paused;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Pausable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;

    function _getPausableStorage() private pure returns (PausableStorage storage $) {
        assembly {
            $.slot := PausableStorageLocation
        }
    }

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

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

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

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

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

    function __Pausable_init() internal onlyInitializing {
    }

    function __Pausable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        PausableStorage storage $ = _getPausableStorage();
        return $._paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

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

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        PausableStorage storage $ = _getPausableStorage();
        $._paused = false;
        emit Unpaused(_msgSender());
    }
}
"
    },
    "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.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].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // 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;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

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

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

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

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

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

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

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

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}
"
    },
    "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

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

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

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

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

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

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

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

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

        _revokeRole(role, callerConfirmation);
    }

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

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Address.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

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

        (bool success, bytes memory returndata) = recipient.call{value: amount}("");
        if (!success) {
            _revert(returndata);
        }
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

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

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

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {\

Tags:
ERC20, ERC165, Multisig, Pausable, Swap, Voting, Upgradeable, Multi-Signature, Factory|addr:0x8b0112e11bb8c41e5bce3863de370b67be5c9ee4|verified:true|block:23477430|tx:0xa6e09641c057b815083927ffa07346240a5488c0b7e826f0e4bf3f03c2070b78|first_check:1759258533

Submitted on: 2025-09-30 20:55:34

Comments

Log in to comment.

No comments yet.