HubPeripheryFactory

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/factories/HubPeripheryFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {AccessManagedUpgradeable} from "@openzeppelin/contracts-upgradeable/access/manager/AccessManagedUpgradeable.sol";
import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";

import {IOwnable2Step} from "@makina-core/interfaces/IOwnable2Step.sol";

import {IHubPeripheryFactory} from "../interfaces/IHubPeripheryFactory.sol";
import {IHubPeripheryRegistry} from "../interfaces/IHubPeripheryRegistry.sol";
import {ISecurityModuleReference} from "../interfaces/ISecurityModuleReference.sol";
import {IMachinePeriphery} from "../interfaces/IMachinePeriphery.sol";
import {ISecurityModule} from "../interfaces/ISecurityModule.sol";
import {Errors} from "../libraries/Errors.sol";
import {MakinaPeripheryContext} from "../utils/MakinaPeripheryContext.sol";
import {SMCooldownReceipt} from "../security-module/SMCooldownReceipt.sol";

contract HubPeripheryFactory is AccessManagedUpgradeable, MakinaPeripheryContext, IHubPeripheryFactory {
    /// @custom:storage-location erc7201:makina.storage.HubPeripheryFactory
    struct HubPeripheryFactoryStorage {
        mapping(address depositor => bool isDepositor) _isDepositor;
        mapping(address redeemer => bool isRedeemer) _isRedeemer;
        mapping(address feeManager => bool isFeeManager) _isFeeManager;
        mapping(address securityModule => bool isSecurityModule) _isSecurityModule;
        mapping(address depositor => uint16 implemId) _depositorImplemId;
        mapping(address redeemer => uint16 implemId) _redeemerImplemId;
        mapping(address feeManager => uint16 implemId) _feeManagerImplemId;
    }

    // keccak256(abi.encode(uint256(keccak256("makina.storage.HubPeripheryFactory")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant HubPeripheryFactoryStorageLocation =
        0x6b50a937759edff8a6a5b23fe11eb54a74c1c4f4d159fd3622707013a01a1e00;

    function _getHubPeripheryFactoryStorage() internal pure returns (HubPeripheryFactoryStorage storage $) {
        assembly {
            $.slot := HubPeripheryFactoryStorageLocation
        }
    }

    constructor(address _peripheryRegistry) MakinaPeripheryContext(_peripheryRegistry) {
        _disableInitializers();
    }

    function initialize(address _initialAuthority) external initializer {
        __AccessManaged_init(_initialAuthority);
    }

    /// @inheritdoc IHubPeripheryFactory
    function isDepositor(address _depositor) external view override returns (bool) {
        return _getHubPeripheryFactoryStorage()._isDepositor[_depositor];
    }

    /// @inheritdoc IHubPeripheryFactory
    function isRedeemer(address _redeemer) external view override returns (bool) {
        return _getHubPeripheryFactoryStorage()._isRedeemer[_redeemer];
    }

    /// @inheritdoc IHubPeripheryFactory
    function isFeeManager(address _feeManager) external view override returns (bool) {
        return _getHubPeripheryFactoryStorage()._isFeeManager[_feeManager];
    }

    /// @inheritdoc IHubPeripheryFactory
    function isSecurityModule(address _securityModule) external view override returns (bool) {
        return _getHubPeripheryFactoryStorage()._isSecurityModule[_securityModule];
    }

    /// @inheritdoc IHubPeripheryFactory
    function depositorImplemId(address _depositor) external view override returns (uint16) {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();
        if (!$._isDepositor[_depositor]) {
            revert Errors.NotDepositor();
        }
        return $._depositorImplemId[_depositor];
    }

    /// @inheritdoc IHubPeripheryFactory
    function redeemerImplemId(address _redeemer) external view override returns (uint16) {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();
        if (!$._isRedeemer[_redeemer]) {
            revert Errors.NotRedeemer();
        }
        return $._redeemerImplemId[_redeemer];
    }

    /// @inheritdoc IHubPeripheryFactory
    function feeManagerImplemId(address _feeManager) external view override returns (uint16) {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();
        if (!$._isFeeManager[_feeManager]) {
            revert Errors.NotFeeManager();
        }
        return $._feeManagerImplemId[_feeManager];
    }

    /// @inheritdoc IHubPeripheryFactory
    function setMachine(address machinePeriphery, address machine) external override restricted {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();

        if (!$._isDepositor[machinePeriphery] && !$._isRedeemer[machinePeriphery] && !$._isFeeManager[machinePeriphery])
        {
            revert Errors.InvalidMachinePeriphery();
        }

        IMachinePeriphery(machinePeriphery).setMachine(machine);
    }

    /// @inheritdoc IHubPeripheryFactory
    function setSecurityModule(address feeManager, address securityModule) external override restricted {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();

        if (!$._isFeeManager[feeManager]) {
            revert Errors.NotFeeManager();
        }

        if (!$._isSecurityModule[securityModule]) {
            revert Errors.NotSecurityModule();
        }

        ISecurityModuleReference(feeManager).setSecurityModule(securityModule);
    }

    /// @inheritdoc IHubPeripheryFactory
    function createDepositor(uint16 _implemId, bytes calldata _initializationData)
        external
        override
        restricted
        returns (address)
    {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();

        address beacon = IHubPeripheryRegistry(peripheryRegistry).depositorBeacon(_implemId);
        if (beacon == address(0)) {
            revert Errors.InvalidDepositorImplemId();
        }

        address depositor =
            address(new BeaconProxy(beacon, abi.encodeCall(IMachinePeriphery.initialize, (_initializationData))));

        $._isDepositor[depositor] = true;
        $._depositorImplemId[depositor] = _implemId;

        emit DepositorCreated(depositor, _implemId);

        return depositor;
    }

    /// @inheritdoc IHubPeripheryFactory
    function createRedeemer(uint16 _implemId, bytes calldata _initializationData)
        external
        override
        restricted
        returns (address)
    {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();

        address beacon = IHubPeripheryRegistry(peripheryRegistry).redeemerBeacon(_implemId);
        if (beacon == address(0)) {
            revert Errors.InvalidRedeemerImplemId();
        }

        address redeemer =
            address(new BeaconProxy(beacon, abi.encodeCall(IMachinePeriphery.initialize, (_initializationData))));

        $._isRedeemer[redeemer] = true;
        $._redeemerImplemId[redeemer] = _implemId;

        emit RedeemerCreated(redeemer, _implemId);

        return redeemer;
    }

    /// @inheritdoc IHubPeripheryFactory
    function createFeeManager(uint16 _implemId, bytes calldata _initializationData)
        external
        override
        restricted
        returns (address)
    {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();

        address beacon = IHubPeripheryRegistry(peripheryRegistry).feeManagerBeacon(_implemId);
        if (beacon == address(0)) {
            revert Errors.InvalidFeeManagerImplemId();
        }

        address feeManager =
            address(new BeaconProxy(beacon, abi.encodeCall(IMachinePeriphery.initialize, (_initializationData))));

        $._isFeeManager[feeManager] = true;
        $._feeManagerImplemId[feeManager] = _implemId;

        emit FeeManagerCreated(feeManager, _implemId);

        return feeManager;
    }

    /// @inheritdoc IHubPeripheryFactory
    function createSecurityModule(ISecurityModule.SecurityModuleInitParams calldata smParams)
        external
        override
        restricted
        returns (address)
    {
        HubPeripheryFactoryStorage storage $ = _getHubPeripheryFactoryStorage();

        address cooldownReceiptNFT = address(new SMCooldownReceipt(address(this)));
        address securityModule =
            address(new BeaconProxy(IHubPeripheryRegistry(peripheryRegistry).securityModuleBeacon(), ""));

        IOwnable2Step(cooldownReceiptNFT).transferOwnership(securityModule);

        ISecurityModule(securityModule).initialize(abi.encode(smParams, cooldownReceiptNFT));

        $._isSecurityModule[securityModule] = true;

        emit SecurityModuleCreated(securityModule);

        return securityModule;
    }
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/access/manager/AccessManagedUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/AccessManaged.sol)

pragma solidity ^0.8.20;

import {AuthorityUtils} from "@openzeppelin/contracts/access/manager/AuthorityUtils.sol";
import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol";
import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be
 * permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface,
 * implementing a policy that allows certain callers to access certain functions.
 *
 * IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public`
 * functions, and ideally only used in `external` functions. See {restricted}.
 */
abstract contract AccessManagedUpgradeable is Initializable, ContextUpgradeable, IAccessManaged {
    /// @custom:storage-location erc7201:openzeppelin.storage.AccessManaged
    struct AccessManagedStorage {
        address _authority;

        bool _consumingSchedule;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessManaged")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessManagedStorageLocation = 0xf3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00;

    function _getAccessManagedStorage() private pure returns (AccessManagedStorage storage $) {
        assembly {
            $.slot := AccessManagedStorageLocation
        }
    }

    /**
     * @dev Initializes the contract connected to an initial authority.
     */
    function __AccessManaged_init(address initialAuthority) internal onlyInitializing {
        __AccessManaged_init_unchained(initialAuthority);
    }

    function __AccessManaged_init_unchained(address initialAuthority) internal onlyInitializing {
        _setAuthority(initialAuthority);
    }

    /**
     * @dev Restricts access to a function as defined by the connected Authority for this contract and the
     * caller and selector of the function that entered the contract.
     *
     * [IMPORTANT]
     * ====
     * In general, this modifier should only be used on `external` functions. It is okay to use it on `public`
     * functions that are used as external entry points and are not called internally. Unless you know what you're
     * doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security
     * implications! This is because the permissions are determined by the function that entered the contract, i.e. the
     * function at the bottom of the call stack, and not the function where the modifier is visible in the source code.
     * ====
     *
     * [WARNING]
     * ====
     * Avoid adding this modifier to the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`]
     * function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These
     * functions are the only execution paths where a function selector cannot be unambiguously determined from the calldata
     * since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function
     * if no calldata is provided. (See {_checkCanCall}).
     *
     * The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length.
     * ====
     */
    modifier restricted() {
        _checkCanCall(_msgSender(), _msgData());
        _;
    }

    /// @inheritdoc IAccessManaged
    function authority() public view virtual returns (address) {
        AccessManagedStorage storage $ = _getAccessManagedStorage();
        return $._authority;
    }

    /// @inheritdoc IAccessManaged
    function setAuthority(address newAuthority) public virtual {
        address caller = _msgSender();
        if (caller != authority()) {
            revert AccessManagedUnauthorized(caller);
        }
        if (newAuthority.code.length == 0) {
            revert AccessManagedInvalidAuthority(newAuthority);
        }
        _setAuthority(newAuthority);
    }

    /// @inheritdoc IAccessManaged
    function isConsumingScheduledOp() public view returns (bytes4) {
        AccessManagedStorage storage $ = _getAccessManagedStorage();
        return $._consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0);
    }

    /**
     * @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the
     * permissions set by the current authority.
     */
    function _setAuthority(address newAuthority) internal virtual {
        AccessManagedStorage storage $ = _getAccessManagedStorage();
        $._authority = newAuthority;
        emit AuthorityUpdated(newAuthority);
    }

    /**
     * @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata
     * is less than 4 bytes long.
     */
    function _checkCanCall(address caller, bytes calldata data) internal virtual {
        AccessManagedStorage storage $ = _getAccessManagedStorage();
        (bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay(
            authority(),
            caller,
            address(this),
            bytes4(data[0:4])
        );
        if (!immediate) {
            if (delay > 0) {
                $._consumingSchedule = true;
                IAccessManager(authority()).consumeScheduledOp(caller, data);
                $._consumingSchedule = false;
            } else {
                revert AccessManagedUnauthorized(caller);
            }
        }
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/beacon/BeaconProxy.sol)

pragma solidity ^0.8.22;

import {IBeacon} from "./IBeacon.sol";
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";

/**
 * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
 *
 * The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an
 * immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by
 * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] so that it can be accessed externally.
 *
 * CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust
 * the beacon to not upgrade the implementation maliciously.
 *
 * IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in
 * an inconsistent state where the beacon storage slot does not match the beacon address.
 */
contract BeaconProxy is Proxy {
    // An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call.
    address private immutable _beacon;

    /**
     * @dev Initializes the proxy with `beacon`.
     *
     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
     * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
     * constructor.
     *
     * Requirements:
     *
     * - `beacon` must be a contract with the interface {IBeacon}.
     * - If `data` is empty, `msg.value` must be zero.
     */
    constructor(address beacon, bytes memory data) payable {
        ERC1967Utils.upgradeBeaconToAndCall(beacon, data);
        _beacon = beacon;
    }

    /**
     * @dev Returns the current implementation address of the associated beacon.
     */
    function _implementation() internal view virtual override returns (address) {
        return IBeacon(_getBeacon()).implementation();
    }

    /**
     * @dev Returns the beacon.
     */
    function _getBeacon() internal view virtual returns (address) {
        return _beacon;
    }
}
"
    },
    "lib/makina-core/src/interfaces/IOwnable2Step.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IOwnable2Step {
    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function transferOwnership(address newOwner) external;
    function acceptOwnership() external;
}
"
    },
    "src/interfaces/IHubPeripheryFactory.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {ISecurityModule} from "../interfaces/ISecurityModule.sol";

interface IHubPeripheryFactory {
    event DepositorCreated(address indexed depositor, uint16 indexed implemId);
    event RedeemerCreated(address indexed redeemer, uint16 indexed implemId);
    event FeeManagerCreated(address indexed feeManager, uint16 indexed implemId);
    event SecurityModuleCreated(address indexed securityModule);

    /// @notice Address => Whether this is a depositor deployed by this factory
    function isDepositor(address depositor) external view returns (bool);

    /// @notice Address => Whether this is a redeemer deployed by this factory
    function isRedeemer(address redeemer) external view returns (bool);

    /// @notice Address => Whether this is a fee manager deployed by this factory
    function isFeeManager(address feeManager) external view returns (bool);

    /// @notice Address => Whether this is a security module deployed by this factory
    function isSecurityModule(address securityModule) external view returns (bool);

    /// @notice Depositor => Implementation ID
    function depositorImplemId(address depositor) external view returns (uint16);

    /// @notice Redeemer => Implementation ID
    function redeemerImplemId(address redeemer) external view returns (uint16);

    /// @notice Fee manager => Implementation ID
    function feeManagerImplemId(address feeManager) external view returns (uint16);

    /// @notice Sets the machine address in the machine periphery contract.
    /// @param machinePeriphery The address of the machine periphery contract.
    /// @param machine The address of the machine to be set.
    function setMachine(address machinePeriphery, address machine) external;

    /// @notice Sets the security module address in the fee manager contract.
    /// @param feeManager The address of the fee manager contract.
    /// @param securityModule The address of the security module to be set.
    function setSecurityModule(address feeManager, address securityModule) external;

    /// @notice Creates a new machine depositor using the specified implementation ID.
    /// @param implemId The ID of the depositor implementation to be used.
    /// @param initializationData Additional initialization data.
    /// @return depositor The address of the newly created depositor.
    function createDepositor(uint16 implemId, bytes calldata initializationData) external returns (address depositor);

    /// @notice Creates a new machine redeemer using the specified implementation ID.
    /// @param implemId The ID of the redeemer implementation to be used.
    /// @param initializationData Additional initialization data.
    /// @return redeemer The address of the newly created redeemer.
    function createRedeemer(uint16 implemId, bytes calldata initializationData) external returns (address redeemer);

    /// @notice Creates a new machine fee manager using the specified implementation ID.
    /// @param implemId The ID of the fee manager implementation to be used.
    /// @param initializationData Additional initialization data.
    /// @return feeManager The address of the newly created fee manager.
    function createFeeManager(uint16 implemId, bytes calldata initializationData)
        external
        returns (address feeManager);

    /// @notice Creates a new security module.
    /// @param smParams The security module initialization parameters.
    /// @return securityModule The address of the newly created security module.
    function createSecurityModule(ISecurityModule.SecurityModuleInitParams calldata smParams)
        external
        returns (address securityModule);
}
"
    },
    "src/interfaces/IHubPeripheryRegistry.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IHubPeripheryRegistry {
    event DepositorBeaconChanged(
        uint16 indexed implemId, address indexed oldDepositorBeacon, address indexed newDepositorBeacon
    );
    event FeeManagerBeaconChanged(
        uint16 indexed implemId, address indexed oldFeeManagerBeacon, address indexed newFeeManagerBeacon
    );
    event PeripheryFactoryChanged(address indexed oldPeripheryFactory, address indexed newPeripheryFactory);
    event RedeemerBeaconChanged(
        uint16 indexed implemId, address indexed oldRedeemerBeacon, address indexed newRedeemerBeacon
    );
    event SecurityModuleBeaconChanged(address indexed oldSecurityModuleBeacon, address indexed newSecurityModuleBeacon);

    /// @notice Address of the periphery factory.
    function peripheryFactory() external view returns (address);

    /// @notice Implementation ID => Address of the depositor beacon
    function depositorBeacon(uint16 implemId) external view returns (address);

    /// @notice Implementation ID => Address of the redeemer beacon
    function redeemerBeacon(uint16 implemId) external view returns (address);

    /// @notice Implementation ID => Address of the fee manager beacon
    function feeManagerBeacon(uint16 implemId) external view returns (address);

    /// @notice Address of the security module beacon.
    function securityModuleBeacon() external view returns (address);

    /// @notice Sets the address of the periphery factory.
    /// @param _peripheryFactory The periphery factory address.
    function setPeripheryFactory(address _peripheryFactory) external;

    /// @notice Sets the beacon address for the depositor implementation.
    /// @param implemId The ID of the machine depositor implementation.
    /// @param _depositorBeacon The machine depositor beacon address.
    function setDepositorBeacon(uint16 implemId, address _depositorBeacon) external;

    /// @notice Sets the beacon address for the redeemer implementation.
    /// @param implemId The ID of the redeemer implementation.
    /// @param _redeemerBeacon The machine redeemer beacon address.
    function setRedeemerBeacon(uint16 implemId, address _redeemerBeacon) external;

    /// @notice Sets the beacon address for the fee manager implementation.
    /// @param implemId The ID of the fee manager implementation.
    /// @param _feeManagerBeacon The fee manager beacon address.
    function setFeeManagerBeacon(uint16 implemId, address _feeManagerBeacon) external;

    /// @notice Sets the security module beacon address.
    /// @param _securityModuleBeacon The security module beacon address.
    function setSecurityModuleBeacon(address _securityModuleBeacon) external;
}
"
    },
    "src/interfaces/ISecurityModuleReference.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface ISecurityModuleReference {
    /// @notice Security module address.
    function securityModule() external view returns (address);

    /// @notice Sets the security module address.
    /// @param securityModule The address of the security module.
    function setSecurityModule(address securityModule) external;
}
"
    },
    "src/interfaces/IMachinePeriphery.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

interface IMachinePeriphery {
    event MachineSet(address indexed machine);

    /// @notice Initializer of the contract.
    /// @param _data The initialization data, if any.
    function initialize(bytes calldata _data) external;

    /// @notice Address of the associated machine.
    function machine() external view returns (address);

    /// @notice Sets the machine address.
    function setMachine(address _machine) external;
}
"
    },
    "src/interfaces/ISecurityModule.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import {IMachinePeriphery} from "../interfaces/IMachinePeriphery.sol";

interface ISecurityModule is IERC20Metadata, IMachinePeriphery {
    event Cooldown(
        uint256 indexed cooldownId, address indexed account, address indexed receiver, uint256 shares, uint256 maturity
    );
    event CooldownCancelled(uint256 indexed cooldownId, address indexed receiver, uint256 shares);
    event CooldownDurationChanged(uint256 oldCooldownDuration, uint256 newCooldownDuration);
    event MaxSlashableBpsChanged(uint256 oldMaxSlashableBps, uint256 newMaxSlashableBps);
    event MinBalanceAfterSlashChanged(uint256 oldMinBalanceAfterSlash, uint256 newMinBalanceAfterSlash);
    event Lock(address indexed account, address indexed receiver, uint256 assets, uint256 shares);
    event Redeem(uint256 indexed cooldownId, address indexed receiver, uint256 assets, uint256 shares);
    event Slash(uint256 amount);
    event SlashingSettled();

    /// @notice Initialization parameters.
    /// @param machineShare Address of the machine share token locked in this contract.
    /// @param initialCooldownDuration Cooldown duration in seconds for unlocking.
    /// @param initialMaxSlashableBps Maximum slashable proportion of the vault balance in basis points.
    /// @param minBalanceAfterSlash Minimum balance that must remain in the vault after a slash.
    struct SecurityModuleInitParams {
        address machineShare;
        uint256 initialCooldownDuration;
        uint256 initialMaxSlashableBps;
        uint256 initialMinBalanceAfterSlash;
    }

    /// @notice Pending cooldown parameters.
    /// @param shares Amount of security shares to be redeemed.
    /// @param maxAssets Maximum amount of machine shares that can be redeemed.
    /// @param maturity Timestamp at which the cooldown period will end and the shares can be redeemed.
    struct PendingCooldown {
        uint256 shares;
        uint256 maxAssets;
        uint256 maturity;
    }

    /// @notice Address of the machine share token locked in this contract.
    function machineShare() external view returns (address);

    /// @notice Address of the cooldown receipt NFT.
    function cooldownReceipt() external view returns (address);

    /// @notice Cooldown duration in seconds for unlocking.
    function cooldownDuration() external view returns (uint256);

    /// @notice Maximum slashable proportion of the vault balance in basis points.
    function maxSlashableBps() external view returns (uint256);

    /// @notice Minimum balance that must remain in the vault after a slash.
    function minBalanceAfterSlash() external view returns (uint256);

    /// @notice Returns data of a pending cooldown.
    /// @param cooldownId ID of the cooldown receipt NFT representing the pending cooldown.
    /// @return shares Amount of security shares to be redeemed.
    /// @return currentExpectedAssets Current expected amount of machine shares that can be redeemed.
    /// @return maturity Timestamp at which the cooldown period will end and the shares can be redeemed.
    function pendingCooldown(uint256 cooldownId)
        external
        view
        returns (uint256 shares, uint256 currentExpectedAssets, uint256 maturity);

    /// @notice Whether the security module is in slashing mode.
    function slashingMode() external view returns (bool);

    /// @notice Total amount of machine shares locked in the module.
    function totalLockedAmount() external view returns (uint256);

    /// @notice Total amount of machine shares currently slashable in the module.
    function maxSlashable() external view returns (uint256);

    /// @notice Converts machine shares to security shares.
    /// @param assets Amount of machine shares to convert.
    /// @return shares Amount of security shares corresponding to the input machine shares.
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /// @notice Converts security shares to machine shares.
    /// @param shares Amount of security shares to convert.
    /// @return assets Amount of machine shares corresponding to the input security shares.
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /// @notice Estimates the amount of security shares that would be received for a given amount of machine shares.
    /// @param assets Amount of machine shares to convert.
    /// @return shares Estimated amount of security shares corresponding to the input machine shares.
    function previewLock(uint256 assets) external view returns (uint256 shares);

    /// @notice Locks machine shares in the module and mints security shares.
    /// @param assets Amount of machine shares to lock.
    /// @param receiver Address that will receive the security shares.
    /// @param minShares Minimum amount of security shares to receive.
    /// @return shares Amount of security shares minted.
    function lock(uint256 assets, address receiver, uint256 minShares) external returns (uint256 shares);

    /// @notice Requests a cooldown for redeeming security shares.
    ///         Shares are locked in the contract until the cooldown is cancelled or expires.
    ///         A cooldown receipt NFT is minted to the specified receiver address.
    /// @param shares Amount of security shares to redeem.
    /// @param receiver Address that will receive the cooldown receipt.
    /// @return cooldownId ID of the minted cooldown receipt NFT representing the pending cooldown.
    /// @return maxAssets Maximum amount of machine shares that can be redeemed.
    /// @return maturity Timestamp at which the cooldown period will end and the shares can be redeemed.
    function startCooldown(uint256 shares, address receiver)
        external
        returns (uint256 cooldownId, uint256 maxAssets, uint256 maturity);

    /// @notice Cancels a pending cooldown.
    ///         Shares for which the cooldown was cancelled are transferred back to caller.
    ///         The associated cooldown receipt NFT is burned.
    /// @param cooldownId ID of the cooldown receipt NFT representing the pending cooldown.
    /// @return shares Amount of security shares for which the cooldown was cancelled.
    function cancelCooldown(uint256 cooldownId) external returns (uint256 shares);

    /// @notice Redeems security shares and transfers machine shares to caller.
    /// @param cooldownId ID of the cooldown receipt NFT representing the pending cooldown.
    /// @param minAssets Minimum amount of machine shares to receive.
    /// @return assets Amount of machine shares transferred to the receiver.
    function redeem(uint256 cooldownId, uint256 minAssets) external returns (uint256 assets);

    /// @notice Slashes a specified amount from the total locked amount and triggers the slashing mode.
    /// @param amount Amount to slash from the total locked amount.
    function slash(uint256 amount) external;

    /// @notice Settles the current slashing, allowing the contract to exit slashing mode and resume normal operations.
    function settleSlashing() external;

    /// @notice Sets the cooldown duration for unlocking.
    /// @param cooldownDuration New cooldown duration in seconds.
    function setCooldownDuration(uint256 cooldownDuration) external;

    /// @notice Sets the maximum slashable proportion of the vault balance in basis points.
    /// @param maxSlashableBps New maximum slashable proportion in basis points.
    function setMaxSlashableBps(uint256 maxSlashableBps) external;

    /// @notice Sets the minimum balance that must remain in the vault after a slash.
    /// @param minBalanceAfterSlash New minimum balance after slash.
    function setMinBalanceAfterSlash(uint256 minBalanceAfterSlash) external;
}
"
    },
    "src/libraries/Errors.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {Errors as CoreErrors} from "@makina-core/libraries/Errors.sol";

library Errors {
    error AlreadyClaimed();
    error AlreadyFinalized();
    error CooldownExpired();
    error CooldownOngoing();
    error FinalizationDelayPending();
    error FutureRequest();
    error GreaterThanCurrentWatermark();
    error InvalidDepositorImplemId();
    error InvalidFeeManagerImplemId();
    error InvalidFeeSplit();
    error InvalidMachinePeriphery();
    error InvalidRedeemerImplemId();
    error InvalidSecurityModule();
    error MachineAlreadySet();
    error MachineNotSet();
    error MaxBpsValueExceeded();
    error MaxFeeRateValueExceeded();
    error MaxSlashableExceeded();
    error NotDepositor();
    error NotEnoughAssets();
    error NotFeeManager();
    error NotFinalized();
    error NotImplemented();
    error NotRedeemer();
    error NotSecurityModule();
    error SecurityModuleAlreadySet();
    error SlashingSettlementOngoing();
    error ZeroMachineAddress();
    error ZeroRequestId();
    error ZeroShares();
}
"
    },
    "src/utils/MakinaPeripheryContext.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {IMakinaPeripheryContext} from "../interfaces/IMakinaPeripheryContext.sol";

abstract contract MakinaPeripheryContext is IMakinaPeripheryContext {
    /// @inheritdoc IMakinaPeripheryContext
    address public immutable override peripheryRegistry;

    constructor(address _peripheryRegistry) {
        peripheryRegistry = _peripheryRegistry;
    }
}
"
    },
    "src/security-module/SMCooldownReceipt.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";

import {ISMCooldownReceipt} from "../interfaces/ISMCooldownReceipt.sol";

contract SMCooldownReceipt is ERC721, Ownable2Step, ISMCooldownReceipt {
    /// @inheritdoc ISMCooldownReceipt
    uint256 public nextTokenId;

    constructor(address _initialMinter)
        ERC721("Makina Security Module Cooldown NFT", "MakinaSMCooldownNFT")
        Ownable(_initialMinter)
    {
        nextTokenId = 1;
    }

    /// @inheritdoc ISMCooldownReceipt
    function mint(address to) external onlyOwner returns (uint256) {
        uint256 tokenId = nextTokenId++;
        _safeMint(to, tokenId);
        return tokenId;
    }

    /// @inheritdoc ISMCooldownReceipt
    function burn(uint256 tokenId) external onlyOwner {
        _burn(tokenId);
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/manager/AuthorityUtils.sol)

pragma solidity ^0.8.20;

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

library AuthorityUtils {
    /**
     * @dev Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility
     * for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data.
     * This helper function takes care of invoking `canCall` in a backwards compatible way without reverting.
     */
    function canCallWithDelay(
        address authority,
        address caller,
        address target,
        bytes4 selector
    ) internal view returns (bool immediate, uint32 delay) {
        bytes memory data = abi.encodeCall(IAuthority.canCall, (caller, target, selector));

        assembly ("memory-safe") {
            mstore(0x00, 0x00)
            mstore(0x20, 0x00)

            if staticcall(gas(), authority, add(data, 0x20), mload(data), 0x00, 0x40) {
                immediate := mload(0x00)
                delay := mload(0x20)

                // If delay does not fit in a uint32, return 0 (no delay)
                // equivalent to: if gt(delay, 0xFFFFFFFF) { delay := 0 }
                delay := mul(delay, iszero(shr(32, delay)))
            }
        }
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/manager/IAccessManager.sol)

pragma solidity ^0.8.20;

interface IAccessManager {
    /**
     * @dev A delayed operation was scheduled.
     */
    event OperationScheduled(
        bytes32 indexed operationId,
        uint32 indexed nonce,
        uint48 schedule,
        address caller,
        address target,
        bytes data
    );

    /**
     * @dev A scheduled operation was executed.
     */
    event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce);

    /**
     * @dev A scheduled operation was canceled.
     */
    event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce);

    /**
     * @dev Informational labelling for a roleId.
     */
    event RoleLabel(uint64 indexed roleId, string label);

    /**
     * @dev Emitted when `account` is granted `roleId`.
     *
     * NOTE: The meaning of the `since` argument depends on the `newMember` argument.
     * If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role,
     * otherwise it indicates the execution delay for this account and roleId is updated.
     */
    event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember);

    /**
     * @dev Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous.
     */
    event RoleRevoked(uint64 indexed roleId, address indexed account);

    /**
     * @dev Role acting as admin over a given `roleId` is updated.
     */
    event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin);

    /**
     * @dev Role acting as guardian over a given `roleId` is updated.
     */
    event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian);

    /**
     * @dev Grant delay for a given `roleId` will be updated to `delay` when `since` is reached.
     */
    event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since);

    /**
     * @dev Target mode is updated (true = closed, false = open).
     */
    event TargetClosed(address indexed target, bool closed);

    /**
     * @dev Role required to invoke `selector` on `target` is updated to `roleId`.
     */
    event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId);

    /**
     * @dev Admin delay for a given `target` will be updated to `delay` when `since` is reached.
     */
    event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since);

    error AccessManagerAlreadyScheduled(bytes32 operationId);
    error AccessManagerNotScheduled(bytes32 operationId);
    error AccessManagerNotReady(bytes32 operationId);
    error AccessManagerExpired(bytes32 operationId);
    error AccessManagerLockedRole(uint64 roleId);
    error AccessManagerBadConfirmation();
    error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId);
    error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector);
    error AccessManagerUnauthorizedConsume(address target);
    error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector);
    error AccessManagerInvalidInitialAdmin(address initialAdmin);

    /**
     * @dev Check if an address (`caller`) is authorised to call a given function on a given contract directly (with
     * no restriction). Additionally, it returns the delay needed to perform the call indirectly through the {schedule}
     * & {execute} workflow.
     *
     * This function is usually called by the targeted contract to control immediate execution of restricted functions.
     * Therefore we only return true if the call can be performed without any delay. If the call is subject to a
     * previously set delay (not zero), then the function should return false and the caller should schedule the operation
     * for future execution.
     *
     * If `immediate` is true, the delay can be disregarded and the operation can be immediately executed, otherwise
     * the operation can be executed if and only if delay is greater than 0.
     *
     * NOTE: The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that
     * is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail
     * to identify the indirect workflow, and will consider calls that require a delay to be forbidden.
     *
     * NOTE: This function does not report the permissions of the admin functions in the manager itself. These are defined by the
     * {AccessManager} documentation.
     */
    function canCall(
        address caller,
        address target,
        bytes4 selector
    ) external view returns (bool allowed, uint32 delay);

    /**
     * @dev Expiration delay for scheduled proposals. Defaults to 1 week.
     *
     * IMPORTANT: Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately,
     * disabling any scheduling usage.
     */
    function expiration() external view returns (uint32);

    /**
     * @dev Minimum setback for all delay updates, with the exception of execution delays. It
     * can be increased without setback (and reset via {revokeRole} in the case event of an
     * accidental increase). Defaults to 5 days.
     */
    function minSetback() external view returns (uint32);

    /**
     * @dev Get whether the contract is closed disabling any access. Otherwise role permissions are applied.
     *
     * NOTE: When the manager itself is closed, admin functions are still accessible to avoid locking the contract.
     */
    function isTargetClosed(address target) external view returns (bool);

    /**
     * @dev Get the role required to call a function.
     */
    function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64);

    /**
     * @dev Get the admin delay for a target contract. Changes to contract configuration are subject to this delay.
     */
    function getTargetAdminDelay(address target) external view returns (uint32);

    /**
     * @dev Get the id of the role that acts as an admin for the given role.
     *
     * The admin permission is required to grant the role, revoke the role and update the execution delay to execute
     * an operation that is restricted to this role.
     */
    function getRoleAdmin(uint64 roleId) external view returns (uint64);

    /**
     * @dev Get the role that acts as a guardian for a given role.
     *
     * The guardian permission allows canceling operations that have been scheduled under the role.
     */
    function getRoleGuardian(uint64 roleId) external view returns (uint64);

    /**
     * @dev Get the role current grant delay.
     *
     * Its value may change at any point without an event emitted following a call to {setGrantDelay}.
     * Changes to this value, including effect timepoint are notified in advance by the {RoleGrantDelayChanged} event.
     */
    function getRoleGrantDelay(uint64 roleId) external view returns (uint32);

    /**
     * @dev Get the access details for a given account for a given role. These details include the timepoint at which
     * membership becomes active, and the delay applied to all operation by this user that requires this permission
     * level.
     *
     * Returns:
     * [0] Timestamp at which the account membership becomes valid. 0 means role is not granted.
     * [1] Current execution delay for the account.
     * [2] Pending execution delay for the account.
     * [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled.
     */
    function getAccess(
        uint64 roleId,
        address account
    ) external view returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect);

    /**
     * @dev Check if a given account currently has the permission level corresponding to a given role. Note that this
     * permission might be associated with an execution delay. {getAccess} can provide more details.
     */
    function hasRole(uint64 roleId, address account) external view returns (bool isMember, uint32 executionDelay);

    /**
     * @dev Give a label to a role, for improved role discoverability by UIs.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {RoleLabel} event.
     */
    function labelRole(uint64 roleId, string calldata label) external;

    /**
     * @dev Add `account` to `roleId`, or change its execution delay.
     *
     * This gives the account the authorization to call any function that is restricted to this role. An optional
     * execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation
     * that is restricted to members of this role. The user will only be able to execute the operation after the delay has
     * passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}).
     *
     * If the account has already been granted this role, the execution delay will be updated. This update is not
     * immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is
     * called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any
     * operation executed in the 3 hours that follows this update was indeed scheduled before this update.
     *
     * Requirements:
     *
     * - the caller must be an admin for the role (see {getRoleAdmin})
     * - granted role must not be the `PUBLIC_ROLE`
     *
     * Emits a {RoleGranted} event.
     */
    function grantRole(uint64 roleId, address account, uint32 executionDelay) external;

    /**
     * @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has
     * no effect.
     *
     * Requirements:
     *
     * - the caller must be an admin for the role (see {getRoleAdmin})
     * - revoked role must not be the `PUBLIC_ROLE`
     *
     * Emits a {RoleRevoked} event if the account had the role.
     */
    function revokeRole(uint64 roleId, address account) external;

    /**
     * @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in
     * the role this call has no effect.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * Emits a {RoleRevoked} event if the account had the role.
     */
    function renounceRole(uint64 roleId, address callerConfirmation) external;

    /**
     * @dev Change admin role for a given role.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {RoleAdminChanged} event
     */
    function setRoleAdmin(uint64 roleId, uint64 admin) external;

    /**
     * @dev Change guardian role for a given role.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {RoleGuardianChanged} event
     */
    function setRoleGuardian(uint64 roleId, uint64 guardian) external;

    /**
     * @dev Update the delay for granting a `roleId`.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {RoleGrantDelayChanged} event.
     */
    function setGrantDelay(uint64 roleId, uint32 newDelay) external;

    /**
     * @dev Set the role required to call functions identified by the `selectors` in the `target` contract.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {TargetFunctionRoleUpdated} event per selector.
     */
    function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external;

    /**
     * @dev Set the delay for changing the configuration of a given target contract.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {TargetAdminDelayUpdated} event.
     */
    function setTargetAdminDelay(address target, uint32 newDelay) external;

    /**
     * @dev Set the closed flag for a contract.
     *
     * Closing the manager itself won't disable access to admin methods to avoid locking the contract.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     *
     * Emits a {TargetClosed} event.
     */
    function setTargetClosed(address target, bool closed) external;

    /**
     * @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the
     * operation is not yet scheduled, has expired, was executed, or was canceled.
     */
    function getSchedule(bytes32 id) external view returns (uint48);

    /**
     * @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never
     * been scheduled.
     */
    function getNonce(bytes32 id) external view returns (uint32);

    /**
     * @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to
     * choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays
     * required for the caller. The special value zero will automatically set the earliest possible time.
     *
     * Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when
     * the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this
     * scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}.
     *
     * Emits a {OperationScheduled} event.
     *
     * NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If
     * this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target
     * contract if it is using standard Solidity ABI encoding.
     */
    function schedule(
        address target,
        bytes calldata data,
        uint48 when
    ) external returns (bytes32 operationId, uint32 nonce);

    /**
     * @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the
     * execution delay is 0.
     *
     * Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the
     * operation wasn't previously scheduled (if the caller doesn't have an execution delay).
     *
     * Emits an {OperationExecuted} event only if the call was scheduled and delayed.
     */
    function execute(address target, bytes calldata data) external payable returns (uint32);

    /**
     * @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled
     * operation that is cancelled.
     *
     * Requirements:
     *
     * - the caller must be the proposer, a guardian of the targeted function, or a global admin
     *
     * Emits a {OperationCanceled} event.
     */
    function cancel(address caller, address target, bytes calldata data) external returns (uint32);

    /**
     * @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed
     * (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error.
     *
     * This is useful for contract that want to enforce that calls targeting them were scheduled on the manager,
     * with all the verifications that it implies.
     *
     * Emit a {OperationExecuted} event.
     */
    function consumeScheduledOp(address caller, bytes calldata data) external;

    /**
     * @dev Hashing function for delayed operations.
     */
    function hashOperation(address caller, address target, bytes calldata data) external view returns (bytes32);

    /**
     * @dev Changes the authority of a target managed by this manager instance.
     *
     * Requirements:
     *
     * - the caller must be a global admin
     */
    function updateAuthority(address target, address newAuthority) external;
}
"
    },
    "lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManaged.sol)

pragma solidity ^0.8.20;

interface IAccessManaged {
    /**
     * @dev Authority that manages this contract was updated.
     */
    event AuthorityUpdated(address authority);

    error AccessManagedUnauthorized(address caller);
    error AccessManagedRequiredDelay(address caller, uint32 delay);
    error AccessManagedInvalidAuthority(address authority);

    /**
     * @dev Returns the current authority.
     */
    function authority() external view returns (address);

    /**
     * @dev Transfers control to a new authority. The caller must be the current authority.
     */
    function setAuthority(address) external;

    /**
     * @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is
     * being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs
     * attacker controlled calls.
     */
    function isConsumingScheduledOp() external view returns (bytes4);
}
"
    },
    "lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    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-upgradeable/contracts/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.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 reinitialization) 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 initi

Tags:
ERC20, ERC721, ERC165, Multisig, Mintable, Burnable, Non-Fungible, Swap, Voting, Upgradeable, Multi-Signature, Factory|addr:0xddf27777c92321d3aa3b65ea096a5e14932e7214|verified:true|block:23383291|tx:0x117559bb839ebc6e8dc949366c7a8dc26d258ebcfb1fa9d61cfaac65088ceb6a|first_check:1758121824

Submitted on: 2025-09-17 17:10:25

Comments

Log in to comment.

No comments yet.