// SPDX-License-Identifier: MIT // solhint-disable no-empty-blocks pragma solidity ^0.8.13; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/utils/Multicall.sol"; import "./IWarperManager.sol"; import "../../contract-registry/ContractEntity.sol"; import "../../universe/universe-registry/IUniverseRegistry.sol"; import "../../acl/direct/AccessControlledUpgradeable.sol"; import "./WarperManagerStorage.sol"; contract WarperManager is IWarperManager, Initializable, UUPSUpgradeable, ContractEntity, AccessControlledUpgradeable, WarperManagerStorage, Multicall { using Warpers for Warpers.Registry; using Warpers for Warpers.Warper; using Assets for Assets.Asset; using Assets for Assets.Registry; /** * @dev WarperManager initialization params. * @param acl ACL contract address. * @param metahub Metahub contract address. */ struct WarperManagerInitParams { IACL acl; IMetahub metahub; } /** * @dev Modifier to make sure the function is called by the authorized Wizard for Warper Management. */ modifier onlyIsAuthorizedWizardForWarperManagement() { checkIsAuthorizedWizardForWarperManagement(_msgSender()); _; } /** * @dev Modifier to make sure the function is called by the authorized Warper Operator. */ modifier onlyIsAuthorizedOperatorForWarperManagement(address warper) { if (!_isAuthorizedWizardForWarperManagement(_msgSender()) && !_isWarperAdmin(warper, _msgSender())) { revert AccountIsNotAuthorizedOperatorForWarperManagement(warper, _msgSender()); } _; } /** * @dev Modifier to make sure that the warper has been registered beforehand. */ modifier onlyRegisteredWarper(address warper) { _checkRegisteredWarper(warper); _; } /** * @dev Metahub initializer. * @param params Initialization params. */ function initialize(WarperManagerInitParams calldata params) external initializer { __UUPSUpgradeable_init(); _aclContract = IACL(params.acl); _metahub = IMetahub(params.metahub); } /** * @inheritdoc IWarperManager */ function registerWarper(address warper, WarperRegistrationParams memory params) external onlyIsAuthorizedWizardForWarperManagement { (bytes4 assetClass, address original) = _warperRegistry.registerWarper(warper, params); _metahub.registerAsset(assetClass, original); emit WarperRegistered(params.universeId, warper, original, assetClass); } /** * @inheritdoc IWarperManager */ function deregisterWarper(address warper) external onlyRegisteredWarper(warper) onlyIsAuthorizedWizardForWarperManagement { _warperRegistry.remove(warper); emit WarperDeregistered(warper); } /** * @inheritdoc IWarperManager */ function pauseWarper(address warper) external onlyRegisteredWarper(warper) onlyIsAuthorizedOperatorForWarperManagement(warper) { _warperRegistry.warpers[warper].pause(); emit WarperPaused(warper); } /** * @inheritdoc IWarperManager */ function unpauseWarper(address warper) external onlyRegisteredWarper(warper) onlyIsAuthorizedOperatorForWarperManagement(warper) { _warperRegistry.warpers[warper].unpause(); emit WarperUnpaused(warper); } /** * @inheritdoc IWarperManager */ function setWarperController(address[] calldata warpers, address controller) external onlyAdmin { for (uint256 i = 0; i < warpers.length; i++) { address warper = warpers[i]; _checkRegisteredWarper(warper); IWarperController(controller).checkCompatibleWarper(warper); _warperRegistry.warpers[warper].controller = IWarperController(controller); } } /** * @inheritdoc IWarperManager */ function metahub() external view returns (address) { return address(_metahub); } /** * @inheritdoc IWarperManager */ function universeWarperCount(uint256 universeId) external view returns (uint256) { return _warperRegistry.universeWarperCount(universeId); } /** * @inheritdoc IWarperManager */ function universeWarpers( uint256 universeId, uint256 offset, uint256 limit ) external view returns (address[] memory, Warpers.Warper[] memory) { return _warperRegistry.universeWarpers(universeId, offset, limit); } /** * @inheritdoc IWarperManager */ function universeAssetWarperCount(uint256 universeId, address asset) external view returns (uint256) { return _warperRegistry.universeAssetWarperCount(universeId, asset); } /** * @inheritdoc IWarperManager */ function universeAssetWarpers( uint256 universeId, address asset, uint256 offset, uint256 limit ) external view returns (address[] memory, Warpers.Warper[] memory) { return _warperRegistry.universeAssetWarpers(universeId, asset, offset, limit); } /** * @inheritdoc IWarperManager */ function isWarperAdmin(address warper, address account) external view returns (bool) { return _isWarperAdmin(warper, account); } /** * @inheritdoc IWarperManager */ function warperInfo(address warper) external view onlyRegisteredWarper(warper) returns (Warpers.Warper memory) { return _warperRegistry.warpers[warper]; } /** * @inheritdoc IWarperManager */ function checkWarperAdmin(address warper, address account) external view { if (!_isWarperAdmin(warper, account)) { revert AccountIsNotWarperAdmin(warper, account); } } /** * @inheritdoc IWarperManager */ function checkRegisteredWarper(address warper) external view { _checkRegisteredWarper(warper); } /** * @inheritdoc IWarperManager */ function checkUniverseHasWarper(uint256 universeId) external view { return _warperRegistry.checkUniverseHasWarper(universeId); } /** * @inheritdoc IWarperManager */ function checkUniverseHasWarperForAsset(uint256 universeId, address asset) external view { return _warperRegistry.checkUniverseHasWarperForAsset(universeId, asset); } /** * @inheritdoc IWarperManager */ function warperController(address warper) external view onlyRegisteredWarper(warper) returns (address) { return address(_warperRegistry.warpers[warper].controller); } /** * @inheritdoc IContractEntity */ function contractKey() external pure override returns (bytes4) { return Contracts.WARPER_MANAGER; } /** * @inheritdoc IWarperManager */ function checkIsAuthorizedWizardForWarperManagement(address account) public view { if (!_isAuthorizedWizardForWarperManagement(account)) { revert AccountIsNotAuthorizedWizardForWarperManagement(account); } } /** * @inheritdoc IERC165 */ function supportsInterface(bytes4 interfaceId) public view override(ContractEntity, IERC165) returns (bool) { return interfaceId == type(IWarperManager).interfaceId || super.supportsInterface(interfaceId); } /** * @inheritdoc UUPSUpgradeable * @dev Checks whether the caller is authorized to upgrade the Metahub implementation. */ function _authorizeUpgrade(address newImplementation) internal override onlyAdmin { // solhint-disable-previous-line no-empty-blocks } function _isAuthorizedWizardForWarperManagement(address account) internal view returns (bool) { return IUniverseRegistry(_metahub.getContract(Contracts.UNIVERSE_REGISTRY)).isUniverseWizard(account) || _aclContract.hasRole(Roles.WARPER_WIZARD, account); } function _isWarperAdmin(address warper, address account) internal view onlyRegisteredWarper(warper) returns (bool) { return IUniverseRegistry(_metahub.getContract(Contracts.UNIVERSE_REGISTRY)).isUniverseOwner( _warperRegistry.warpers[warper].universeId, account ); } function _checkRegisteredWarper(address warper) internal view { _warperRegistry.checkRegisteredWarper(warper); } /** * @inheritdoc AccessControlledUpgradeable */ function _acl() internal view override returns (IACL) { return _aclContract; } }