MetaHooks

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",
  "sources": {
    "src/hooks/MetaHooks.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {IHooks, IVault} from "lib/yieldnest-vault/src/interface/IHooks.sol";
import {AccessControl} from "lib/openzeppelin-contracts/contracts/access/AccessControl.sol";
import {IVaultForHooks} from "src/interface/IVaultForHooks.sol";

/**
 * @title MetaHooks
 * @notice MetaHooks is a contract that manages a set of hooks for a vault.
 * @dev It is used to manage the hooks for a vault and to call the hooks in the order set by the setHooks call.
 * @dev Important: Order in which hoos run is of utmost importance. Eg. if a hook verifies the effect of
 * @dev afterProcessAccounting minting fee shares as performed by another hook, it needs to be set *after*
 * @dev the other hook in order to make the check useful.
 * @dev It supports the IHooks interface, in order to be used as a hook for the vault.
 */
contract MetaHooks is IHooks, IVaultForHooks, AccessControl {
    string public constant VERSION = "0.1.0";

    error ZeroVaultAddress();
    error DuplicateInInput(IHooks hook);
    error CallerNotHook(address caller);
    error NotSupported();
    error EmptyHooksArray();
    error TooManyHooks();
    error IndexOutOfBounds();

    event ConfigBitmapUpdated(ConfigBitmap configBitmap, ConfigBitmap newConfigBitmap);
    event SharesMinted(address to, uint256 shares, address caller);
    event HookAdded(IHooks hook);
    event HookRemoved(IHooks hook);

    /**
     * @notice The data of a hook
     * @dev The index of the hook in the hooks array;
     * @dev The active boolean is used to check if the hook is registered, when calling the onlyHook modifier
     */
    struct HookData {
        uint8 index;
        bool active;
    }

    struct ConfigBitmap {
        uint16 beforeDeposit;
        uint16 afterDeposit;
        uint16 beforeMint;
        uint16 afterMint;
        uint16 beforeRedeem;
        uint16 afterRedeem;
        uint16 beforeWithdraw;
        uint16 afterWithdraw;
        uint16 beforeProcessAccounting;
        uint16 afterProcessAccounting;
    }

    /**
     * @notice The vault that the MetaHooks contract is attached to
     */
    IVault public immutable override VAULT;

    /**
     * @notice The array of hooks that are active for this MetaHooks contract
     * @dev The array is used to call the hooks in the correct order
     */
    IHooks[] public hooks;

    /**
     * @notice The mapping of the hooks that are active for each operation
     * @dev The mapping is used to store the index and active status of the hooks
     * @dev The index is used to call the hooks in the correct order
     * @dev The active status is used to check if the hook is active for the operation
     */
    mapping(IHooks => HookData) public hookData;

    /**
     * @notice The bitmap of the hooks that are active for each operation
     * @dev The bitmap is a uint16 where each bit represents a hook
     * @dev The bit is set to 1 if the hook is active for the operation
     * @dev The bit is set to 0 if the hook is not active for the operation
     * @dev The bitmap is used to optimize the check for what hooks to call (single slot read)
     */
    ConfigBitmap private configBitmap;

    /// @notice Role identifier for hook managers.
    bytes32 public constant HOOK_MANAGER_ROLE = keccak256("HOOK_MANAGER_ROLE");

    modifier onlyVault() {
        if (msg.sender != address(VAULT)) revert CallerNotVault();
        _;
    }

    modifier onlyHook() {
        if (!hookData[IHooks(msg.sender)].active) revert CallerNotHook(msg.sender);
        _;
    }

    /**
     * @notice Constructor for the MetaHooks contract
     * @param vault_ The address of the vault to be managed by the MetaHooks contract
     * @param defaultAdmin The address of the default admin
     * @param hookManager The address of the hook manager
     */
    constructor(address vault_, address defaultAdmin, address hookManager) {
        if (vault_ == address(0)) revert ZeroVaultAddress();
        VAULT = IVault(vault_);
        _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);
        _grantRole(HOOK_MANAGER_ROLE, hookManager);
    }

    /// @inheritdoc IHooks
    function name() external pure override returns (string memory) {
        return "MetaHooks";
    }

    /**
     * @notice Sets the array of hooks to be executed by this MetaHooks contract
     * @dev This function replaces all existing hooks with the provided array. Clears existing hook data.
     * @dev Hooks are called IN THE ORDER they are added to the array.
     * @param hooks_ Array of hook contracts to be set. Each hook must implement the IHooks interface.
     */
    function setHooks(IHooks[] memory hooks_) external onlyRole(HOOK_MANAGER_ROLE) {
        // Check if the array is empty
        if (hooks_.length == 0) revert EmptyHooksArray();
        // uint16 can only hold 16 hooks
        if (hooks_.length > 16) revert TooManyHooks();

        // Check for duplicates in hooks_
        for (uint256 i = 0; i < hooks_.length; i++) {
            for (uint256 j = i + 1; j < hooks_.length; j++) {
                if (hooks_[i] == hooks_[j]) revert DuplicateInInput(hooks_[i]);
            }
        }

        // Clear existing hook data mappings
        for (uint256 i = 0; i < hooks.length; i++) {
            delete hookData[hooks[i]];
            emit HookRemoved(hooks[i]);
        }

        // Clear the hooks array before setting new hooks
        delete hooks;

        // add the hooks to the hookData array
        for (uint256 i = 0; i < hooks_.length; i++) {
            hooks.push(hooks_[i]);
            hookData[hooks_[i]] = HookData({index: uint8(i), active: true});
            emit HookAdded(hooks_[i]);
        }

        _syncConfigBitmap();
    }

    /**
     * @notice Syncs the config bitmap for all the hooks
     * @dev This function is used to sync the config bitmap for the hooks, based on the config of each hook
     * @dev Must be called if the getConfig() output of any of the hooks changes.
     * @dev This function is called when the hooks are set
     */
    function syncConfigBitmap() external onlyRole(HOOK_MANAGER_ROLE) {
        _syncConfigBitmap();
    }

    function _syncConfigBitmap() internal {
        ConfigBitmap memory newConfigBitmap;

        IHooks[] memory _hooks = hooks;

        for (uint256 i = 0; i < _hooks.length; i++) {
            IHooks.Config memory config = _hooks[i].getConfig();

            // encode the config of hook at index i into the bitmap of each Hook Type flag
            if (config.beforeDeposit) newConfigBitmap.beforeDeposit = setHook(i, newConfigBitmap.beforeDeposit);

            if (config.afterDeposit) newConfigBitmap.afterDeposit = setHook(i, newConfigBitmap.afterDeposit);

            if (config.beforeMint) newConfigBitmap.beforeMint = setHook(i, newConfigBitmap.beforeMint);

            if (config.afterMint) newConfigBitmap.afterMint = setHook(i, newConfigBitmap.afterMint);

            if (config.beforeRedeem) newConfigBitmap.beforeRedeem = setHook(i, newConfigBitmap.beforeRedeem);

            if (config.afterRedeem) newConfigBitmap.afterRedeem = setHook(i, newConfigBitmap.afterRedeem);

            if (config.beforeWithdraw) newConfigBitmap.beforeWithdraw = setHook(i, newConfigBitmap.beforeWithdraw);

            if (config.afterWithdraw) newConfigBitmap.afterWithdraw = setHook(i, newConfigBitmap.afterWithdraw);

            if (config.beforeProcessAccounting) {
                newConfigBitmap.beforeProcessAccounting = setHook(i, newConfigBitmap.beforeProcessAccounting);
            }

            if (config.afterProcessAccounting) {
                newConfigBitmap.afterProcessAccounting = setHook(i, newConfigBitmap.afterProcessAccounting);
            }
        }

        emit ConfigBitmapUpdated(configBitmap, newConfigBitmap);

        configBitmap = newConfigBitmap;
    }

    /// CONFIG ///

    /// @inheritdoc IHooks
    function setConfig(Config memory) public pure override {
        revert NotSupported();
    }

    /// @inheritdoc IHooks
    function getConfig() public view override returns (Config memory) {
        ConfigBitmap memory bitmap = configBitmap;
        // Convert bitmap values to boolean flags for each hook type
        // Each bitmap field is a uint16 where bits represent which hooks support that operation
        // If any bit is set (bitmap != 0), then at least one hook supports that operation
        return Config({
            beforeDeposit: bitmap.beforeDeposit != 0,
            afterDeposit: bitmap.afterDeposit != 0,
            beforeMint: bitmap.beforeMint != 0,
            afterMint: bitmap.afterMint != 0,
            beforeRedeem: bitmap.beforeRedeem != 0,
            afterRedeem: bitmap.afterRedeem != 0,
            beforeWithdraw: bitmap.beforeWithdraw != 0,
            afterWithdraw: bitmap.afterWithdraw != 0,
            beforeProcessAccounting: bitmap.beforeProcessAccounting != 0,
            afterProcessAccounting: bitmap.afterProcessAccounting != 0
        });
    }

    /**
     * @notice Check if a hook is supported in the bitmap
     * @param index The index of the hook to check
     * @param bitmap The bitmap to check the hook in
     * @return True if the hook is supported, false otherwise
     */
    function supportsHook(uint256 index, uint16 bitmap) public pure returns (bool) {
        if (index >= 16) revert IndexOutOfBounds();
        return (bitmap & (1 << index)) != 0;
    }

    /**
     * @notice Toggle a hook in the bitmap
     * @param index The index of the hook to set
     * @param bitmap The bitmap to set the hook in
     * @return The new bitmap
     */
    function setHook(uint256 index, uint16 bitmap) public pure returns (uint16) {
        if (index >= 16) revert IndexOutOfBounds();
        return bitmap | uint16(1 << index);
    }

    /**
     * @notice Returns the hooks array
     * @return The hooks array
     */
    function getHooks() public view returns (IHooks[] memory) {
        return hooks;
    }

    /**
     * @notice Returns the length of the hooks array
     * @return The length of the hooks array
     */
    function hooksLength() public view returns (uint256) {
        return hooks.length;
    }

    /// HOOKS FUNCTIONS ///

    /// @inheritdoc IHooks
    function beforeDeposit(DepositParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.beforeDeposit;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].beforeDeposit(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function afterDeposit(DepositParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.afterDeposit;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].afterDeposit(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function beforeMint(MintParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.beforeMint;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].beforeMint(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function afterMint(MintParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.afterMint;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].afterMint(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function beforeRedeem(RedeemParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.beforeRedeem;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].beforeRedeem(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function afterRedeem(RedeemParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.afterRedeem;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].afterRedeem(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function beforeWithdraw(WithdrawParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.beforeWithdraw;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].beforeWithdraw(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function afterWithdraw(WithdrawParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.afterWithdraw;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].afterWithdraw(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function beforeProcessAccounting(BeforeProcessAccountingParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.beforeProcessAccounting;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].beforeProcessAccounting(params);
            }
        }
    }

    /// @inheritdoc IHooks
    function afterProcessAccounting(AfterProcessAccountingParams memory params) external override onlyVault {
        uint16 bitmap = configBitmap.afterProcessAccounting;
        if (bitmap == 0) return;

        uint256 _hooksLength = hooks.length;
        for (uint256 i = 0; i < _hooksLength; i++) {
            if (supportsHook(i, bitmap)) {
                hooks[i].afterProcessAccounting(params);
            }
        }
    }

    /// VAULT FUNCTIONS ///

    /**
     * @notice Allows authorized hooks to mint shares directly to a specified address
     * @dev This function acts as a proxy to the vault's mintShares function, restricted to registered hooks
     * @param to The address that will receive the newly minted shares
     * @param shares The number of shares to mint
     */
    function mintShares(address to, uint256 shares) external override onlyHook {
        VAULT.mintShares(to, shares);
        emit SharesMinted(to, shares, msg.sender);
    }

    /**
     * @notice Converts a given amount of assets to the equivalent amount of shares
     * @dev This function acts as a proxy to the vault's convertToShares function
     * @param assets The amount of assets to convert
     * @return The equivalent amount of shares
     */
    function convertToShares(uint256 assets) external view override returns (uint256) {
        return VAULT.convertToShares(assets);
    }

    /**
     * @notice Returns the address of the underlying asset
     * @dev This function acts as a proxy to the vault's asset function
     * @return The address of the underlying asset
     */
    function asset() external view override returns (address) {
        return VAULT.asset();
    }

    /**
     * @notice Calculates the fee on raw assets
     * @dev This function acts as a proxy to the vault's _feeOnRaw function
     * @param amount The amount of assets to calculate the fee for
     * @param caller The address of the caller
     * @return The calculated fee amount
     */
    function _feeOnRaw(uint256 amount, address caller) external view override returns (uint256) {
        return VAULT._feeOnRaw(amount, caller);
    }

    /**
     * @notice Calculates the fee on total shares
     * @dev This function acts as a proxy to the vault's _feeOnTotal function
     * @param amount The amount of shares to calculate the fee for
     * @param caller The address of the caller
     * @return The calculated fee amount
     */
    function _feeOnTotal(uint256 amount, address caller) external view override returns (uint256) {
        return VAULT._feeOnTotal(amount, caller);
    }

    /**
     * @notice Previews the amount of shares that would be received for depositing a specific asset
     * @dev This function acts as a proxy to the vault's previewDepositAsset function
     * @param assetAddress The address of the asset to deposit
     * @param assets The amount of assets to deposit
     * @return The amount of shares that would be received
     */
    function previewDepositAsset(address assetAddress, uint256 assets) external view override returns (uint256) {
        return VAULT.previewDepositAsset(assetAddress, assets);
    }

    /**
     * @notice Converts a given amount of shares to the equivalent amount of assets
     * @dev This function acts as a proxy to the vault's convertToAssets function
     * @param shares The amount of shares to convert
     * @return The equivalent amount of assets
     */
    function convertToAssets(uint256 shares) external view override returns (uint256) {
        return VAULT.convertToAssets(shares);
    }

    /**
     * @notice Returns the total supply of shares
     * @dev This function acts as a proxy to the vault's totalSupply function
     * @return The total supply of shares
     */
    function totalSupply() external view override returns (uint256) {
        return VAULT.totalSupply();
    }

    /**
     * @notice Returns the total amount of assets held by the vault
     * @dev This function acts as a proxy to the vault's totalAssets function
     * @return The total amount of assets
     */
    function totalAssets() external view override returns (uint256) {
        return VAULT.totalAssets();
    }

    /**
     * @notice Returns whether the vault always computes total assets
     * @dev This function acts as a proxy to the vault's alwaysComputeTotalAssets function
     * @return True if the vault always computes total assets, false otherwise
     */
    function alwaysComputeTotalAssets() external view override returns (bool) {
        return VAULT.alwaysComputeTotalAssets();
    }
}
"
    },
    "lib/yieldnest-vault/src/interface/IHooks.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {IVault} from "src/interface/IVault.sol";

interface IHooks {
    /**
     * @notice Parameters for deposit operations
     */
    struct DepositParams {
        address asset;
        uint256 assets;
        address caller;
        address receiver;
        uint256 shares;
        uint256 baseAssets;
    }

    /**
     * @notice Parameters for mint operations
     */
    struct MintParams {
        address asset;
        uint256 shares;
        address caller;
        address receiver;
        uint256 assets;
        uint256 baseAssets;
    }

    /**
     * @notice Parameters for redeem operations
     */
    struct RedeemParams {
        address asset;
        uint256 shares;
        address caller;
        address receiver;
        address owner;
        uint256 assets;
    }

    /**
     * @notice Parameters for withdraw operations
     */
    struct WithdrawParams {
        address asset;
        uint256 assets;
        address caller;
        address receiver;
        address owner;
        uint256 shares;
    }

    /**
     * @notice Parameters for before process accounting operations
     */
    struct BeforeProcessAccountingParams {
        uint256 totalAssetsBeforeAccounting;
        uint256 totalSupplyBeforeAccounting;
        uint256 totalBaseAssetsBeforeAccounting;
    }

    /**
     * @notice Parameters for after process accounting operations
     */
    struct AfterProcessAccountingParams {
        uint256 totalAssetsBeforeAccounting;
        uint256 totalAssetsAfterAccounting;
        uint256 totalSupplyBeforeAccounting;
        uint256 totalSupplyAfterAccounting;
        uint256 totalBaseAssetsBeforeAccounting;
        uint256 totalBaseAssetsAfterAccounting;
    }

    /**
     * @notice Config struct for the hooks
     * @dev Each flag is a boolean value that indicates if the corresponding hook function is enabled for the vault
     * if the flag is true, the hook function must be called by the vault.
     * if the flag is false, the hook function is expected to be a no-op.
     */
    struct Config {
        bool beforeDeposit;
        bool afterDeposit;
        bool beforeMint;
        bool afterMint;
        bool beforeRedeem;
        bool afterRedeem;
        bool beforeWithdraw;
        bool afterWithdraw;
        bool beforeProcessAccounting;
        bool afterProcessAccounting;
    }

    error CallerNotVault();

    /**
     * @notice Returns the name of the hooks module
     * @return The name of the hooks module
     */
    function name() external view returns (string memory);

    /**
     * @notice Returns the vault that the hooks are attached to
     * @return The vault contract interface
     */
    function VAULT() external view returns (IVault);

    /**
     * @notice Sets the hooks configuration
     * @param config_ The configuration struct containing hook permissions
     */
    function setConfig(Config memory config_) external;

    /**
     * @notice Gets the current hooks configuration
     * @return The configuration struct containing hook permissions
     */
    function getConfig() external view returns (Config memory);

    /**
     * @notice Hook called before deposit is processed
     * @param params The deposit parameters
     */
    function beforeDeposit(DepositParams memory params) external;

    /**
     * @notice Hook called after deposit is processed
     * @param params The deposit parameters
     */
    function afterDeposit(DepositParams memory params) external;

    /**
     * @notice Hook called before mint is processed
     * @param params The mint parameters
     */
    function beforeMint(MintParams memory params) external;

    /**
     * @notice Hook called after mint is processed
     * @param params The mint parameters
     */
    function afterMint(MintParams memory params) external;

    /**
     * @notice Hook called before redeem is processed
     * @param params The redeem parameters
     */
    function beforeRedeem(RedeemParams memory params) external;

    /**
     * @notice Hook called after redeem is processed
     * @param params The redeem parameters
     */
    function afterRedeem(RedeemParams memory params) external;

    /**
     * @notice Hook called before withdraw is processed
     * @param params The withdraw parameters
     */
    function beforeWithdraw(WithdrawParams memory params) external;

    /**
     * @notice Hook called after withdraw is processed
     * @param params The withdraw parameters
     */
    function afterWithdraw(WithdrawParams memory params) external;

    /**
     * @notice Hook called before process accounting is executed
     * @param params The before process accounting parameters
     */
    function beforeProcessAccounting(BeforeProcessAccountingParams memory params) external;

    /**
     * @notice Hook called after process accounting is executed
     * @param params The after process accounting parameters
     */
    function afterProcessAccounting(AfterProcessAccountingParams memory params) external;
}
"
    },
    "lib/openzeppelin-contracts/contracts/access/AccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {IERC165, ERC165} from "../utils/introspection/ERC165.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 AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

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

    /// @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) {
        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) {
        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 {
        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) {
        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) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
"
    },
    "src/interface/IVaultForHooks.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

interface IVaultForHooks {
    function mintShares(address to, uint256 shares) external;
    function convertToShares(uint256 assets) external view returns (uint256);
    function asset() external view returns (address);
    function _feeOnRaw(uint256 assets, address caller) external view returns (uint256);
    function _feeOnTotal(uint256 shares, address caller) external view returns (uint256);
    function previewDepositAsset(address assetAddress, uint256 assets) external view returns (uint256);
    function convertToAssets(uint256 shares) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function totalAssets() external view returns (uint256);
    function alwaysComputeTotalAssets() external view returns (bool);
}
"
    },
    "lib/yieldnest-vault/src/interface/IVault.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {IERC4626} from "src/Common.sol";
import {IValidator} from "src/interface/IValidator.sol";
import {IHooks} from "src/interface/IHooks.sol";

interface IVault is IERC4626 {
    struct VaultStorage {
        uint256 totalAssets;
        address provider;
        address buffer;
        bool paused;
        uint8 decimals;
        bool countNativeAsset;
        bool alwaysComputeTotalAssets;
        /// @notice The index of the default asset.
        /// The default asset is vault.asset(), used for deposit, withdraw, redeem, mint as default.
        /// If defaultAssetIndex is 0, the vault will use the base asset as default asset.
        uint256 defaultAssetIndex;
    }

    struct AssetParams {
        uint256 index;
        bool active;
        uint8 decimals;
    }

    struct AssetUpdateFields {
        bool active;
    }

    struct AssetStorage {
        mapping(address => AssetParams) assets;
        address[] list;
    }

    struct OverriddenBaseWithdrawalFeeFields {
        /// @notice The base withdrawal fee in basis points (1e8 = 100%) for the user to override
        uint64 baseWithdrawalFee;
        /// @notice Whether the fee is overridden for the user
        bool isOverridden;
    }

    struct FeeStorage {
        /// @notice The base withdrawal fee in basis points (1e8 = 100%)
        uint64 baseWithdrawalFee;
        mapping(address user => OverriddenBaseWithdrawalFeeFields fields) overriddenBaseWithdrawalFee;
    }

    struct HooksStorage {
        IHooks hooks;
    }

    enum ParamType {
        UINT256,
        ADDRESS
    }

    struct ParamRule {
        ParamType paramType;
        bool isArray;
        address[] allowList;
    }

    struct FunctionRule {
        bool isActive;
        ParamRule[] paramRules;
        IValidator validator;
    }

    struct ProcessorStorage {
        uint256 lastProcessed;
        uint256 lastAccounting;
        mapping(address => mapping(bytes4 => FunctionRule)) rules;
    }

    error Paused();
    error Unpaused();
    error ZeroAddress();
    error ZeroAmount();
    error ZeroRate();
    error InvalidString();
    error InvalidArray();
    error ExceededMaxDeposit(address sender, uint256 amount, uint256 maxAssets);
    error DefaultAsset();
    error AssetNotEmpty(address);
    error InvalidAsset(address);
    error InvalidTarget(address);
    error InvalidDecimals();
    error InvalidFunction(address target, bytes4 funcSig);
    error DuplicateAsset(address asset);
    error ExceededMaxWithdraw(address, uint256, uint256);
    error ExceededMaxRedeem(address, uint256, uint256);
    error ProcessFailed(bytes, bytes);
    error ProcessInvalid(bytes);
    error ProviderNotSet();
    error BufferNotSet();
    error DepositFailed();
    error AssetNotActive();
    error ExceedsMaxBasisPoints(uint256 value);
    error InvalidNativeAssetDecimals(uint256 decimals);
    error InvalidAssetDecimals(uint256 decimals);
    error InvalidDefaultAssetIndex(uint256 index);
    error ExceedsMaxPerformanceFee(uint256 value);
    error BaseAsset();
    error CallerNotHooks();
    error InvalidHooks();

    event DepositAsset(
        address indexed sender,
        address indexed receiver,
        address indexed asset,
        uint256 assets,
        uint256 baseAssets,
        uint256 shares
    );
    event WithdrawAsset(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        address asset,
        uint256 assets,
        uint256 shares
    );

    event SetProvider(address indexed provider);
    event SetBuffer(address indexed buffer);
    event SetAlwaysComputeTotalAssets(bool alwaysComputeTotalAssets);
    event NewAsset(address indexed asset, uint256 decimals, uint256 index);
    event ProcessSuccess(address[] targets, uint256[] values, bytes[] data);
    event Pause(bool paused);
    event SetProcessorRule(address indexed target, bytes4, FunctionRule);
    event NativeDeposit(uint256 amount);
    event ProcessAccounting(uint256 timestamp, uint256 totalAssetsBefore, uint256 totalAssetsAfter);
    event UpdateAsset(uint256 indexed index, address indexed asset, AssetUpdateFields fields);
    event DeleteAsset(uint256 indexed index, address indexed asset);
    event SetBaseWithdrawalFee(uint64 oldFee, uint64 newFee);
    event WithdrawalFeeOverridden(address indexed user, uint64 baseWithdrawalFee, bool isOverridden);
    event SetHooks(address indexed oldHooks, address indexed newHooks);

    // 4626-MAX
    function getAssets() external view returns (address[] memory list);
    function getAsset(address asset_) external view returns (AssetParams memory);
    function hasAsset(address asset_) external view returns (bool);
    function getProcessorRule(address contractAddress, bytes4 funcSig) external view returns (FunctionRule memory);
    function previewDepositAsset(address assetAddress, uint256 assets) external view returns (uint256);
    function depositAsset(address assetAddress, uint256 amount, address receiver) external returns (uint256);
    function provider() external view returns (address);
    function buffer() external view returns (address);
    function totalBaseAssets() external view returns (uint256);
    function computeTotalAssets() external view returns (uint256);
    function alwaysComputeTotalAssets() external view returns (bool);

    // ADMIN
    function setProvider(address provider) external;
    function setBuffer(address buffer) external;
    function setProcessorRule(address target, bytes4 functionSig, FunctionRule memory rule) external;
    function setProcessorRules(address[] memory targets, bytes4[] memory functionSigs, FunctionRule[] memory rules)
        external;
    function addAsset(address asset_, bool active_) external;
    function deleteAsset(uint256 index) external;
    function pause() external;
    function unpause() external;
    function hooks() external view returns (IHooks);
    function setHooks(address hooks) external;
    function mintShares(address recipient, uint256 shares) external;
    function withdrawAsset(address asset_, uint256 assets, address receiver, address owner)
        external
        returns (uint256);

    function processAccounting() external;
    function processor(address[] calldata targets, uint256[] calldata values, bytes[] calldata data)
        external
        returns (bytes[] memory);

    // FEES
    function _feeOnRaw(uint256 amount, address user) external view returns (uint256);
    function _feeOnTotal(uint256 amount, address user) external view returns (uint256);
}
"
    },
    "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)

pragma solidity >=0.8.4;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted to signal this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @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.
     */
    function grantRole(bytes32 role, address account) external;

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

    /**
     * @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 granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
"
    },
    "lib/openzeppelin-contracts/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
"
    },
    "lib/yieldnest-vault/src/Common.sol": {
      "content": "/* solhint-disable no-empty-blocks, no-unused-import */
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

import {AccessControlUpgradeable} from
    "lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
import {Address} from "lib/openzeppelin-contracts/contracts/utils/Address.sol";
import {ERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {ERC20PermitUpgradeable} from
    "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
import {ERC20Upgradeable} from "lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol";
import {IAccessControl} from "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol";
import {IERC20} from "lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import {IERC20Metadata} from "lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol";
import {IERC20Permit} from "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {IERC4626} from "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {Math} from "lib/openzeppelin-contracts/contracts/utils/math/Math.sol";
import {ProxyAdmin} from "lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol";
import {ReentrancyGuardUpgradeable} from
    "lib/openzeppelin-contracts-upgradeable/contracts/utils/ReentrancyGuardUpgradeable.sol";
import {SafeERC20} from "lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {TimelockController} from "lib/openzeppelin-contracts/contracts/governance/TimelockController.sol";
import {
    TransparentUpgradeableProxy,
    ITransparentUpgradeableProxy
} from "lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {IERC165} from "lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol";
import {Initializable} from "lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import {OwnableUpgradeable} from "lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
import {Ownable} from "lib/openzeppelin-contracts/contracts/access/Ownable.sol";

contract Common {}
"
    },
    "lib/yieldnest-vault/src/interface/IValidator.sol": {
      "content": "// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;

interface IValidator {
    /// @notice Validates a transaction before execution
    /// @param target The address the transaction will be sent to
    /// @param value The amount of ETH (in wei) that will be sent with the transaction
    /// @param data The calldata that will be sent with the transaction
    /// @dev This function should revert if the transaction is invalid
    /// @dev This function is called before executing a transaction
    function validate(address target, uint256 value, bytes calldata data) external view;
}
"
    },
    "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": {
      "content": "// 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);
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/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;
        }
    }
}
"
    },
    "lib/openzeppelin-contracts/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 {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            assembly ("memory-safe") {
                revert(add(returndata, 0x20), mload(returndata))
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts gui

Tags:
ERC20, ERC165, Multisig, Mintable, Pausable, Yield, Voting, Timelock, Upgradeable, Multi-Signature, Factory|addr:0x436e02c1d2719eb79390aa0a52ccd6268267017d|verified:true|block:23594502|tx:0x9caea4da4bac2e7c8e3e44e86adee8e87a1db139a94f91a461e7e645d2a33c6b|first_check:1760690399

Submitted on: 2025-10-17 10:40:00

Comments

Log in to comment.

No comments yet.