Initial commit
This commit is contained in:
129
contracts/governance/PolicyEngine.sol
Normal file
129
contracts/governance/PolicyEngine.sol
Normal file
@@ -0,0 +1,129 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.24;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
import "../interfaces/IPolicyEngine.sol";
|
||||
import "../interfaces/IPolicyModule.sol";
|
||||
|
||||
/**
|
||||
* @title PolicyEngine
|
||||
* @notice Aggregates policy decisions from multiple modules
|
||||
* @dev All registered modules must approve an action for it to be allowed
|
||||
*/
|
||||
contract PolicyEngine is IPolicyEngine, Ownable {
|
||||
// Registered policy modules
|
||||
address[] private policyModules;
|
||||
mapping(address => bool) private isRegisteredModule;
|
||||
|
||||
modifier onlyRegistered(address module) {
|
||||
require(isRegisteredModule[module], "Module not registered");
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(address initialOwner) Ownable(initialOwner) {}
|
||||
|
||||
/**
|
||||
* @notice Register a policy module
|
||||
*/
|
||||
function registerPolicyModule(address module) external override onlyOwner {
|
||||
require(module != address(0), "Invalid module");
|
||||
require(!isRegisteredModule[module], "Module already registered");
|
||||
|
||||
// Verify it implements IPolicyModule
|
||||
try IPolicyModule(module).name() returns (string memory) {
|
||||
// Module is valid
|
||||
} catch {
|
||||
revert("Invalid policy module");
|
||||
}
|
||||
|
||||
policyModules.push(module);
|
||||
isRegisteredModule[module] = true;
|
||||
|
||||
emit PolicyModuleRegistered(module, IPolicyModule(module).name());
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Unregister a policy module
|
||||
*/
|
||||
function unregisterPolicyModule(address module) external override onlyOwner onlyRegistered(module) {
|
||||
// Remove from array
|
||||
for (uint256 i = 0; i < policyModules.length; i++) {
|
||||
if (policyModules[i] == module) {
|
||||
policyModules[i] = policyModules[policyModules.length - 1];
|
||||
policyModules.pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete isRegisteredModule[module];
|
||||
emit PolicyModuleUnregistered(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Evaluate all registered policy modules
|
||||
* @return allowed True if ALL modules allow the action
|
||||
* @return reason Reason from first denying module
|
||||
*/
|
||||
function evaluateAll(
|
||||
bytes32 actionType,
|
||||
bytes memory actionData
|
||||
) external view override returns (bool allowed, string memory reason) {
|
||||
// If no modules registered, allow by default
|
||||
if (policyModules.length == 0) {
|
||||
return (true, "");
|
||||
}
|
||||
|
||||
// Check all modules
|
||||
for (uint256 i = 0; i < policyModules.length; i++) {
|
||||
address module = policyModules[i];
|
||||
|
||||
// Skip if module is disabled
|
||||
try IPolicyModule(module).isEnabled() returns (bool enabled) {
|
||||
if (!enabled) {
|
||||
continue;
|
||||
}
|
||||
} catch {
|
||||
continue; // Skip if check fails
|
||||
}
|
||||
|
||||
// Get decision from module
|
||||
IPolicyModule.PolicyDecision memory decision;
|
||||
try IPolicyModule(module).evaluate(actionType, actionData) returns (IPolicyModule.PolicyDecision memory d) {
|
||||
decision = d;
|
||||
} catch {
|
||||
// If evaluation fails, deny for safety
|
||||
return (false, "Policy evaluation failed");
|
||||
}
|
||||
|
||||
// If any module denies, return denial
|
||||
if (!decision.allowed) {
|
||||
return (false, decision.reason);
|
||||
}
|
||||
}
|
||||
|
||||
// All modules allowed
|
||||
return (true, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get all registered policy modules
|
||||
*/
|
||||
function getPolicyModules() external view override returns (address[] memory) {
|
||||
return policyModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Check if a module is registered
|
||||
*/
|
||||
function isRegistered(address module) external view override returns (bool) {
|
||||
return isRegisteredModule[module];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get number of registered modules
|
||||
*/
|
||||
function getModuleCount() external view returns (uint256) {
|
||||
return policyModules.length;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user