// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/access/AccessControl.sol"; import "./LegallyCompliantBase.sol"; /** * @title ComplianceRegistry * @notice Registry for tracking legal compliance status of contracts * @dev This registry tracks contracts that inherit from LegallyCompliantBase * Separate from eMoney ComplianceRegistry which has KYC/AML features */ contract ComplianceRegistry is AccessControl { bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE"); /** * @notice Compliance status for a contract */ struct ContractComplianceStatus { bool isRegistered; string legalFrameworkVersion; string legalJurisdiction; bytes32 lastLegalNoticeHash; uint256 registeredAt; uint256 lastUpdated; } mapping(address => ContractComplianceStatus) private _contractCompliance; event ContractRegistered( address indexed contractAddress, string legalFrameworkVersion, string legalJurisdiction, uint256 timestamp ); event ContractComplianceUpdated( address indexed contractAddress, bytes32 lastLegalNoticeHash, uint256 timestamp ); /** * @notice Constructor * @param admin Address that will receive DEFAULT_ADMIN_ROLE */ constructor(address admin) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(REGISTRAR_ROLE, admin); } /** * @notice Register a contract that inherits from LegallyCompliantBase * @param contractAddress Address of the compliant contract * @dev Requires REGISTRAR_ROLE */ function registerContract(address contractAddress) external onlyRole(REGISTRAR_ROLE) { require(contractAddress != address(0), "ComplianceRegistry: zero address"); require(!_contractCompliance[contractAddress].isRegistered, "ComplianceRegistry: contract already registered"); // Get compliance information from the contract LegallyCompliantBase compliantContract = LegallyCompliantBase(contractAddress); _contractCompliance[contractAddress] = ContractComplianceStatus({ isRegistered: true, legalFrameworkVersion: compliantContract.LEGAL_FRAMEWORK_VERSION(), legalJurisdiction: compliantContract.LEGAL_JURISDICTION(), lastLegalNoticeHash: bytes32(0), registeredAt: block.timestamp, lastUpdated: block.timestamp }); emit ContractRegistered( contractAddress, compliantContract.LEGAL_FRAMEWORK_VERSION(), compliantContract.LEGAL_JURISDICTION(), block.timestamp ); } /** * @notice Update compliance status with a new legal notice * @param contractAddress Address of the compliant contract * @param newLegalNoticeHash Hash of the new legal notice * @dev Requires REGISTRAR_ROLE */ function updateContractCompliance( address contractAddress, bytes32 newLegalNoticeHash ) external onlyRole(REGISTRAR_ROLE) { require(_contractCompliance[contractAddress].isRegistered, "ComplianceRegistry: contract not registered"); _contractCompliance[contractAddress].lastLegalNoticeHash = newLegalNoticeHash; _contractCompliance[contractAddress].lastUpdated = block.timestamp; emit ContractComplianceUpdated(contractAddress, newLegalNoticeHash, block.timestamp); } /** * @notice Get compliance status for a contract * @param contractAddress Address of the contract * @return Compliance status struct */ function getContractComplianceStatus( address contractAddress ) external view returns (ContractComplianceStatus memory) { return _contractCompliance[contractAddress]; } /** * @notice Check if a contract is registered * @param contractAddress Address of the contract * @return True if registered, false otherwise */ function isContractRegistered(address contractAddress) external view returns (bool) { return _contractCompliance[contractAddress].isRegistered; } }