// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; /** * @title ProxyFactory * @notice Factory for deploying upgradeable proxies (UUPS and Beacon patterns) * @dev Tracks all deployed proxies for the universal bridge system */ contract ProxyFactory is AccessControl { bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE"); struct ProxyInfo { address proxy; address implementation; ProxyType proxyType; uint256 deployedAt; address deployer; bool isActive; } enum ProxyType { UUPS, Beacon, Transparent } // Storage mapping(address => ProxyInfo) public proxies; address[] public allProxies; mapping(address => address[]) public proxiesByImplementation; mapping(address => UpgradeableBeacon) public beacons; event ProxyDeployed( address indexed proxy, address indexed implementation, ProxyType proxyType, address deployer ); event BeaconCreated( address indexed beacon, address indexed implementation ); constructor(address admin) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(DEPLOYER_ROLE, admin); } /** * @notice Deploy UUPS proxy */ function deployUUPSProxy( address implementation, bytes calldata initData ) external onlyRole(DEPLOYER_ROLE) returns (address proxy) { require(implementation != address(0), "Zero implementation"); require(implementation.code.length > 0, "Not a contract"); // Deploy proxy proxy = address(new ERC1967Proxy(implementation, initData)); // Track proxy _trackProxy(proxy, implementation, ProxyType.UUPS); emit ProxyDeployed(proxy, implementation, ProxyType.UUPS, msg.sender); return proxy; } /** * @notice Deploy beacon proxy */ function deployBeaconProxy( address beacon, bytes calldata initData ) external onlyRole(DEPLOYER_ROLE) returns (address proxy) { require(beacon != address(0), "Zero beacon"); // Get implementation from beacon address implementation = UpgradeableBeacon(beacon).implementation(); // Deploy beacon proxy proxy = address(new BeaconProxy(beacon, initData)); // Track proxy _trackProxy(proxy, implementation, ProxyType.Beacon); emit ProxyDeployed(proxy, implementation, ProxyType.Beacon, msg.sender); return proxy; } /** * @notice Create beacon for implementation */ function createBeacon(address implementation) external onlyRole(DEPLOYER_ROLE) returns (address beacon) { require(implementation != address(0), "Zero implementation"); require(implementation.code.length > 0, "Not a contract"); UpgradeableBeacon newBeacon = new UpgradeableBeacon(implementation, address(this)); beacons[implementation] = newBeacon; emit BeaconCreated(address(newBeacon), implementation); return address(newBeacon); } /** * @notice Track deployed proxy */ function _trackProxy( address proxy, address implementation, ProxyType proxyType ) internal { proxies[proxy] = ProxyInfo({ proxy: proxy, implementation: implementation, proxyType: proxyType, deployedAt: block.timestamp, deployer: msg.sender, isActive: true }); allProxies.push(proxy); proxiesByImplementation[implementation].push(proxy); } // View functions function getProxyInfo(address proxy) external view returns (ProxyInfo memory) { return proxies[proxy]; } function getAllProxies() external view returns (address[] memory) { return allProxies; } function getProxiesByImplementation(address implementation) external view returns (address[] memory) { return proxiesByImplementation[implementation]; } function getProxyCount() external view returns (uint256) { return allProxies.length; } function isProxy(address addr) external view returns (bool) { return proxies[addr].isActive; } }