// 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 ConfigurationRegistry * @notice Centralized configuration without hardcoding * @dev Eliminates hardcoded addresses, enables runtime configuration */ contract ConfigurationRegistry is Initializable, AccessControlUpgradeable, UUPSUpgradeable { bytes32 public constant CONFIG_ADMIN_ROLE = keccak256("CONFIG_ADMIN_ROLE"); bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); mapping(address => mapping(bytes32 => bytes)) private configs; mapping(address => bytes32[]) private configKeys; event ConfigSet(address indexed contractAddr, bytes32 indexed key, bytes value); event ConfigDeleted(address indexed contractAddr, bytes32 indexed key); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize(address admin) external initializer { __AccessControl_init(); __UUPSUpgradeable_init(); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(CONFIG_ADMIN_ROLE, admin); _grantRole(UPGRADER_ROLE, admin); } function _authorizeUpgrade(address newImplementation) internal override onlyRole(UPGRADER_ROLE) {} function set(address contractAddr, bytes32 key, bytes calldata value) external onlyRole(CONFIG_ADMIN_ROLE) { require(contractAddr != address(0), "Zero address"); require(key != bytes32(0), "Zero key"); if (configs[contractAddr][key].length == 0) { configKeys[contractAddr].push(key); } configs[contractAddr][key] = value; emit ConfigSet(contractAddr, key, value); } function get(address contractAddr, bytes32 key) external view returns (bytes memory) { return configs[contractAddr][key]; } function getAddress(address contractAddr, bytes32 key) external view returns (address) { bytes memory data = configs[contractAddr][key]; require(data.length == 32, "Invalid data"); return abi.decode(data, (address)); } function getUint256(address contractAddr, bytes32 key) external view returns (uint256) { bytes memory data = configs[contractAddr][key]; require(data.length == 32, "Invalid data"); return abi.decode(data, (uint256)); } }