// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "./interfaces/IComboHandler.sol"; /** * @title UpgradeableComboHandler * @notice Upgradeable version of ComboHandler with timelock * @dev Uses UUPS upgrade pattern with timelock protection */ contract UpgradeableComboHandler is Initializable, UUPSUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable { bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); uint256 public upgradeTimelock; uint256 public pendingUpgradeTime; address public pendingUpgradeImplementation; function initialize(address admin) public initializer { __AccessControl_init(); __ReentrancyGuard_init(); __Pausable_init(); __UUPSUpgradeable_init(); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(UPGRADER_ROLE, admin); _grantRole(PAUSER_ROLE, admin); upgradeTimelock = 7 days; // 7 day timelock for upgrades } function _authorizeUpgrade(address newImplementation) internal override onlyRole(UPGRADER_ROLE) { require( pendingUpgradeImplementation == newImplementation && block.timestamp >= pendingUpgradeTime, "Upgrade not scheduled or timelock not expired" ); // Clear pending upgrade pendingUpgradeImplementation = address(0); pendingUpgradeTime = 0; } /** * @notice Schedule an upgrade (requires timelock) */ function scheduleUpgrade(address newImplementation) external onlyRole(UPGRADER_ROLE) { pendingUpgradeImplementation = newImplementation; pendingUpgradeTime = block.timestamp + upgradeTimelock; } /** * @notice Cancel scheduled upgrade */ function cancelUpgrade() external onlyRole(UPGRADER_ROLE) { pendingUpgradeImplementation = address(0); pendingUpgradeTime = 0; } /** * @notice Pause contract (emergency only) */ function pause() external onlyRole(PAUSER_ROLE) { _pause(); } /** * @notice Unpause contract */ function unpause() external onlyRole(PAUSER_ROLE) { _unpause(); } }