// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @title PluginRegistry * @notice Central registry for all pluggable components * @dev Enables adding new asset types, liquidity providers, compliance modules without redeployment */ contract PluginRegistry is Initializable, AccessControlUpgradeable, UUPSUpgradeable { bytes32 public constant PLUGIN_ADMIN_ROLE = keccak256("PLUGIN_ADMIN_ROLE"); bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); enum PluginType { AssetTypeHandler, LiquidityProvider, ComplianceModule, OracleProvider, VaultStrategy } struct Plugin { address implementation; string version; bool active; uint256 registeredAt; string description; } // Storage mapping(PluginType => mapping(bytes32 => Plugin)) public plugins; mapping(PluginType => bytes32[]) public pluginsByType; // Plugin metadata mapping(address => bool) public isRegisteredPlugin; mapping(PluginType => uint256) public pluginCount; event PluginRegistered( PluginType indexed pluginType, bytes32 indexed identifier, address implementation, string version ); event PluginActivated(PluginType indexed pluginType, bytes32 indexed identifier); event PluginDeactivated(PluginType indexed pluginType, bytes32 indexed identifier); event PluginUpgraded( PluginType indexed pluginType, bytes32 indexed identifier, address oldImplementation, address newImplementation ); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address admin) external initializer { __AccessControl_init(); __UUPSUpgradeable_init(); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(PLUGIN_ADMIN_ROLE, admin); _grantRole(UPGRADER_ROLE, admin); } function _authorizeUpgrade(address newImplementation) internal override onlyRole(UPGRADER_ROLE) {} /** * @notice Register new plugin */ function registerPlugin( PluginType pluginType, bytes32 identifier, address implementation, string calldata version, string calldata description ) external onlyRole(PLUGIN_ADMIN_ROLE) { require(implementation != address(0), "Zero address"); require(implementation.code.length > 0, "Not a contract"); require(plugins[pluginType][identifier].implementation == address(0), "Already registered"); plugins[pluginType][identifier] = Plugin({ implementation: implementation, version: version, active: true, registeredAt: block.timestamp, description: description }); pluginsByType[pluginType].push(identifier); isRegisteredPlugin[implementation] = true; pluginCount[pluginType]++; emit PluginRegistered(pluginType, identifier, implementation, version); } /** * @notice Upgrade plugin to new implementation */ function upgradePlugin( PluginType pluginType, bytes32 identifier, address newImplementation, string calldata newVersion ) external onlyRole(PLUGIN_ADMIN_ROLE) { require(newImplementation != address(0), "Zero address"); require(newImplementation.code.length > 0, "Not a contract"); Plugin storage plugin = plugins[pluginType][identifier]; require(plugin.implementation != address(0), "Plugin not found"); address oldImplementation = plugin.implementation; plugin.implementation = newImplementation; plugin.version = newVersion; isRegisteredPlugin[newImplementation] = true; emit PluginUpgraded(pluginType, identifier, oldImplementation, newImplementation); } /** * @notice Activate plugin */ function activatePlugin( PluginType pluginType, bytes32 identifier ) external onlyRole(PLUGIN_ADMIN_ROLE) { Plugin storage plugin = plugins[pluginType][identifier]; require(plugin.implementation != address(0), "Plugin not found"); plugin.active = true; emit PluginActivated(pluginType, identifier); } /** * @notice Deactivate plugin */ function deactivatePlugin( PluginType pluginType, bytes32 identifier ) external onlyRole(PLUGIN_ADMIN_ROLE) { Plugin storage plugin = plugins[pluginType][identifier]; require(plugin.implementation != address(0), "Plugin not found"); plugin.active = false; emit PluginDeactivated(pluginType, identifier); } // View functions function getPlugin( PluginType pluginType, bytes32 identifier ) external view returns (address implementation) { Plugin memory plugin = plugins[pluginType][identifier]; require(plugin.active, "Plugin not active"); return plugin.implementation; } function getPluginInfo( PluginType pluginType, bytes32 identifier ) external view returns (Plugin memory) { return plugins[pluginType][identifier]; } function getAllPlugins(PluginType pluginType) external view returns (bytes32[] memory) { return pluginsByType[pluginType]; } function getPluginCount(PluginType pluginType) external view returns (uint256) { return pluginCount[pluginType]; } function isPluginActive( PluginType pluginType, bytes32 identifier ) external view returns (bool) { return plugins[pluginType][identifier].active; } }