// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "./UniversalCCIPBridge.sol"; import "../iso4217w/interfaces/IISO4217WToken.sol"; /** * @title ISO4217WCCIPBridge * @notice Specialized bridge for ISO-4217W eMoney/CBDC tokens * @dev Enforces KYC compliance and reserve backing verification */ contract ISO4217WCCIPBridge is UniversalCCIPBridge { mapping(address => bool) public kycVerified; mapping(address => uint256) public kycExpiration; mapping(string => bool) public allowedJurisdictions; mapping(address => string) public userJurisdictions; mapping(address => uint256) public verifiedReserves; event KYCVerified(address indexed user, uint256 expirationTime); event KYCRevoked(address indexed user); event JurisdictionEnabled(string indexed jurisdiction); event ReserveVerified(address indexed token, uint256 amount); function bridgeISO4217W( address token, uint256 amount, uint64 destinationChain, address recipient, bytes calldata complianceProof ) external nonReentrant returns (bytes32 messageId) { UniversalAssetRegistry.UniversalAsset memory asset = assetRegistry.getAsset(token); require(asset.assetType == UniversalAssetRegistry.AssetType.ISO4217W, "Not ISO-4217W"); require(asset.isActive, "Asset not active"); require(_checkKYC(msg.sender), "KYC required"); require(_checkKYC(recipient), "Recipient KYC required"); string memory senderJurisdiction = userJurisdictions[msg.sender]; string memory recipientJurisdiction = userJurisdictions[recipient]; require( allowedJurisdictions[senderJurisdiction] && allowedJurisdictions[recipientJurisdiction], "Jurisdiction not allowed" ); require(_verifyReserveBacking(token, amount), "Insufficient reserves"); BridgeOperation memory op = BridgeOperation({ token: token, amount: amount, destinationChain: destinationChain, recipient: recipient, assetType: bytes32(uint256(UniversalAssetRegistry.AssetType.ISO4217W)), usePMM: false, useVault: false, complianceProof: complianceProof, vaultInstructions: "" }); messageId = this.bridge(op); return messageId; } function _verifyReserveBacking(address token, uint256 amount) internal view returns (bool) { try IISO4217WToken(token).verifiedReserve() returns (uint256 reserve) { return reserve >= amount; } catch { return verifiedReserves[token] >= amount; } } function _checkKYC(address user) internal view returns (bool) { return kycVerified[user] && block.timestamp < kycExpiration[user]; } function setKYCStatus(address user, bool status, uint256 expirationTime) external onlyRole(BRIDGE_OPERATOR_ROLE) { kycVerified[user] = status; kycExpiration[user] = expirationTime; if (status) { emit KYCVerified(user, expirationTime); } else { emit KYCRevoked(user); } } function enableJurisdiction(string calldata jurisdiction) external onlyRole(DEFAULT_ADMIN_ROLE) { allowedJurisdictions[jurisdiction] = true; emit JurisdictionEnabled(jurisdiction); } function setUserJurisdiction(address user, string calldata jurisdiction) external onlyRole(BRIDGE_OPERATOR_ROLE) { userJurisdictions[user] = jurisdiction; } function updateVerifiedReserve(address token, uint256 reserve) external onlyRole(BRIDGE_OPERATOR_ROLE) { verifiedReserves[token] = reserve; emit ReserveVerified(token, reserve); } }