// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; /** * @title WorkflowRegistry * @notice Registers and tracks workflow definitions on-chain * @dev Placeholder for future workflow verification capabilities */ contract WorkflowRegistry is Ownable { struct WorkflowDefinition { bytes32 id; string workflowType; string name; bytes32 definitionHash; uint256 version; uint256 timestamp; bool isActive; } // Mapping from workflow ID to definition mapping(bytes32 => WorkflowDefinition) private _workflows; // Mapping from workflow type to latest workflow ID mapping(string => bytes32) private _latestWorkflows; // Array of all workflow IDs bytes32[] private _workflowIds; // Counter for unique IDs uint256 private _workflowCounter; // Events event WorkflowRegistered( bytes32 indexed workflowId, string indexed workflowType, string name, bytes32 definitionHash, uint256 version ); event WorkflowDeactivated(bytes32 indexed workflowId); event WorkflowActivated(bytes32 indexed workflowId); constructor() Ownable(msg.sender) {} /** * @notice Register a new workflow definition * @param workflowType The type of workflow (e.g., "RESORT_LICENSE") * @param name Human-readable name * @param definitionHash Hash of the workflow definition JSON * @return workflowId The unique workflow ID */ function registerWorkflow( string calldata workflowType, string calldata name, bytes32 definitionHash ) public onlyOwner returns (bytes32) { require(bytes(workflowType).length > 0, "Workflow type required"); require(bytes(name).length > 0, "Name required"); require(definitionHash != bytes32(0), "Definition hash required"); _workflowCounter++; bytes32 workflowId = keccak256( abi.encodePacked(workflowType, _workflowCounter, block.timestamp) ); // Determine version uint256 version = 1; bytes32 latestId = _latestWorkflows[workflowType]; if (latestId != bytes32(0)) { version = _workflows[latestId].version + 1; // Deactivate previous version _workflows[latestId].isActive = false; } WorkflowDefinition storage workflow = _workflows[workflowId]; workflow.id = workflowId; workflow.workflowType = workflowType; workflow.name = name; workflow.definitionHash = definitionHash; workflow.version = version; workflow.timestamp = block.timestamp; workflow.isActive = true; _latestWorkflows[workflowType] = workflowId; _workflowIds.push(workflowId); emit WorkflowRegistered( workflowId, workflowType, name, definitionHash, version ); return workflowId; } /** * @notice Get workflow definition by ID * @param workflowId The workflow ID * @return The WorkflowDefinition struct */ function getWorkflow(bytes32 workflowId) public view returns (WorkflowDefinition memory) { require(_workflows[workflowId].timestamp > 0, "Workflow not found"); return _workflows[workflowId]; } /** * @notice Get the latest active workflow for a type * @param workflowType The workflow type * @return The WorkflowDefinition struct */ function getLatestWorkflow(string calldata workflowType) public view returns (WorkflowDefinition memory) { bytes32 workflowId = _latestWorkflows[workflowType]; require(workflowId != bytes32(0), "No workflow found for type"); return _workflows[workflowId]; } /** * @notice Verify a workflow definition hash * @param workflowId The workflow ID * @param definitionHash The hash to verify * @return True if the hash matches */ function verifyWorkflow(bytes32 workflowId, bytes32 definitionHash) public view returns (bool) { WorkflowDefinition memory workflow = _workflows[workflowId]; return workflow.isActive && workflow.definitionHash == definitionHash; } /** * @notice Deactivate a workflow * @param workflowId The workflow ID */ function deactivateWorkflow(bytes32 workflowId) public onlyOwner { require(_workflows[workflowId].timestamp > 0, "Workflow not found"); require(_workflows[workflowId].isActive, "Workflow already inactive"); _workflows[workflowId].isActive = false; emit WorkflowDeactivated(workflowId); } /** * @notice Activate a workflow * @param workflowId The workflow ID */ function activateWorkflow(bytes32 workflowId) public onlyOwner { require(_workflows[workflowId].timestamp > 0, "Workflow not found"); require(!_workflows[workflowId].isActive, "Workflow already active"); _workflows[workflowId].isActive = true; emit WorkflowActivated(workflowId); } /** * @notice Get total workflow count * @return The number of registered workflows */ function getWorkflowCount() public view returns (uint256) { return _workflowIds.length; } /** * @notice Check if a workflow is active * @param workflowId The workflow ID * @return True if active */ function isWorkflowActive(bytes32 workflowId) public view returns (bool) { return _workflows[workflowId].isActive; } }