// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IConfigRegistry.sol"; /** * @title ConfigRegistry * @notice Stores all system parameters and limits * @dev Central configuration registry with access control */ contract ConfigRegistry is IConfigRegistry, Ownable { // Constants uint256 private constant HF_SCALE = 1e18; uint256 private constant DEFAULT_MIN_HF = 1.05e18; // 1.05 uint256 private constant DEFAULT_TARGET_HF = 1.20e18; // 1.20 uint256 private constant DEFAULT_MAX_LOOPS = 5; // Core parameters uint256 public override maxLoops = DEFAULT_MAX_LOOPS; uint256 public override minHealthFactor = DEFAULT_MIN_HF; uint256 public override targetHealthFactor = DEFAULT_TARGET_HF; // Asset-specific limits mapping(address => uint256) public override maxFlashSize; mapping(address => bool) public override isAllowedAsset; // Provider capacity caps mapping(bytes32 => uint256) public override providerCap; // Parameter name constants (for events) bytes32 public constant PARAM_MAX_LOOPS = keccak256("MAX_LOOPS"); bytes32 public constant PARAM_MIN_HF = keccak256("MIN_HF"); bytes32 public constant PARAM_TARGET_HF = keccak256("TARGET_HF"); bytes32 public constant PARAM_MAX_FLASH = keccak256("MAX_FLASH"); bytes32 public constant PARAM_PROVIDER_CAP = keccak256("PROVIDER_CAP"); modifier validHealthFactor(uint256 hf) { require(hf >= 1e18, "HF must be >= 1.0"); _; } constructor(address initialOwner) Ownable(initialOwner) { // Initialize with safe defaults } /** * @notice Update maximum loops */ function setMaxLoops(uint256 newMaxLoops) external override onlyOwner { require(newMaxLoops > 0 && newMaxLoops <= 50, "Invalid max loops"); uint256 oldValue = maxLoops; maxLoops = newMaxLoops; emit ParameterUpdated(PARAM_MAX_LOOPS, oldValue, newMaxLoops); } /** * @notice Update maximum flash size for an asset */ function setMaxFlashSize(address asset, uint256 newMaxFlash) external override onlyOwner { require(asset != address(0), "Invalid asset"); uint256 oldValue = maxFlashSize[asset]; maxFlashSize[asset] = newMaxFlash; emit ParameterUpdated(keccak256(abi.encodePacked(PARAM_MAX_FLASH, asset)), oldValue, newMaxFlash); } /** * @notice Update minimum health factor */ function setMinHealthFactor(uint256 newMinHF) external override onlyOwner validHealthFactor(newMinHF) { require(newMinHF <= targetHealthFactor, "Min HF must be <= target HF"); uint256 oldValue = minHealthFactor; minHealthFactor = newMinHF; emit ParameterUpdated(PARAM_MIN_HF, oldValue, newMinHF); } /** * @notice Update target health factor */ function setTargetHealthFactor(uint256 newTargetHF) external override onlyOwner validHealthFactor(newTargetHF) { require(newTargetHF >= minHealthFactor, "Target HF must be >= min HF"); uint256 oldValue = targetHealthFactor; targetHealthFactor = newTargetHF; emit ParameterUpdated(PARAM_TARGET_HF, oldValue, newTargetHF); } /** * @notice Add or remove allowed asset */ function setAllowedAsset(address asset, bool allowed) external override onlyOwner { require(asset != address(0), "Invalid asset"); bool oldValue = isAllowedAsset[asset]; isAllowedAsset[asset] = allowed; emit ParameterUpdated(keccak256(abi.encodePacked("ALLOWED_ASSET", asset)), oldValue ? 1 : 0, allowed ? 1 : 0); } /** * @notice Update provider capacity cap */ function setProviderCap(bytes32 provider, uint256 newCap) external override onlyOwner { require(provider != bytes32(0), "Invalid provider"); uint256 oldValue = providerCap[provider]; providerCap[provider] = newCap; emit ParameterUpdated(keccak256(abi.encodePacked(PARAM_PROVIDER_CAP, provider)), oldValue, newCap); } /** * @notice Batch update allowed assets */ function batchSetAllowedAssets(address[] calldata assets, bool[] calldata allowed) external onlyOwner { require(assets.length == allowed.length, "Array length mismatch"); for (uint256 i = 0; i < assets.length; i++) { setAllowedAsset(assets[i], allowed[i]); } } }