// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/AccessControl.sol"; import "../interop/BridgeEscrowVault.sol"; import "../../emoney/PolicyManager.sol"; import "../../emoney/ComplianceRegistry.sol"; /** * @title eMoneyPolicyEnforcer * @notice Enforces eMoney transfer restrictions on bridge operations * @dev Integrates PolicyManager and ComplianceRegistry with bridge */ contract eMoneyPolicyEnforcer is AccessControl { bytes32 public constant ENFORCER_ROLE = keccak256("ENFORCER_ROLE"); bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); BridgeEscrowVault public bridgeEscrowVault; PolicyManager public policyManager; ComplianceRegistry public complianceRegistry; mapping(address => bool) public enabledTokens; // eMoney token => enabled event TokenEnabled(address indexed token, bool enabled); event TransferAuthorized( address indexed token, address indexed from, address indexed to, uint256 amount, bool authorized ); error TransferNotAuthorized(); error TokenNotEnabled(); error InvalidToken(); constructor( address admin, address bridgeEscrowVault_, address policyManager_, address complianceRegistry_ ) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(ENFORCER_ROLE, admin); _grantRole(OPERATOR_ROLE, admin); require(bridgeEscrowVault_ != address(0), "eMoneyPolicyEnforcer: zero bridge"); require(policyManager_ != address(0), "eMoneyPolicyEnforcer: zero policy manager"); require(complianceRegistry_ != address(0), "eMoneyPolicyEnforcer: zero compliance registry"); bridgeEscrowVault = BridgeEscrowVault(bridgeEscrowVault_); policyManager = PolicyManager(policyManager_); complianceRegistry = ComplianceRegistry(complianceRegistry_); } /** * @notice Check if transfer is authorized before bridge operation * @param token eMoney token address * @param from Source address * @param to Destination address (bridge escrow) * @param amount Amount to bridge * @return authorized True if transfer is authorized */ function checkTransferAuthorization( address token, address from, address to, uint256 amount ) external returns (bool authorized) { if (!enabledTokens[token]) revert TokenNotEnabled(); // Check PolicyManager authorization (bool isAuthorized, bytes32 reasonCode) = policyManager.canTransfer( token, from, to, amount ); if (!isAuthorized) { emit TransferAuthorized(token, from, to, amount, false); revert TransferNotAuthorized(); } // Check ComplianceRegistry restrictions bool complianceAllowed = complianceRegistry.canTransfer(token, from, to, amount); if (!complianceAllowed) { emit TransferAuthorized(token, from, to, amount, false); revert TransferNotAuthorized(); } emit TransferAuthorized(token, from, to, amount, true); authorized = true; } /** * @notice Check transfer authorization with additional context * @param token eMoney token address * @param from Source address * @param to Destination address * @param amount Amount to transfer * @param context Additional context data * @return authorized True if transfer is authorized */ function checkTransferAuthorizationWithContext( address token, address from, address to, uint256 amount, bytes memory context ) external returns (bool authorized) { if (!enabledTokens[token]) revert TokenNotEnabled(); // Check PolicyManager with context (bool isAuthorized, bytes32 reasonCode) = policyManager.canTransferWithContext( token, from, to, amount, context ); if (!isAuthorized) { emit TransferAuthorized(token, from, to, amount, false); revert TransferNotAuthorized(); } // Check ComplianceRegistry bool complianceAllowed = complianceRegistry.canTransfer(token, from, to, amount); if (!complianceAllowed) { emit TransferAuthorized(token, from, to, amount, false); revert TransferNotAuthorized(); } emit TransferAuthorized(token, from, to, amount, true); authorized = true; } /** * @notice Enable an eMoney token for policy enforcement * @param token eMoney token address */ function enableToken(address token) external onlyRole(OPERATOR_ROLE) { require(token != address(0), "eMoneyPolicyEnforcer: zero token"); enabledTokens[token] = true; emit TokenEnabled(token, true); } /** * @notice Disable an eMoney token * @param token eMoney token address */ function disableToken(address token) external onlyRole(OPERATOR_ROLE) { enabledTokens[token] = false; emit TokenEnabled(token, false); } /** * @notice Check if token is enabled */ function isTokenEnabled(address token) external view returns (bool) { return enabledTokens[token]; } }