// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "./interfaces/ICoupon.sol"; /// @title Compliance — 合规合约 /// @notice OFAC 黑名单筛查、Travel Rule、KYC 差异化检查、账户冻结 /// @dev 使用 Transparent Proxy 部署 contract Compliance is Initializable, AccessControlUpgradeable { bytes32 public constant COMPLIANCE_OFFICER_ROLE = keccak256("COMPLIANCE_OFFICER_ROLE"); bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE"); bytes32 public constant KYC_PROVIDER_ROLE = keccak256("KYC_PROVIDER_ROLE"); // OFAC 黑名单 mapping(address => bool) private _blacklist; // 冻结账户(紧急冻结,需 Governance 多签) mapping(address => bool) private _frozen; // KYC 等级映射: 0=L0(未验证), 1=L1(基本), 2=L2(增强), 3=L3(机构) mapping(address => uint8) private _kycLevels; // Travel Rule 记录 mapping(address => mapping(address => bool)) private _travelRuleRecorded; // Travel Rule 详情 mapping(bytes32 => TravelRuleRecord) private _travelRuleRecords; struct TravelRuleRecord { address sender; address receiver; bytes32 senderInfoHash; bytes32 receiverInfoHash; uint256 recordedAt; } // Travel Rule 阈值(美元,USDC 精度 6 位) uint256 public constant TRAVEL_RULE_THRESHOLD = 3000e6; // $3,000 // 大额交易阈值 uint256 public constant LARGE_TRADE_THRESHOLD = 10000e6; // $10,000 // --- Events --- event AddressBlacklisted(address indexed account, string reason); event AddressRemovedFromBlacklist(address indexed account); event AccountFrozen(address indexed account); event AccountUnfrozen(address indexed account); event KycLevelUpdated(address indexed account, uint8 oldLevel, uint8 newLevel); event TravelRuleRecorded( address indexed sender, address indexed receiver, bytes32 senderInfoHash, bytes32 receiverInfoHash ); function initialize(address admin) external initializer { __AccessControl_init(); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(COMPLIANCE_OFFICER_ROLE, admin); _grantRole(GOVERNANCE_ROLE, admin); _grantRole(KYC_PROVIDER_ROLE, admin); } // ======================== // OFAC 黑名单 // ======================== /// @notice OFAC 筛查 function isBlacklisted(address account) external view returns (bool) { return _blacklist[account]; } /// @notice 添加 OFAC 黑名单 function addToBlacklist(address account, string calldata reason) external onlyRole(COMPLIANCE_OFFICER_ROLE) { _blacklist[account] = true; emit AddressBlacklisted(account, reason); } /// @notice 从黑名单移除 function removeFromBlacklist(address account) external onlyRole(GOVERNANCE_ROLE) { _blacklist[account] = false; emit AddressRemovedFromBlacklist(account); } // ======================== // 账户冻结 // ======================== /// @notice 查询是否冻结 function isFrozen(address account) external view returns (bool) { return _frozen[account]; } /// @notice 紧急冻结(需 Governance 多签) function freezeAccount(address account) external onlyRole(GOVERNANCE_ROLE) { _frozen[account] = true; emit AccountFrozen(account); } /// @notice 解除冻结 function unfreezeAccount(address account) external onlyRole(GOVERNANCE_ROLE) { _frozen[account] = false; emit AccountUnfrozen(account); } // ======================== // KYC 等级管理 // ======================== /// @notice 获取 KYC 等级 function getKycLevel(address account) external view returns (uint8) { return _kycLevels[account]; } /// @notice 设置 KYC 等级 function setKycLevel(address account, uint8 level) external onlyRole(KYC_PROVIDER_ROLE) { require(level <= 3, "Compliance: invalid KYC level"); uint8 oldLevel = _kycLevels[account]; _kycLevels[account] = level; emit KycLevelUpdated(account, oldLevel, level); } /// @notice 批量设置 KYC 等级 function batchSetKycLevel(address[] calldata accounts, uint8[] calldata levels) external onlyRole(KYC_PROVIDER_ROLE) { require(accounts.length == levels.length, "Compliance: length mismatch"); for (uint256 i = 0; i < accounts.length; i++) { require(levels[i] <= 3, "Compliance: invalid KYC level"); uint8 oldLevel = _kycLevels[accounts[i]]; _kycLevels[accounts[i]] = levels[i]; emit KycLevelUpdated(accounts[i], oldLevel, levels[i]); } } /// @notice 要求最低 KYC 等级(revert if不满足) function requireKycLevel(address account, uint8 requiredLevel) external view { require(_kycLevels[account] >= requiredLevel, "Compliance: insufficient KYC level"); } // ======================== // Travel Rule // ======================== /// @notice 记录 Travel Rule 数据(≥$3,000 强制) function recordTravelRule( address sender, address receiver, bytes32 senderInfoHash, bytes32 receiverInfoHash ) external onlyRole(COMPLIANCE_OFFICER_ROLE) { require(sender != address(0) && receiver != address(0), "Compliance: zero address"); require(senderInfoHash != bytes32(0) && receiverInfoHash != bytes32(0), "Compliance: empty hash"); _travelRuleRecorded[sender][receiver] = true; bytes32 recordId = keccak256(abi.encodePacked(sender, receiver, block.timestamp)); _travelRuleRecords[recordId] = TravelRuleRecord({ sender: sender, receiver: receiver, senderInfoHash: senderInfoHash, receiverInfoHash: receiverInfoHash, recordedAt: block.timestamp }); emit TravelRuleRecorded(sender, receiver, senderInfoHash, receiverInfoHash); } /// @notice 查询 Travel Rule 是否已记录 function hasTravelRuleRecord(address sender, address receiver) external view returns (bool) { return _travelRuleRecorded[sender][receiver]; } // ======================== // 综合合规检查 // ======================== /// @notice 交易前合规检查(Settlement 调用) function preTradeCheck( address buyer, address seller, uint256 amount, ICoupon.CouponType couponType ) external view { // OFAC 黑名单检查 require(!_blacklist[buyer], "Compliance: buyer blacklisted"); require(!_blacklist[seller], "Compliance: seller blacklisted"); // 冻结检查 require(!_frozen[buyer], "Compliance: buyer frozen"); require(!_frozen[seller], "Compliance: seller frozen"); // Utility Track: 双方至少 KYC L1 if (couponType == ICoupon.CouponType.Utility) { require(_kycLevels[buyer] >= 1, "Compliance: buyer needs KYC L1 for Utility"); require(_kycLevels[seller] >= 1, "Compliance: seller needs KYC L1 for Utility"); } // Securities Track: 双方至少 KYC L2 else { require(_kycLevels[buyer] >= 2, "Compliance: buyer needs KYC L2 for Security"); require(_kycLevels[seller] >= 2, "Compliance: seller needs KYC L2 for Security"); } // 大额交易: KYC L2+ if (amount >= LARGE_TRADE_THRESHOLD) { require(_kycLevels[buyer] >= 2, "Compliance: buyer needs KYC L2 for large trade"); require(_kycLevels[seller] >= 2, "Compliance: seller needs KYC L2 for large trade"); } } /// @notice P2P 转移合规路由 function p2pComplianceCheck( address sender, address receiver, uint256 amount ) external view { require(!_blacklist[sender], "Compliance: sender blacklisted"); require(!_blacklist[receiver], "Compliance: receiver blacklisted"); require(!_frozen[sender], "Compliance: sender frozen"); require(!_frozen[receiver], "Compliance: receiver frozen"); // ≥$3,000 强制 Travel Rule if (amount >= TRAVEL_RULE_THRESHOLD) { require(_kycLevels[sender] >= 2, "Compliance: sender needs KYC L2 for Travel Rule"); require(_kycLevels[receiver] >= 2, "Compliance: receiver needs KYC L2 for Travel Rule"); require(_travelRuleRecorded[sender][receiver], "Compliance: Travel Rule data required"); } } }