From 7da9b66d1dd96dc10c5a6f4af4130865746903ae Mon Sep 17 00:00:00 2001 From: JMSBPP Date: Tue, 9 Dec 2025 20:09:30 -0500 Subject: [PATCH] test: protocol-pkg test coverage improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- .../ProtocolHookMediator.sol | 4 +- .../src/protocol-pkg/ProtocolAdminClient.sol | 100 +++++++++--- .../src/protocol-pkg/ProtocolAdminManager.sol | 145 +++++++++++++++--- .../src/protocol-pkg/ProtocolAdminPanel.sol | 92 +++++------ .../protocol-pkg/ProtocolAdminRegistry.sol | 97 ++++++------ .../src/protocol-pkg/ProtocolFactoryFacet.sol | 77 +++++++--- .../test/master-hook-pkg/utils/ForkUtils.sol | 1 + .../ProtocolAdminClient.fork.t.sol | 105 +++++++++---- .../protocol-pkg/ProtocolAdminClient.t.sol | 46 ++++-- .../protocol-pkg/ProtocolAdminManager.t.sol | 126 +++++++++++++-- .../protocol-pkg/ProtocolAdminPanel.t.sol | 99 ++++++++---- .../protocol-pkg/ProtocolAdminRegistry.t.sol | 32 +++- .../protocol-pkg/ProtocolFactoryFacet.t.sol | 49 ++++-- .../test/protocol-pkg/helpers/ProxyHelper.sol | 6 +- foundry.toml | 16 +- 15 files changed, 710 insertions(+), 285 deletions(-) diff --git a/contracts/src/protocol-hook-pkg/ProtocolHookMediator.sol b/contracts/src/protocol-hook-pkg/ProtocolHookMediator.sol index a762cb7e3..2bf02a2ba 100644 --- a/contracts/src/protocol-hook-pkg/ProtocolHookMediator.sol +++ b/contracts/src/protocol-hook-pkg/ProtocolHookMediator.sol @@ -11,6 +11,7 @@ import {IProtocolAdminPanel} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminPa import {IProtocolAdminClient} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminClient.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {InitializableBase} from "compose-extensions/LibInitializable.sol"; +import {PoolId, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; interface IProtocolHookMediator{ function initialize(IMasterHook _masterHook,IProtocolAdminClient protocolAdminClient,IPositionManager positionManager) external; @@ -68,8 +69,9 @@ contract ProtocolHookMediator is IProtocolHookMediator, Context, InitializableBa poolKey, _initialSqrtPrice ); + - return abi.encode(tick); + return abi.encode(tick, PoolIdLibrary.toId(poolKey)); } } } \ No newline at end of file diff --git a/contracts/src/protocol-pkg/ProtocolAdminClient.sol b/contracts/src/protocol-pkg/ProtocolAdminClient.sol index 8d13f03ca..68d7575bc 100644 --- a/contracts/src/protocol-pkg/ProtocolAdminClient.sol +++ b/contracts/src/protocol-pkg/ProtocolAdminClient.sol @@ -6,11 +6,11 @@ import {InitializableBase} from "compose-extensions/LibInitializable.sol"; import "Compose/access/Owner/OwnerMod.sol" as OwnerMod; import {ProtocolAdminPanel, IProtocolAdminPanel} from "./ProtocolAdminPanel.sol"; import {IProtocolAdminRegistry} from "./ProtocolAdminRegistry.sol"; -import {IProtocolFactory} from "./ProtocolFactoryFacet.sol"; +import {IProtocolFactory, IProtocolAdminPanelConsumer} from "./ProtocolFactoryFacet.sol"; import {IProtocolAdminManager, Authority} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; import {IProtocolHookMediator} from "@hook-bazaar/protocol-hook-pkg/src/ProtocolHookMediator.sol"; -import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol"; +import {PoolId, PoolKey, PoolIdLibrary} from "@uniswap/v4-core/src/types/PoolId.sol"; interface IProtocolAdminClient{ @@ -27,14 +27,24 @@ interface IProtocolAdminClient{ //================================================================================================================== - function adminPanel() external view returns(address); function nextTokenId() external view returns(uint256); //====================================PROTOCOL-CREATOR=============================================================== - function create_protocol(string calldata _name) external returns(uint256); + function create_protocol(string calldata _name) external returns(uint256, address _adminManager); event ProtocolCreated(address indexed protocolCaller, uint256 indexed tokenId, address indexed __adminManager); - function create_pool(uint256 protocolId, bytes calldata _encoded_pool_key, uint160 initialSqrtPrice) external returns(bytes32); + + function getProtocols() external returns(uint256[] memory); + function getProtocolRevenue(uint256 protocolId) external returns(uint256); + function getPoolRevenue(uint256 protocolId, PoolId poolId) external returns(uint256); + + + + //======================================POOL-CREATOR======================================================================= + function create_pool(uint256 protocolId, bytes calldata _encoded_pool_key, uint160 initialSqrtPrice) external returns(PoolId, int24); + function getProtocolActivePools(uint256 protocolId) external returns(PoolId[] memory); + function getNumberOfActivePools(uint256 protocolId) external returns(uint256); + function setProtocolHookMediator(IProtocolHookMediator _hookMediator) external; @@ -45,8 +55,13 @@ interface IProtocolAdminClient{ } +interface IOwnable{ + function owner() external view returns(address); +} + -contract ProtocolAdminClient is IProtocolAdminClient, InitializableBase{ + +contract ProtocolAdminClient is IProtocolAdminClient, IProtocolAdminPanelConsumer ,InitializableBase, IOwnable{ bytes32 constant PROTOCOL_ADMIN_CLIENT_POSITION = keccak256("hook-bazaar.protocol.admin-client"); @@ -98,53 +113,98 @@ contract ProtocolAdminClient is IProtocolAdminClient, InitializableBase{ IProtocolAdminRegistry($.admin_panel)._initialize(); } - - - + function owner() public view returns(address){ + OwnerMod.OwnerStorage storage o$ = OwnerMod.getStorage(); + return o$.owner; + } // NOTE: The caller can delegate ownership of the protocol to an __auth address, defaults to msg.sender // if __auth is 0, the name is only for visibilty - function create_protocol(string calldata _name) external onlyInitialized returns(uint256){ - + + function create_protocol(string calldata _name) external onlyInitialized returns(uint256, address){ + ProtocolAdminClientStorage storage $ = getStorage(); + uint256 _token_id = $.nextTokenId; - address _protocol_admin_manager = IProtocolAdminRegistry($.admin_panel).protocol_manager(_token_id); + address _protocol_admin_manager = IProtocolAdminRegistry($.admin_panel).setProtocolManager(_token_id, msg.sender); IProtocolFactory($.admin_panel).create_protocol(_name, _protocol_admin_manager, _token_id); - IProtocolAdminPanel($.admin_panel).unlockAdminManager(IProtocolAdminManager(_protocol_admin_manager)); emit ProtocolCreated(msg.sender, _token_id,_protocol_admin_manager); $.nextTokenId++; - return _token_id; + + return (_token_id, _protocol_admin_manager); } + + function getProtocols() external returns(uint256[] memory){ + ProtocolAdminClientStorage storage $ = getStorage(); + return IProtocolFactory($.admin_panel).getProtocols(msg.sender); + } + + function getProtocolRevenue(uint256 protocolId) external returns(uint256){} + function getPoolRevenue(uint256 protocolId, PoolId poolId) external returns(uint256){} - function create_pool(uint256 protocolId, bytes calldata _encoded_pool_key, uint160 initialSqrtPrice) external onlyInitialized returns(bytes32){ + + function create_pool(uint256 protocolId, bytes calldata _encoded_pool_key, uint160 initialSqrtPrice) external onlyInitialized returns(PoolId, int24){ ProtocolAdminClientStorage storage $ = getStorage(); console2.log("Protocol Creator:", msg.sender); bytes4 createPoolSig = msg.sig; console2.logBytes4(createPoolSig); // NOTE: With protocolId one can fetch the associated adminManager - address adminManager = IProtocolAdminRegistry($.admin_panel).protocol_manager(protocolId); - // if (!Authority($.admin_panel).canCall(msg.sender, adminManager, createPoolSig)) revert ProtocolAdminClientUnauthorizedCaller(); + address adminManager = IProtocolAdminRegistry($.admin_panel).getProtocolManager(protocolId); + bool _isPoolCreator = IProtocolAdminRegistry($.admin_panel).isPoolCreator(adminManager, msg.sender); + + if (!_isPoolCreator) revert ProtocolAdminClientUnauthorizedCaller(); PoolKey memory poolKey = abi.decode(_encoded_pool_key, (PoolKey)); - int24 _initialTick = abi.decode( + + (int24 _initialTick, PoolId poolId) = abi.decode( IProtocolHookMediator($.protocolHookMediator).notify( address(this) , createPoolSig, abi.encode(protocolId, poolKey, initialSqrtPrice)), - (int24) + (int24, PoolId) ); + IProtocolAdminRegistry($.admin_panel).addPool(adminManager, poolId); + return (poolId,_initialTick); + } + function getProtocolActivePools(uint256 protocolId) public returns(PoolId[] memory){ + ProtocolAdminClientStorage storage $ = getStorage(); + address protocolManager = IProtocolAdminRegistry($.admin_panel).getProtocolManager(protocolId); + PoolId[] memory protocolPools = IProtocolAdminRegistry($.admin_panel).getProtocolPools(protocolManager); + return protocolPools; + + // protocols per accout are stored on protocolFactory + // pools per protocol are created on protocolHookMediator + // pools per protocol MUST be each stored on ProtocolAdminManager + // one protocol can have many pools + // one pool can be attached to many protocols (this is more complex) } + + function getNumberOfActivePools(uint256 protocolId) external returns(uint256){ + return getProtocolActivePools(protocolId).length; + } + + + +// - getProtocols() --> uint256[] protocols +// - for protocol in protocols: +// - getPools(protocol) +// - getTotalRevenue(protocol) +// - getProtocolMetadata(protocol) + + + + function supportsInterface(bytes4 interfaceID) external view returns (bool){ return interfaceID == type(IProtocolAdminClient).interfaceId; } - function setProtocolHookMediator(IProtocolHookMediator _hookMediator) external{ + function setProtocolHookMediator(IProtocolHookMediator _hookMediator) external onlyInitialized{ OwnerMod.requireOwner(); ProtocolAdminClientStorage storage $ = getStorage(); $.protocolHookMediator = address(_hookMediator); diff --git a/contracts/src/protocol-pkg/ProtocolAdminManager.sol b/contracts/src/protocol-pkg/ProtocolAdminManager.sol index 1d23a9e54..648d2eae8 100644 --- a/contracts/src/protocol-pkg/ProtocolAdminManager.sol +++ b/contracts/src/protocol-pkg/ProtocolAdminManager.sol @@ -11,29 +11,60 @@ import {IComponent} from "compose-extensions/LibGenericFactory.sol"; import {IERC1155Receiver} from "Compose/interfaces/IERC1155Receiver.sol"; import "Compose/libraries/NonReentrancyMod.sol" as NonReentrancy; +import {PoolId} from "@uniswap/v4-core/src/types/PoolId.sol"; +import {DiamondLoupeFacet} from "Compose/diamond/DiamondLoupeFacet.sol"; +import {IProtocolAdminRegistry} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; +import {IProtocolAdminPanelConsumer} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; + library ProxyUtils{ - function metadata() internal pure returns(address){ - address _protocolCreator; + function metadata() internal pure returns(address _protocolCreator, address _adminPanel){ assembly{ - _protocolCreator := shr(96, calldataload(sub(calldatasize(),20))) + // Metadata is appended to calldata as abi.encodePacked(protocolCreator, adminPanel) + // Each address is 20 bytes, so last 40 bytes contain the metadata + // adminPanel is at the very end (last 20 bytes, right-aligned in last 32 bytes) + _adminPanel := calldataload(sub(calldatasize(), 32)) + // protocolCreator is 20 bytes before adminPanel + _protocolCreator := calldataload(sub(calldatasize(), 52)) } - return _protocolCreator; } } interface IProtocolAdminManager{ + + error ProtocolAdminManagerNotClone(); + error ProtocolAdminManagerInvalidContextCall(); error ProtocolAdminManagerCallerIsNotCreator(); error ProtocolAdminManagerUninitialized(); - event ProtocolAdminManagerInitialized(address indexed adminPanel, address indexed _protocolCreator); + // event ProtocolAdminManagerInitialized(address indexed adminPanel, address indexed _protocolCreator); function __self() external view returns(address); function isCreator(address _account) external view returns(bool); + + + // Throug the admin panel + function setPool(PoolId _poolId) external; + // On individual storage + function getPools() external view returns(PoolId[] memory); function delegatePoolCreatorRole(address _account) external; + function isPoolCreator(address _account) external view returns(bool); + function protocolId() external view returns(uint256); + function protocolName() external view returns(string memory); + function setURI(URI_TYPE _uriType,string calldata _uri) external; + function getURI(URI_TYPE _uriType) external view returns(string memory); +} +enum URI_TYPE{ + ZORA, + WEBSITE, + X, + FARCASTER } // NOTE: ProtocolAdminManager is an operator -contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminManager, Authority, InitializableBase{ + +// NOTE: The stroage of this contract MUST not be on ProtocolAdminClient + +contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminManager, Authority, InitializableBase, IProtocolAdminPanelConsumer{ address public immutable __self; // function __self() public view returns(address){ // return __self; @@ -45,7 +76,12 @@ contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminMan bytes32 constant STORAGE_POSITION = keccak256("wvs-finance.protocolAdminManager"); struct ProtocolAdminManagerStorage{ + address adminPanel; + bool isClone; uint256 tokenId; + string name; + mapping(URI_TYPE => string uri) uris; + PoolId[] pools; } function getStorage() internal pure returns (ProtocolAdminManagerStorage storage s) { @@ -55,24 +91,30 @@ contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminMan } } - constructor(){ - __self = address(this); + function adminPanel() public view returns(address){ + ProtocolAdminManagerStorage storage $ = getStorage(); + return $.adminPanel; } + constructor(){} - // NOTE: Creator MUST be the address that called create_protocol - - - // NOTE: The creator needs to be the caller of the create_protocol on ProtocolAdminClient - function initialize(address creator) external initializer{ + modifier onlyClone(){ ProtocolAdminManagerStorage storage $ = getStorage(); - AccessControlMod.grantRole(CREATOR, creator); - AccessControlMod.grantRole(POOL_CREATOR, creator); - // NOTE : creator is supposed to be the owner of the protocol - // which is potentially a smart accounMT , regular EOA or governance contract - emit ProtocolAdminManagerInitialized(creator, creator); + if (!$.isClone) revert ProtocolAdminManagerNotClone(); + _; } + function initialize(address creator) external initializer { + ProtocolAdminManagerStorage storage $ = getStorage(); + (address _protocolCreator, address _adminPanel) = ProxyUtils.metadata(); + $.isClone = _protocolCreator != address(0x00); + // Use adminPanel from metadata if clone, otherwise use creator (for implementation) + $.adminPanel = $.isClone ? _adminPanel : creator; + if ($.isClone){ + AccessControlMod.grantRole(CREATOR, _protocolCreator); + AccessControlMod.grantRole(POOL_CREATOR, _protocolCreator); + } + } function isCreator(address _account) public view returns(bool){ @@ -84,9 +126,29 @@ contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminMan _; } - function delegatePoolCreatorRole(address _account) external onlyCreator onlyInitialized{ + modifier onlyPoolCreator(){ + AccessControlMod.requireRole(POOL_CREATOR, msg.sender); + _; + } + + function delegatePoolCreatorRole(address _account) external onlyCreator{ AccessControlMod.grantRole(POOL_CREATOR, _account); } + + function setURI(URI_TYPE _uriType,string calldata _uri) external onlyCreator onlyClone{ + ProtocolAdminManagerStorage storage $ = getStorage(); + $.uris[_uriType] = _uri; + } + + function getURI(URI_TYPE _uriType) external onlyClone view returns(string memory){ + ProtocolAdminManagerStorage storage $ = getStorage(); + return $.uris[_uriType]; + } + + function protocolName() external onlyClone view returns(string memory) { + ProtocolAdminManagerStorage storage $ = getStorage(); + return $.name; + } // TODO: Function is only callable during mints triggered by the create_protocol flow ... modifier nonReentrant(){ @@ -97,17 +159,26 @@ contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminMan function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data) external - onlyInitialized + onlyClone nonReentrant returns (bytes4){ ProtocolAdminManagerStorage storage $ = getStorage(); + $.tokenId = _id; + $.name = abi.decode(_data, (string)); return IERC1155Receiver.onERC1155Received.selector; // TODO: It sets the protocoll as created and this uncloks the create_pool to be called // // by the caller address, additioanlly the caller can now use this contract // to custom his protocol } + + function protocolId() external view onlyClone returns(uint256){ + ProtocolAdminManagerStorage storage $ = getStorage(); + return $.tokenId; + } + + function onERC1155BatchReceived( address _operator, @@ -122,14 +193,44 @@ contract ProtocolAdminManager is IComponent, IERC1155Receiver, IProtocolAdminMan address user, address target, bytes4 functionSig - ) external view returns (bool){ + ) public view onlyClone returns (bool){ bool _canCall; if (functionSig == bytes4(keccak256("create_pool(uint256,bytes,uint160)"))){ - _canCall = (AccessControlMod.hasRole(POOL_CREATOR, user) && target == __self); + _canCall = (AccessControlMod.hasRole(POOL_CREATOR, user)); } return _canCall; } + function isPoolCreator(address _account) external view returns(bool){ + return AccessControlMod.hasRole(POOL_CREATOR,_account); + } + // TODO: Function only callable through the create pool flow + // client --> panel --> registry --> manager + modifier onlyCreatePoolContext(){ + ProtocolAdminManagerStorage storage $ = getStorage(); + // Verify the call is coming from the adminPanel (diamond) and that addPool selector is registered + try DiamondLoupeFacet($.adminPanel).facetAddress(IProtocolAdminRegistry.addPool.selector) returns(address registryFacet){ + // Call must come from the diamond (adminPanel), and the addPool selector must be registered + if (msg.sender != $.adminPanel || registryFacet == address(0)) revert ProtocolAdminManagerInvalidContextCall(); + } catch { + revert ProtocolAdminManagerInvalidContextCall(); + } + _; + } + + // Note: Pool creator permission is checked in ProtocolAdminClient.create_pool() before calling addPool + // onlyCreatePoolContext ensures this is called only from the correct facet through the diamond + function setPool(PoolId _poolId) external onlyClone onlyCreatePoolContext{ + ProtocolAdminManagerStorage storage $ = getStorage(); + $.pools.push(_poolId); + + } + + function getPools() external view onlyClone returns(PoolId[] memory) { + ProtocolAdminManagerStorage storage $ = getStorage(); + return $.pools; + } + diff --git a/contracts/src/protocol-pkg/ProtocolAdminPanel.sol b/contracts/src/protocol-pkg/ProtocolAdminPanel.sol index 262117514..85d48daca 100644 --- a/contracts/src/protocol-pkg/ProtocolAdminPanel.sol +++ b/contracts/src/protocol-pkg/ProtocolAdminPanel.sol @@ -4,16 +4,17 @@ pragma solidity 0.8.30; import {IERC1155} from "Compose/interfaces/IERC1155.sol"; import {ERC1155Facet} from "Compose/token/ERC1155/ERC1155Facet.sol"; -import {IProtocolFactory} from "./ProtocolFactoryFacet.sol"; +import {IProtocolFactory, IProtocolAdminPanelConsumer} from "./ProtocolFactoryFacet.sol"; import "Compose/access/Owner/OwnerMod.sol" as OwnerMod; import {IProtocolAdminRegistry, IGenericFactory} from "./ProtocolAdminRegistry.sol"; import {IProtocolAdminClient} from "./ProtocolAdminClient.sol"; import {IProtocolHookMediator} from "@hook-bazaar/protocol-hook-pkg/src/ProtocolHookMediator.sol"; import "Compose/diamond/DiamondMod.sol" as DiamondMod; +import {DiamondLoupeFacet} from "Compose/diamond/DiamondLoupeFacet.sol"; + import {IProtocolAdminManager, Authority} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; // // NOTE: This contract is the interaction point for protocol -// // developers, AI agents - +// // developers, AI agents interface IProtocolAdminPanel{ error ProtocolAdminPanelAlreadyInitialized(); @@ -25,7 +26,7 @@ interface IProtocolAdminPanel{ //==============================CREATE-PROTOCOL-FLOW=================================================== - function unlockAdminManager(IProtocolAdminManager _adminManager) external; + // function unlockAdminManager(IProtocolAdminManager _adminManager) external; @@ -59,6 +60,18 @@ contract ProtocolAdminPanel is IProtocolAdminPanel{ OwnerMod.OwnerStorage storage o$ = OwnerMod.getStorage(); o$.owner = msg.sender; $._initialized = false; + DiamondMod.FacetCut[] memory loupeFacetCut = new DiamondMod.FacetCut[](uint256(0x01)); + { + bytes4[] memory _interface = new bytes4[](uint256(0x04)); + _interface[0x00] = DiamondLoupeFacet.facetAddress.selector; + _interface[0x01] = DiamondLoupeFacet.facets.selector; + _interface[0x02] = DiamondLoupeFacet.facetFunctionSelectors.selector; + _interface[0x03] = DiamondLoupeFacet.facetAddresses.selector; + loupeFacetCut[0x00] = DiamondMod.FacetCut(address(new DiamondLoupeFacet()), DiamondMod.FacetCutAction.Add, _interface); + + } + DiamondMod.addFacets(loupeFacetCut); + } function initialize( @@ -74,30 +87,30 @@ contract ProtocolAdminPanel is IProtocolAdminPanel{ //TODO: Introspection checks ... DiamondMod.FacetCut[] memory _cut = new DiamondMod.FacetCut[](uint256(0x02)); { - bytes4[] memory _interface = new bytes4[](uint256(0x06)); + bytes4[] memory _interface = new bytes4[](uint256(0x07)); _interface[0x00] = _protocol_factory.__initialize.selector; - _interface[0x01] = _protocol_factory.adminPanel.selector; - _interface[0x02] = _protocol_factory.baseURI.selector; - _interface[0x03] = _protocol_factory.create_protocol.selector; - _interface[0x04] = IERC1155.balanceOf.selector; - _interface[0x05] = IERC1155.uri.selector; - + _interface[0x01] = _protocol_factory.baseURI.selector; + _interface[0x02] = _protocol_factory.create_protocol.selector; + _interface[0x03] = IERC1155.balanceOf.selector; + _interface[0x04] = IERC1155.uri.selector; + _interface[0x05] = _protocol_factory.getProtocols.selector; + _interface[0x06] = IProtocolAdminPanelConsumer.adminPanel.selector; + _cut[0x00] = DiamondMod.FacetCut(address(_protocol_factory), DiamondMod.FacetCutAction.Add, _interface); } - { - bytes4[] memory _interface = new bytes4[](uint256(0x04)); - - _interface[0x00] = _protocol_admin_registry._initialize.selector; - _interface[0x01] = _protocol_admin_registry.protocol_manager.selector; - _interface[0x02] = _protocol_admin_registry.adminManagerTemplate.selector; - _interface[0x03] = _protocol_admin_registry.upgradeAdmin.selector; - // _interface[0x04] = _protocol_admin_registry.isUpgradeAdmin.selector; - // _interface[0x05] = IERC165.supportsInterface.selector; - + { + bytes4[] memory _interface = new bytes4[](uint256(0x08)); + + _interface[0x00] = _protocol_admin_registry._initialize.selector; + _interface[0x01] = _protocol_admin_registry.setProtocolManager.selector; + _interface[0x02] = _protocol_admin_registry.getProtocolManager.selector; + _interface[0x03] = _protocol_admin_registry.adminManagerTemplate.selector; + _interface[0x04] = _protocol_admin_registry.upgradeAdmin.selector; + _interface[0x05] = _protocol_admin_registry.addPool.selector; + _interface[0x06] = _protocol_admin_registry.getProtocolPools.selector; + _interface[0x07] = _protocol_admin_registry.isPoolCreator.selector; _cut[0x01] = DiamondMod.FacetCut(address(_protocol_admin_registry), DiamondMod.FacetCutAction.Add, _interface); - - } DiamondMod.addFacets(_cut); @@ -105,39 +118,6 @@ contract ProtocolAdminPanel is IProtocolAdminPanel{ } - - -// function setProtocolHookMediator(IProtocolHookMediator _hookMediator) external{ -// // OwnerMod.requireOwner(); -// ProtocolAdminPanelStorage storage $ = getStorage(); -// $.protocolHookMediator = _hookMediator; -// } - -// function protocolHookMediator() public view returns(IProtocolHookMediator){ -// ProtocolAdminPanelStorage storage $ = getStorage(); -// return $.protocolHookMediator; -// } - - function unlockAdminManager(IProtocolAdminManager _adminManager) external{ - DiamondMod.FacetCut[] memory _cut = new DiamondMod.FacetCut[](uint256(0x01)); - bytes4[] memory _interface = new bytes4[](uint256(0x02)); - _interface[0] = IProtocolAdminManager.delegatePoolCreatorRole.selector; - _interface[1] = Authority.canCall.selector; - _cut[0x00] = DiamondMod.FacetCut(address(_adminManager), DiamondMod.FacetCutAction.Add, _interface); - - DiamondMod.addFacets(_cut); - - } - - - - // TODO: It must verify the _account is compliant - // with the adminManager, msg.sender MUST be - // ProtocolAdminClient - // NOTE: Checks - - // NOTE: After checks - // If first time enabling create pool. Enable it fallback() external payable { DiamondMod.diamondFallback(); } diff --git a/contracts/src/protocol-pkg/ProtocolAdminRegistry.sol b/contracts/src/protocol-pkg/ProtocolAdminRegistry.sol index 05c3fade0..2cf1caf42 100644 --- a/contracts/src/protocol-pkg/ProtocolAdminRegistry.sol +++ b/contracts/src/protocol-pkg/ProtocolAdminRegistry.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity >=0.8.30; +import {console2} from "forge-std/console2.sol"; import {LibGenericFactory} from "compose-extensions/LibGenericFactory.sol"; import "compose-extensions/GenericFactoryMod.sol" as GenericFactoryMod; import {GenericFactory} from "@euler/GenericFactory/GenericFactory.sol"; @@ -8,10 +9,18 @@ import {InitializableBase} from "compose-extensions/LibInitializable.sol"; import "compose-extensions/InitializableMod.sol" as InitializableMod; import "Compose/access/AccessControl/AccessControlMod.sol" as AccessControlMod; -import {ProtocolAdminManager} from "./ProtocolAdminManager.sol"; +import {ProtocolAdminManager, IProtocolAdminManager} from "./ProtocolAdminManager.sol"; +import {Authority} from "solmate/src/auth/Auth.sol"; + // import "./ProtocolAdminClient.sol"; import {IERC165} from "forge-std/interfaces/IERC165.sol"; +import {PoolId} from "@uniswap/v4-core/src/types/PoolId.sol"; + + +import {DiamondLoupeFacet} from "Compose/diamond/DiamondLoupeFacet.sol"; +import {IProtocolAdminPanelConsumer} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; + interface IGenericFactory{ function implementation() external view returns(address); function upgradeAdmin() external view returns(address); @@ -24,15 +33,10 @@ interface IGenericFactory{ function getProxyListLength() external view returns (uint256); function getProxyListSlice(uint256 start, uint256 end) external view returns (address[] memory list); } -interface IVersionControl{ - // TODO: This needs protection for attackers altering versions on re-entrancy or multicalls - function version() external view returns(uint64); - function updateVersion() external returns(uint64); - -} interface IProtocolAdminRegistry{ + error ProtocolAdminRegistryInvalidTokenId(); error ProtocolAdminRegistryUninitialized(); error ProtocolAdminRegistryNotDelegateCall(); @@ -42,13 +46,19 @@ interface IProtocolAdminRegistry{ function __self() external view returns(address); function _initialize() external; - function protocol_manager(uint256 _protocolId) external returns(address); function adminManagerTemplate() external returns(address); function upgradeAdmin() external returns(address); + + function setProtocolManager(uint256 _protocolId,address _protocolCreator) external returns(address); + function getProtocolManager(uint256 _protcolId) external view returns(address); + + function addPool(address _protocolAdminManager, PoolId _poolId) external; + function getProtocolPools(address _protocolAdminManager) external returns(PoolId[] memory); + function isPoolCreator(address _adminManager,address _account) external returns(bool); } -contract ProtocolAdminRegistry is IVersionControl ,IProtocolAdminRegistry, InitializableBase{ +contract ProtocolAdminRegistry is IProtocolAdminRegistry, InitializableBase, IProtocolAdminPanelConsumer{ // NOTE: delegate call only guard address immutable public __self; @@ -65,6 +75,7 @@ contract ProtocolAdminRegistry is IVersionControl ,IProtocolAdminRegistry, Initi struct ProtocolAdminRegistryStorage{ // NOTE: One protocol has one admin + address adminPanel; uint64 version; mapping(uint256 tokenId => address protocol_manager) protocol_managers; mapping(uint256 tokenId => address protocol_admin_operator) protocol_admin_operators; @@ -80,34 +91,29 @@ contract ProtocolAdminRegistry is IVersionControl ,IProtocolAdminRegistry, Initi } } + function adminPanel() public view returns(address){ + ProtocolAdminRegistryStorage storage $ = getStorage(); + return $.adminPanel; + } + function version() public view returns(uint64){ ProtocolAdminRegistryStorage storage $ = getStorage(); return $.version; } // TODO: This needs access control protection - function updateVersion() public returns(uint64){ + function _updateVersion() private returns(uint64){ ProtocolAdminRegistryStorage storage $ = getStorage(); $.version = $.version == uint64(0x00) ? STARTER_VERSION : $.version++; return $.version; } - - - - function _initialize() external reinitializer(updateVersion()){ + function _initialize() external reinitializer(_updateVersion()){ ProtocolAdminRegistryStorage storage $ = getStorage(); - LibGenericFactory.GenericFactoryStorage storage g$ = LibGenericFactory.getStorage(); g$.upgradeAdmin = msg.sender; - // TODO: Further introspection checks are suggested here - // if (msg.sender.code.length == uint256(0x00)) revert ProtocolAdminRegistryInvalidInitializer(); - // NOTE: The msg.sender in our implementation - // is the ProtocolAdminPanel - + $.adminPanel = address(this); LibGenericFactory.setImplementation(address(new ProtocolAdminManager())); - - } @@ -130,47 +136,48 @@ contract ProtocolAdminRegistry is IVersionControl ,IProtocolAdminRegistry, Initi // // NOTE The function can only be called through delegate // // call, and the delegate caller must be the admin panel - function onlyAdminPanel() private { - if (address(this) == __self) revert ProtocolAdminRegistryNotDelegateCall(); - // if (address(this) != upgradeAdmin()) revert ProtocolAdminRegistryInvalidDelegateCaller(); - + + modifier onlyAdminPanel(){ + ProtocolAdminRegistryStorage storage $ = getStorage(); + address registryOnPanel = DiamondLoupeFacet($.adminPanel).facetAddress(IProtocolAdminRegistry.setProtocolManager.selector); + if (address(this) == __self || registryOnPanel != __self) revert ProtocolAdminRegistryNotDelegateCall(); + _; } function upgradeAdmin() public initialized returns(address){ return LibGenericFactory.upgradeAdmin(); } - function protocol_manager(uint256 _protocolId) external initialized returns(address){ - if (_protocolId == uint256(0x00)) return address(0x00); + function setProtocolManager(uint256 _protocolId, address _protocolCreator) external initialized onlyAdminPanel returns(address){ ProtocolAdminRegistryStorage storage $ = getStorage(); if ($.protocol_managers[_protocolId] == address(0x00)){ - // NOTE: This protects for the delegate call - - onlyAdminPanel(); - // TODO: Now we need protection for the Context to be msg.sender == protocolAdminClient AND - // msg.sig == IProtocolAdminClient.create_protocol.selector - // Regiostry does not reference client - - // TODO: This - // msg.sender == protocolAdminClient needs to be checked with introspection on CLient since - // if ( - // !IERC165(address(this)).supportsInterface(type(IProtocolAdminClient).interfaceId) - // || - // _parentSig != CREATE_PROTOCOL_CLIENT_SIG - // ) revert ProtocolAdminRegistryInvalidContextCall(); - - $.protocol_managers[_protocolId] = LibGenericFactory.createProxy(adminManagerTemplate(), false, abi.encode("0x00")); + // Pass both protocolCreator and adminPanel (address(this) in delegatecall context) + $.protocol_managers[_protocolId] = LibGenericFactory.createProxy(adminManagerTemplate(), false, abi.encodePacked(_protocolCreator, address(this))); } return $.protocol_managers[_protocolId]; } - function protocolManagers(uint256 _tokenId) external returns(address){ + function getProtocolManager(uint256 _tokenId) external view returns(address){ ProtocolAdminRegistryStorage storage $ = getStorage(); return $.protocol_managers[_tokenId]; } + function isPoolCreator(address _adminManager, address _account) external returns(bool){ + // TODO: Targert is the DEX engine entry point address + return Authority(_adminManager).canCall(_account, address(0x00), bytes4(keccak256("create_pool(uint256,bytes,uint160)"))); + } + + function addPool(address _protocolAdminManager, PoolId _poolId) external onlyAdminPanel{ + IProtocolAdminManager(_protocolAdminManager).setPool(_poolId); + } + + function getProtocolPools(address _protocolAdminManager) external returns(PoolId[] memory){ + return IProtocolAdminManager(_protocolAdminManager).getPools(); + } + + } \ No newline at end of file diff --git a/contracts/src/protocol-pkg/ProtocolFactoryFacet.sol b/contracts/src/protocol-pkg/ProtocolFactoryFacet.sol index 54c199de8..6083494bb 100644 --- a/contracts/src/protocol-pkg/ProtocolFactoryFacet.sol +++ b/contracts/src/protocol-pkg/ProtocolFactoryFacet.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.30; import {console2} from "forge-std/console2.sol"; import {InitializableBase} from "compose-extensions/LibInitializable.sol"; +import {EnumerableMap} from "../../lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol"; import {IERC165} from "forge-std/interfaces/IERC165.sol"; @@ -12,6 +13,26 @@ import "Compose/token/ERC1155/ERC1155Mod.sol" as ERC1155Mod; import {ERC1155Facet} from "Compose/token/ERC1155/ERC1155Facet.sol"; import "Compose/access/Owner/OwnerMod.sol" as OwnerMod; +import {DiamondLoupeFacet} from "Compose/diamond/DiamondLoupeFacet.sol"; + +interface IProtocolAdminPanelConsumer{ + function adminPanel() external view returns(address); +} + +library ArrayUtils{ + + function indexOf(uint256[] memory arr, uint256 target) internal pure returns (int) { + for (uint i = 0; i < arr.length; i++) { + if (arr[i] == target) { + return int(i); // Found + } + } + return -1; // Not found + } + +} + + interface IProtocolFactory{ function __self() external view returns(address); @@ -19,11 +40,11 @@ interface IProtocolFactory{ error ProtocolFactoryFacetInvalidInitializer(); error ProtocolFactoryFacetNotDelegateCall(); error ProtocolFactoryFacetInvalidDelegateCaller(); - + error ProtocolFactoryAlreadyTaken(); function __initialize(string calldata _baseURI) external; function baseURI() external view returns(string memory); - function adminPanel() external view returns(address); function create_protocol(string calldata _name, address _protocol_admin, uint256 _token_id) external; + function getProtocols(address _account) external returns(uint256[] memory); } @@ -37,7 +58,7 @@ interface IProtocolFactory{ // constructor() GenericFactory(msg.sender){} // } -contract ProtocolFactoryFacet is IProtocolFactory, InitializableBase{ +contract ProtocolFactoryFacet is InitializableBase, IProtocolAdminPanelConsumer, IProtocolFactory{ address immutable public __self; constructor(){ @@ -49,6 +70,10 @@ contract ProtocolFactoryFacet is IProtocolFactory, InitializableBase{ struct ProtocolFactoryStorage{ address adminPanel; + mapping(address _creator => uint256[] creatorProtocols) protocols; + uint256[] names; + + //address 1-->*uint256[] } function getStorage() internal pure returns (ProtocolFactoryStorage storage $) { @@ -72,37 +97,48 @@ contract ProtocolFactoryFacet is IProtocolFactory, InitializableBase{ } + + function baseURI() public view returns(string memory){ ERC1155Mod.ERC1155Storage storage e1155$ = ERC1155Mod.getStorage(); return e1155$.baseURI; } - - function adminPanel() public view returns(address){ - ProtocolFactoryStorage storage $ = getStorage(); - return $.adminPanel; - } - // TODO: This needs to check protocolAdmin is compliant and tokenId // is compliant too // TODO: This is called only on delegate call by the adminPanel modifier onlyAdminPanel(){ - if (address(this) == __self) revert ProtocolFactoryFacetNotDelegateCall(); - if (address(this) != adminPanel()) revert ProtocolFactoryFacetInvalidDelegateCaller(); + ProtocolFactoryStorage storage $ = getStorage(); + address factoryOnPanel = DiamondLoupeFacet($.adminPanel).facetAddress(IProtocolFactory.create_protocol.selector); + if (address(this) == __self || factoryOnPanel != __self) revert ProtocolFactoryFacetInvalidDelegateCaller(); + _; + } + + function adminPanel() external view returns(address){ + ProtocolFactoryStorage storage $ = getStorage(); + return $.adminPanel; + } + + // This is only callable after the contract has been initialized + // NOTE: This also needs protection against reentrancy + modifier nonRepeatedNames(string calldata _name){ + ProtocolFactoryStorage storage $ = getStorage(); + if (ArrayUtils.indexOf($.names,uint256(keccak256(bytes(_name)))) != int256(-1)) revert ProtocolFactoryAlreadyTaken(); _; } - // This is only callable after the contract has been initialized - // NOTE: This also needs protection against reentrancy - function create_protocol(string calldata _name,address _protocol_admin, uint256 _token_id) external onlyInitialized onlyAdminPanel{ - // TODO: This library must also expose a payload to the protocol admin - // and perform checks against the protocol_admin - // TODO: This is missing the data param on the mint function - console2.log("Caller", msg.sender); - ERC1155Mod.mint(_protocol_admin,_token_id,1,abi.encode("0x00")); - // NOTE: Needs to concat /ProtocolDashboard/protocolName ?= _name + function create_protocol(string calldata _name,address _protocol_admin, uint256 _token_id) external onlyInitialized onlyAdminPanel nonRepeatedNames(_name){ + ProtocolFactoryStorage storage $ = getStorage(); + ERC1155Mod.mint(_protocol_admin,_token_id,1,abi.encode(_name)); ERC1155Mod.setTokenURI(_token_id, _name); + $.protocols[msg.sender].push(_token_id); + $.names.push(uint256(keccak256(bytes(_name)))); + } + + function getProtocols(address _account) external returns(uint256[] memory){ + ProtocolFactoryStorage storage $ = getStorage(); + return $.protocols[_account]; } @@ -116,6 +152,5 @@ contract ProtocolFactoryFacet is IProtocolFactory, InitializableBase{ return e1155$.tokenURIs[_id]; } - fallback() external payable{} } \ No newline at end of file diff --git a/contracts/test/master-hook-pkg/utils/ForkUtils.sol b/contracts/test/master-hook-pkg/utils/ForkUtils.sol index acef39c50..2cf0388d9 100644 --- a/contracts/test/master-hook-pkg/utils/ForkUtils.sol +++ b/contracts/test/master-hook-pkg/utils/ForkUtils.sol @@ -7,6 +7,7 @@ library EthereumMainnet{ address constant CREATE2_DEPLOYER = address(0x4e59b44847b379578588920cA78FbF26c0B4956C); address constant POOL_MANAGER = address(0x000000000004444c5dc75cB358380D2e3dE08A90); + address constant STATE_VIEW = address(0x7fFE42C4a5DEeA5b0feC41C94C136Cf115597227); address constant POSITION_MANAGER = address(0xbD216513d74C8cf14cf4747E6AaA6420FF64ee9e); address constant UNIVERSAL_ROUTER = address(0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af); bytes32 constant ETH_USDC_0_3 = bytes32(0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d); diff --git a/contracts/test/protocol-pkg/ProtocolAdminClient.fork.t.sol b/contracts/test/protocol-pkg/ProtocolAdminClient.fork.t.sol index e6892e545..6d9c36a07 100644 --- a/contracts/test/protocol-pkg/ProtocolAdminClient.fork.t.sol +++ b/contracts/test/protocol-pkg/ProtocolAdminClient.fork.t.sol @@ -6,6 +6,7 @@ import "@hook-bazaar/protocol-pkg/src/ProtocolAdminClient.sol"; import "@hook-bazaar/protocol-hook-pkg/src/ProtocolHookMediator.sol"; import {ProtocolAdminRegistry} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; import {ProtocolFactoryFacet} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; +import {IStateView} from "@uniswap/v4-periphery/src/interfaces/IStateView.sol"; contract ProtocolAdminClientForkTest is Test, SwapHelper, LiquidityHelper{ bool forked; @@ -16,13 +17,15 @@ contract ProtocolAdminClientForkTest is Test, SwapHelper, LiquidityHelper{ PoolKey poolKey; - IMasterHook masterHook; - IHooks allHook; + address masterHook; + address allHook; - IProtocolAdminClient protocolAdminClient; - IProtocolHookMediator protocolHookMediator; - IProtocolAdminRegistry protocolAdminRegistry; - IProtocolFactory protocolFactory; + address protocolAdminClient; + address protocolHookMediator; + + address protocolAdminRegistry; + address protocolFactory; + address adminPanel; IPoolManager poolManager; @@ -46,20 +49,20 @@ contract ProtocolAdminClientForkTest is Test, SwapHelper, LiquidityHelper{ lpm = IPositionManager(EthereumMainnet.POSITION_MANAGER); swapRouter = IUniversalRouter(EthereumMainnet.UNIVERSAL_ROUTER); - protocolAdminClient = IProtocolAdminClient(address(new ProtocolAdminClient())); - protocolAdminRegistry = IProtocolAdminRegistry(address(new ProtocolAdminRegistry())); - protocolFactory = IProtocolFactory(address(new ProtocolFactoryFacet())); + protocolAdminClient = address(new ProtocolAdminClient()); + protocolAdminRegistry = address(new ProtocolAdminRegistry()); + protocolFactory = address(new ProtocolFactoryFacet()); - masterHook = IMasterHook(MasterHook(payable(address(uint160((type(uint160).max & clearAllHookPermissionsMask) | Hooks.ALL_HOOK_MASK))))); - allHook = IHooks(address(AllHook(payable(address(uint160(((type(uint160).max & clearAllHookPermissionsMask) | Hooks.ALL_HOOK_MASK) & (type(uint160).max - 2 ** 156))))))); + masterHook = address(IMasterHook(MasterHook(payable(address(uint160((type(uint160).max & clearAllHookPermissionsMask) | Hooks.ALL_HOOK_MASK)))))); + allHook = address(AllHook(payable(address(uint160(((type(uint160).max & clearAllHookPermissionsMask) | Hooks.ALL_HOOK_MASK) & (type(uint160).max - 2 ** 156)))))); - deployCodeTo("MasterHook.sol:MasterHook", abi.encode("0x00"), address(masterHook)); - deployCodeTo("AllHook.sol:AllHook", abi.encode(address(poolManager)), address(allHook)); + deployCodeTo("MasterHook.sol:MasterHook", abi.encode("0x00"), masterHook); + deployCodeTo("AllHook.sol:AllHook", abi.encode(address(poolManager)), allHook); - protocolHookMediator = IProtocolHookMediator(address(new ProtocolHookMediator())); + protocolHookMediator = address(new ProtocolHookMediator()); - poolKey = PoolKey(Currency.wrap(EthereumMainnet.ETH),Currency.wrap(EthereumMainnet.USDC), uint24(0x00), int24(0x3c), IHooks(address(masterHook))); + poolKey = PoolKey(Currency.wrap(EthereumMainnet.ETH),Currency.wrap(EthereumMainnet.USDC), uint24(0x00), int24(0x3c), IHooks(masterHook)); forked = true; @@ -80,23 +83,56 @@ contract ProtocolAdminClientForkTest is Test, SwapHelper, LiquidityHelper{ //========================TEST============================================ vm.startPrank(any_caller); vm.expectRevert(); - protocolAdminClient.create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); + IProtocolAdminClient(protocolAdminClient).create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); vm.stopPrank(); //=====================POST-CONDITIONS==================================== } + function test__fork__setProtocolHookMediatorMustSucceed() public { + //======================PRE-CONDITIONS=========================== + vm.startPrank(protocol_admin); + IProtocolAdminClient(protocolAdminClient).initialize(IProtocolAdminRegistry(protocolAdminRegistry),IProtocolFactory(protocolFactory), "localhost"); + vm.stopPrank(); + + //========================TEST================================== + vm.prank(protocol_admin); + IProtocolAdminClient(protocolAdminClient).setProtocolHookMediator(IProtocolHookMediator(protocolHookMediator)); + + + //======================POST-CONDITIONS======================= + assertEq(protocolHookMediator, address(IProtocolAdminClient(protocolAdminClient).protocolHookMediator())); + + } + + function test__fork__NotOwnerSetProtocolHookMediatorMustRevert() public { + //======================PRE-CONDITIONS=========================== + vm.startPrank(protocol_admin); + IProtocolAdminClient(protocolAdminClient).initialize(IProtocolAdminRegistry(protocolAdminRegistry),IProtocolFactory(protocolFactory), "localhost"); + vm.stopPrank(); + //========================TEST================================== + vm.prank(any_caller); + vm.expectRevert(); + IProtocolAdminClient(protocolAdminClient).setProtocolHookMediator(IProtocolHookMediator(protocolHookMediator)); + + + //======================POST-CONDITIONS======================= + } + function test__fork__createPoolWitNoProtocolAttachedMustRevert() public{ //=======================PRE-CONDITIONS============================ vm.startPrank(protocol_admin); - protocolAdminClient.initialize(protocolAdminRegistry,protocolFactory, "localhost"); + IProtocolAdminClient(protocolAdminClient).initialize(IProtocolAdminRegistry(protocolAdminRegistry),IProtocolFactory(protocolFactory), "localhost"); + adminPanel = IProtocolAdminPanelConsumer(protocolAdminClient).adminPanel(); + vm.stopPrank(); + //==========================TEST=================================== vm.startPrank(any_caller); vm.expectRevert(); - protocolAdminClient.create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); + IProtocolAdminClient(protocolAdminClient).create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); vm.stopPrank(); //========================POST-CONDITIONS=========================== } @@ -104,40 +140,51 @@ contract ProtocolAdminClientForkTest is Test, SwapHelper, LiquidityHelper{ function test__fork__createPoolWithUnauthorizedPermsMustRevert() public { //====================PRE-CONDITIONS==================================== vm.prank(protocol_admin); - protocolAdminClient.initialize(protocolAdminRegistry, protocolFactory, "localhost"); - + IProtocolAdminClient(protocolAdminClient).initialize(IProtocolAdminRegistry(protocolAdminRegistry), IProtocolFactory(protocolFactory), "localhost"); + adminPanel = IProtocolAdminPanelConsumer(protocolAdminClient).adminPanel(); vm.prank(any_caller); - protocolAdminClient.create_protocol("MyProtocol1"); + + IProtocolAdminClient(protocolAdminClient).create_protocol("MyProtocol1"); //=======================TEST=========================================== vm.prank(any_caller2); vm.expectRevert(); - protocolAdminClient.create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); + IProtocolAdminClient(protocolAdminClient).create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); //======================POST-CONDITIONS================================== } function test__fork__createPoolMustSucceed() public { //===================PRE-CONDITIONS=================== vm.startPrank(protocol_admin); - masterHook.initialize(address(poolManager), address(allHook)); - protocolAdminClient.initialize(protocolAdminRegistry, protocolFactory, "localhost"); - protocolHookMediator.initialize(masterHook,protocolAdminClient,lpm); - protocolAdminClient.setProtocolHookMediator(protocolHookMediator); + IMasterHook(masterHook).initialize(address(poolManager), address(allHook)); + IProtocolAdminClient(protocolAdminClient).initialize(IProtocolAdminRegistry(protocolAdminRegistry), IProtocolFactory(protocolFactory), "localhost"); + IProtocolHookMediator(protocolHookMediator).initialize(IMasterHook(masterHook),IProtocolAdminClient(protocolAdminClient),lpm); + IProtocolAdminClient(protocolAdminClient).setProtocolHookMediator(IProtocolHookMediator(protocolHookMediator)); vm.stopPrank(); - vm.prank(any_caller); - protocolAdminClient.create_protocol("MyProtocol1"); + vm.prank(any_caller); + (uint256 protocolId, address adminManager) = IProtocolAdminClient(protocolAdminClient).create_protocol("MyProtocol1"); + PoolId[] memory prevProtocolPools = IProtocolAdminClient(protocolAdminClient).getProtocolActivePools(protocolId); + //=====================TEST============================= vm.prank(any_caller); - protocolAdminClient.create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); + (PoolId poolId, int24 _initialTick) = IProtocolAdminClient(protocolAdminClient).create_pool(1,abi.encode(poolKey), Constants.SQRT_PRICE_1_1); //======================POST-CONDITIONS======================== + PoolId[] memory postProtocolPools = IProtocolAdminClient(protocolAdminClient).getProtocolActivePools(protocolId); + + assertEq(PoolId.unwrap(PoolIdLibrary.toId(poolKey)),PoolId.unwrap(poolId)); + (, int24 tick,, uint24 lpFee) = IStateView(EthereumMainnet.STATE_VIEW).getSlot0(poolId); + assertEq(tick, _initialTick); + assertEq(lpFee, poolKey.fee); + // assertEq(prevProtocolPools.length + uint256(0x01),postProtocolPools.length); + assertEq(PoolId.unwrap(poolId),PoolId.unwrap(postProtocolPools[prevProtocolPools.length])); } diff --git a/contracts/test/protocol-pkg/ProtocolAdminClient.t.sol b/contracts/test/protocol-pkg/ProtocolAdminClient.t.sol index 5bbb76dc6..ab6742010 100644 --- a/contracts/test/protocol-pkg/ProtocolAdminClient.t.sol +++ b/contracts/test/protocol-pkg/ProtocolAdminClient.t.sol @@ -2,11 +2,12 @@ pragma solidity 0.8.30; import {Test, console2} from "forge-std/Test.sol"; -import {ProtocolAdminClient, IProtocolAdminClient} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminClient.sol"; +import {ProtocolAdminClient, IProtocolAdminClient, IOwnable} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminClient.sol"; import {ProtocolAdminRegistry, IProtocolAdminRegistry} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; -import {ProtocolFactoryFacet, IProtocolFactory} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; - +import {ProtocolFactoryFacet, IProtocolFactory, IProtocolAdminPanelConsumer} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; +import {IProtocolAdminManager} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; + contract ProtocolAdminClientTest is Test{ @@ -47,14 +48,18 @@ contract ProtocolAdminClientTest is Test{ ); vm.stopPrank(); //================POST-CONDITIONS==================== - assertNotEq(IProtocolAdminClient(protocol_admin_client).adminPanel(), address(0x00)); - assertGt(IProtocolAdminClient(protocol_admin_client).adminPanel().code.length, uint256(0x00)); + assertEq(protocol_deployer, IOwnable(protocol_admin_client).owner()); + assertNotEq(IProtocolAdminPanelConsumer(protocol_admin_client).adminPanel(), address(0x00)); + assertGt(IProtocolAdminPanelConsumer(protocol_admin_client).adminPanel().code.length, uint256(0x00)); + } - function test__unit__initializeAdminProtocolMustSucceed() public { + function test__unit__initializeDoubleMustRevert() public { //======================PRE-CONDITIONS============================= + test__unit__initializeMustSucceed(); //=========================TEST=================================== vm.startPrank(protocol_deployer); + vm.expectRevert(); IProtocolAdminClient(protocol_admin_client).initialize( IProtocolAdminRegistry(protocol_admin_registry), IProtocolFactory(protocol_factory_facet), @@ -66,18 +71,31 @@ contract ProtocolAdminClientTest is Test{ function test__unit__createProtocolMustSucceed() public { //=================PRE-CONDITIONS======================= - vm.startPrank(protocol_deployer); - IProtocolAdminClient(protocol_admin_client).initialize( - IProtocolAdminRegistry(protocol_admin_registry), - IProtocolFactory(protocol_factory_facet), - "http://localhost:3000/metadata/" - ); - vm.stopPrank(); + test__unit__initializeMustSucceed(); + uint256 beforeTokenId = IProtocolAdminClient(protocol_admin_client).nextTokenId(); //=======================TEST================================ vm.startPrank(any_caller); - IProtocolAdminClient(protocol_admin_client).create_protocol("DefiHub"); + (uint256 _protocolId, address _protocolAdminManager) = IProtocolAdminClient(protocol_admin_client).create_protocol("DefiHub"); vm.stopPrank(); //=====================POST-CONDITIONS===================== + //======================CLIENT============================= + uint256 afterTokenId = IProtocolAdminClient(protocol_admin_client).nextTokenId(); + assertEq(afterTokenId,beforeTokenId + uint256(0x01)); + assertEq(beforeTokenId, _protocolId); + //================ADMIN-MANAGER==================================== + assertEq(_protocolId, IProtocolAdminManager(_protocolAdminManager).protocolId()); + assertEq(IProtocolAdminPanelConsumer(protocol_admin_client).adminPanel(),IProtocolAdminPanelConsumer(_protocolAdminManager).adminPanel()); + } + + function test__unit__createProtocolsWithDuplicateNamesMustRevert() public{ + //==================PRE-CONDITIONS======================================== + test__unit__createProtocolMustSucceed(); + //======================TEST============================================= + vm.startPrank(any_caller); + vm.expectRevert(); + IProtocolAdminClient(protocol_admin_client).create_protocol("DefiHub"); + vm.stopPrank(); + //===================POST-CONDITIONS===================================== } } \ No newline at end of file diff --git a/contracts/test/protocol-pkg/ProtocolAdminManager.t.sol b/contracts/test/protocol-pkg/ProtocolAdminManager.t.sol index 079e74c21..676425f14 100644 --- a/contracts/test/protocol-pkg/ProtocolAdminManager.t.sol +++ b/contracts/test/protocol-pkg/ProtocolAdminManager.t.sol @@ -2,35 +2,53 @@ pragma solidity >=0.8.30; import {Test, console2} from "forge-std/Test.sol"; -import {ProtocolAdminManager, IProtocolAdminManager, Authority} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; +import {ERC20Facet} from "Compose/token/ERC20/ERC20/ERC20Facet.sol"; +import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol"; +import {Currency} from "@uniswap/v4-core/src/types/Currency.sol"; + +import {ProtocolAdminManager, IProtocolAdminManager, Authority, URI_TYPE} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; import {IComponent} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; +import {GenericFactory} from "@euler/GenericFactory/GenericFactory.sol"; +import {PoolId, PoolIdLibrary, PoolKey} from "@uniswap/v4-core/src/types/PoolId.sol"; +import {IProtocolAdminPanelConsumer} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; + contract ProtocolAdminManagerTest is Test{ address protocol_admin = makeAddr("admin"); address protocol_admin_manager_impl; + address any_caller = makeAddr("anyCaller"); + address any_caller2 = makeAddr("anyCaller2"); + + address anyAddress = makeAddr("anyAddress"); + address mockAdminPanel = makeAddr("mockAdminPanel"); + address adminManagerFactory; + address adminManager; function setUp() public{ protocol_admin_manager_impl = address(new ProtocolAdminManager()); + vm.prank(protocol_admin); + adminManagerFactory = address(new GenericFactory(protocol_admin)); } - function test__unit__initializeMustSucceed() public{ + function test__unit__ImplInitializeMustSucceed() public{ //============PRE-CONDITIONS================== - + //===============TEST========================= vm.startPrank(protocol_admin); - IComponent(protocol_admin_manager_impl).initialize(protocol_admin); + IComponent(protocol_admin_manager_impl).initialize(anyAddress); vm.stopPrank(); //============POST-CONDITIONS============== - assertTrue(IProtocolAdminManager(protocol_admin_manager_impl).isCreator(protocol_admin)); + assertEq(anyAddress, IProtocolAdminPanelConsumer(protocol_admin_manager_impl).adminPanel()); + } - function test__unit__initializeDoubleMustRevert() public { + function test__unit__ImplInitializeDoubleMustRevert() public { //===============PRE-CONDITIONS===================== - test__unit__initializeMustSucceed(); + test__unit__ImplInitializeMustSucceed(); //=================TEST=============================== vm.startPrank(any_caller); vm.expectRevert(); @@ -39,21 +57,95 @@ contract ProtocolAdminManagerTest is Test{ //=================POST-CONDITIONS======================= } + + function test__unit__CloneInitializationMustSucceed() public { + //================PRE-CONDITIONS==================== + vm.prank(protocol_admin); + GenericFactory(adminManagerFactory).setImplementation(protocol_admin_manager_impl); + + //===================TEST========================== + vm.prank(any_caller); + // Pass both protocolCreator and adminPanel as metadata + adminManager = GenericFactory(adminManagerFactory).createProxy(protocol_admin_manager_impl, false, abi.encodePacked(any_caller, mockAdminPanel)); + + //=================POST-CONDITIONS================= + assertEq(IProtocolAdminPanelConsumer(adminManager).adminPanel(), mockAdminPanel); + assertTrue(IProtocolAdminManager(adminManager).isCreator(any_caller)); + assertTrue(IProtocolAdminManager(adminManager).isPoolCreator(any_caller)); + } + + function test__unit__CloneSetURIProtocolCreatorMustSucceed() public { + //====================PRE-CONDITIONS=========================== + test__unit__CloneInitializationMustSucceed(); + + //=====================TEST================================ + vm.prank(any_caller); + IProtocolAdminManager(adminManager).setURI(URI_TYPE.WEBSITE, "myProtocol.com"); + //====================POST-CONDITIONS======================== + assertEq(keccak256(bytes("myProtocol.com")), keccak256(bytes(IProtocolAdminManager(adminManager).getURI(URI_TYPE.WEBSITE)))); + } + + function test__unit__CloneSetURINotProtocolCreatorMustFail() public { + //====================PRE-CONDITIONS=========================== + test__unit__CloneInitializationMustSucceed(); + + //=====================TEST================================ + vm.prank(any_caller2); + vm.expectRevert(); + IProtocolAdminManager(adminManager).setURI(URI_TYPE.WEBSITE, "myProtocol.com"); + + //====================POST-CONDITIONS======================== + } + + function test__unit__CloneInitializationDoubleMustReveert() public { + //======================PRE-CONDITIONS============================ + test__unit__CloneInitializationMustSucceed(); + //=======================TEST===================================== + vm.prank(any_caller); + vm.expectRevert(); + IComponent(adminManager).initialize(address(0x12)); + + //=======================POST-CONDITIONS========================== + } + + function test__unit__delegatePoolCreatorRoleMustSucceed() public { //=================PRE-CONDITIONS========================== - test__unit__initializeMustSucceed(); + test__unit__CloneInitializationMustSucceed(); //==================TEST=================================== - vm.startPrank(protocol_admin); + vm.startPrank(any_caller); - IProtocolAdminManager(protocol_admin_manager_impl).delegatePoolCreatorRole(any_caller); + IProtocolAdminManager(adminManager).delegatePoolCreatorRole(any_caller2); vm.stopPrank(); //=================POST-CONDITIONS========================= - // assertTrue(Authority(protocol_admin_manager_impl).canCall(any_caller, address(0x00), bytes4(keccak256("create_pool(bytes,uint160)")))); + assertTrue(IProtocolAdminManager(adminManager).isPoolCreator(any_caller)); + assertTrue(IProtocolAdminManager(adminManager).isPoolCreator(any_caller2)); } - function test__unit__makeCallsBeforeInitializingMustFail() public { + function test__unit__setPoolsOnInvalidContextMustRevert() public { + //===================PRE-CONDITIONS =========================== + test__unit__delegatePoolCreatorRoleMustSucceed(); + + // Create PoolId before expectRevert + PoolId poolId = PoolIdLibrary.toId( + PoolKey( + Currency.wrap(address(new ERC20Facet())), + Currency.wrap(address(new ERC20Facet())), + uint24(0x00), + int24(60), + IHooks(address(0x00)) + ) + ); + //======================TEST=================================== + vm.prank(any_caller2); + vm.expectRevert(); + IProtocolAdminManager(adminManager).setPool(poolId); + //====================POST-CONDITIONS========================= + } + + function test__unit__ImplMakeCallsBeforeInitializingMustFail() public { //====================PRE-CONDITIONS======================= //======================TEST============================== @@ -67,17 +159,21 @@ contract ProtocolAdminManagerTest is Test{ function test__unit__delegatePoolCreatorRoleUnauthorizedMustRevert() public{ //====================PRE-CONDITIONS======================= - test__unit__initializeMustSucceed(); - + test__unit__CloneInitializationMustSucceed(); + //======================TEST============================== vm.startPrank(any_caller); vm.expectRevert(); - IProtocolAdminManager(protocol_admin_manager_impl).delegatePoolCreatorRole(any_caller); + IProtocolAdminManager(protocol_admin_manager_impl).delegatePoolCreatorRole(any_caller2); vm.stopPrank(); //=====================POST-CONDITIONS========================= } + + + + } diff --git a/contracts/test/protocol-pkg/ProtocolAdminPanel.t.sol b/contracts/test/protocol-pkg/ProtocolAdminPanel.t.sol index 7070280c2..cb05dfec1 100644 --- a/contracts/test/protocol-pkg/ProtocolAdminPanel.t.sol +++ b/contracts/test/protocol-pkg/ProtocolAdminPanel.t.sol @@ -3,11 +3,13 @@ pragma solidity 0.8.30; import {Test, console2} from "forge-std/Test.sol"; import {ProtocolAdminPanel, IProtocolAdminPanel} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminPanel.sol"; -import {ProtocolFactoryFacet, IProtocolFactory} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; +import {ProtocolFactoryFacet, IProtocolFactory,IProtocolAdminPanelConsumer} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; import {ProtocolAdminRegistry, IProtocolAdminRegistry} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; import {IProtocolAdminClient} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminClient.sol"; +import {IProtocolAdminManager, ProtocolAdminManager} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; import {ERC165Facet} from "Compose/interfaceDetection/ERC165/ERC165Facet.sol"; import {IERC1155} from "Compose/interfaces/IERC1155.sol"; +import {DiamondLoupeFacet} from "Compose/diamond/DiamondLoupeFacet.sol"; contract ProtocolAdminPanelTest is Test{ @@ -15,9 +17,8 @@ contract ProtocolAdminPanelTest is Test{ address protocol_admin_panel; address protocol_admin_registry; address protocol_factory_facet; - - - + address _admin_manager; + address adminManagerImpl; address protocol_deployer = makeAddr("deployer"); address any_caller = makeAddr("anyCaller"); @@ -31,18 +32,19 @@ contract ProtocolAdminPanelTest is Test{ protocol_factory_facet = address(new ProtocolFactoryFacet()); protocol_admin_registry = address(new ProtocolAdminRegistry()); + adminManagerImpl = address(new ProtocolAdminManager()); erc165 = address(new ERC165Facet()); vm.stopPrank(); - } - - function test__unit__initializeMustSucceed() public { - //===============PRE-CONDITIONS===================== vm.startPrank(protocol_deployer); protocol_admin_panel = address(new ProtocolAdminPanel()); - vm.stopPrank(); + + } + + function test__unit__initializeMustSucceed() public { + //===============PRE-CONDITIONS===================== //====================TEST============================ vm.startPrank(protocol_deployer); IProtocolAdminPanel(protocol_admin_panel).initialize( @@ -53,16 +55,29 @@ contract ProtocolAdminPanelTest is Test{ ); vm.stopPrank(); //================POST-CONDITIONS===================== - //============================FACTORY===================================================== - // assertEq(IProtocolFactory(protocol_admin_panel).adminPanel(), protocol_admin_panel); - // assertEq(IProtocolFactory(protocol_factory_facet).adminPanel(), address(0x00)); - // assertEq(keccak256(bytes("http://localhost:3000/metadata/")), keccak256(bytes(IProtocolFactory(protocol_admin_panel).baseURI()))); - //=========================ADMIN-REGISTRY================================================================ - // assertTrue(IProtocolAdminRegistry(protocol_admin_panel).isUpgradeAdmin(protocol_admin_panel)); - // assertEq(IProtocolAdminRegistry(protocol_admin_panel).upgradeAdmin(),protocol_admin_panel); - // assertNotEq(address(0x00), IProtocolAdminRegistry(protocol_admin_panel).adminManagerTemplate()); + //===================DIAMOND-LOUPE======================= + assertEq(3,DiamondLoupeFacet(protocol_admin_panel).facetAddresses().length); } + + function test__unit__initializeMustRevertDoubleInitialization() public{ + //========================PRE-CONDITIONS============================ + test__unit__initializeMustSucceed(); + // Create ERC165Facet before expectRevert so it doesn't consume the revert expectation + IProtocolAdminClient client = IProtocolAdminClient(address(new ERC165Facet())); + //=========================TEST===================================== + vm.startPrank(protocol_deployer); + vm.expectRevert(); + IProtocolAdminPanel(protocol_admin_panel).initialize( + client, + IProtocolAdminRegistry(protocol_admin_registry), + IProtocolFactory(protocol_factory_facet), + "http://localhost:3000/metadata/" + ); + vm.stopPrank(); + //========================POST-CONDITIONS========================= + } + function test__unit__deployProtocolAdminManagerMustSucceed() public{ //===============PRE-CONDITIONS===================== @@ -70,51 +85,69 @@ contract ProtocolAdminPanelTest is Test{ vm.startPrank(protocol_deployer); IProtocolFactory(protocol_admin_panel).__initialize("localhost"); IProtocolAdminRegistry(protocol_admin_panel)._initialize(); - vm.stopPrank(); //====================TEST============================ vm.startPrank(any_caller); - address _admin_manager = IProtocolAdminRegistry(protocol_admin_panel).protocol_manager(uint256(0x01)); + _admin_manager = IProtocolAdminRegistry(protocol_admin_panel).setProtocolManager(uint256(0x01), any_caller); vm.stopPrank(); //================POST-CONDITIONS===================== - assertEq(_admin_manager, IProtocolAdminRegistry(protocol_admin_panel).protocol_manager(uint256(0x01))); + assertEq(_admin_manager, IProtocolAdminRegistry(protocol_admin_panel).getProtocolManager(uint256(0x01))); + assertEq(protocol_admin_panel, IProtocolAdminPanelConsumer(_admin_manager).adminPanel()); + assertTrue(IProtocolAdminManager(_admin_manager).isCreator(any_caller)); + assertTrue(IProtocolAdminManager(_admin_manager).isPoolCreator(any_caller)); + } function test__unit__createProtocolMustSucceed() public { //=================PRE-CONDITIONS======================= test__unit__initializeMustSucceed(); vm.startPrank(protocol_deployer); + IProtocolFactory(protocol_admin_panel).__initialize("localhost"); IProtocolAdminRegistry(protocol_admin_panel)._initialize(); vm.stopPrank(); - + vm.startPrank(any_caller); - address _admin_manager = IProtocolAdminRegistry(protocol_admin_panel).protocol_manager(uint256(0x01)); + _admin_manager = IProtocolAdminRegistry(protocol_admin_panel).setProtocolManager(uint256(0x01), any_caller); vm.stopPrank(); + uint256[] memory beforeProtocols = IProtocolFactory(protocol_admin_panel).getProtocols(any_caller); + //=====================TEST============================= - vm.startPrank(protocol_admin_panel); + vm.startPrank(any_caller); IProtocolFactory(protocol_admin_panel).create_protocol("DeFiHub",_admin_manager,uint256(0x01)); vm.stopPrank(); //=================POST-CONDITIONS====================== - + //===================================ADMIN-MANAGER============================================ assertEq(uint256(0x01),IERC1155(protocol_admin_panel).balanceOf(_admin_manager, uint256(0x01))); - // assertEq(keccak256(bytes("DeFiHub")),keccak256(bytes(IERC1155(protocol_admin_panel).uri(uint256(0x01))))); - } + assertEq(uint256(0x01), IProtocolAdminManager(_admin_manager).protocolId()); + assertEq(keccak256(bytes("DeFiHub")),keccak256(bytes(IProtocolAdminManager(_admin_manager).protocolName()))); - function test__unit__setProtocolHookMediatorMustSucceed() public { - //==================PRE-CONDITIONS=========================== + //==================================FACTORY================================================== + uint256[] memory afterProtocols = IProtocolFactory(protocol_admin_panel).getProtocols(any_caller); + assertEq(afterProtocols.length, beforeProtocols.length + uint256(0x01)); + assertEq(uint256(0x01),afterProtocols[beforeProtocols.length]); + assertGt(uint256(keccak256(bytes(IERC1155(protocol_admin_panel).uri(uint256(0x01))))),uint256(0x00)); + + + } - //====================TEST=================================== - // vm.startPrank(protocol_deployer); - // IProtocolAdminPanel(protocol_admin_panel).setProtocolHookMediator(_hookMediator); - // vm.stopPrank(); - //==================POST-CONDITIONS========================= + function test__unit__createProtocolWithExistingNameMustRevert() public { + //=========================PRE-CONDITIONS================================= + test__unit__createProtocolMustSucceed(); + //============================TEST===================================== + vm.startPrank(any_caller); + vm.expectRevert(); + IProtocolFactory(protocol_admin_panel).create_protocol("DeFiHub",_admin_manager,uint256(0x01)); + vm.stopPrank(); + + //========================POST-CONDITIONS================================ } + } \ No newline at end of file diff --git a/contracts/test/protocol-pkg/ProtocolAdminRegistry.t.sol b/contracts/test/protocol-pkg/ProtocolAdminRegistry.t.sol index 299d4e8cf..5a4848816 100644 --- a/contracts/test/protocol-pkg/ProtocolAdminRegistry.t.sol +++ b/contracts/test/protocol-pkg/ProtocolAdminRegistry.t.sol @@ -3,7 +3,14 @@ pragma solidity >=0.8.30; import {Test, console2} from "forge-std/Test.sol"; -import {ProtocolAdminRegistry, IProtocolAdminRegistry, IGenericFactory} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; + +import { + ProtocolAdminRegistry, + IProtocolAdminRegistry, + IGenericFactory, + IProtocolAdminPanelConsumer +} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; + import {ProxyHelper} from "./helpers/ProxyHelper.sol"; contract ProtocolAdminRegistryTest is Test{ @@ -30,6 +37,7 @@ contract ProtocolAdminRegistryTest is Test{ vm.stopPrank(); //===============POST-CONDITIONS================== assertEq(IProtocolAdminRegistry(proxy_helper).upgradeAdmin(),admin); + assertEq(proxy_helper, IProtocolAdminPanelConsumer(proxy_helper).adminPanel()); assertNotEq(address(0x00), IProtocolAdminRegistry(proxy_helper).adminManagerTemplate()); } @@ -45,19 +53,31 @@ contract ProtocolAdminRegistryTest is Test{ //===================POST-CONDITIONS=========================== } - function test__unit__deployAdminManagerMustSucceed() public{ + function test__unit__deployAdminManagerMustRevertOnInvalidContext() public{ //=================PRE-CONDITIONS========================= test__unit__initializeMustSucceed(); - + address prevProtocolManager = IProtocolAdminRegistry(proxy_helper).getProtocolManager(uint256(0x01)); //====================TEST============================== vm.startPrank(any_caller); - address _admin_manager = IProtocolAdminRegistry(proxy_helper).protocol_manager(uint256(0x01)); + vm.expectRevert(); + address _admin_manager = IProtocolAdminRegistry(proxy_helper).setProtocolManager(uint256(0x01), any_caller); vm.stopPrank(); - + //====================POST-CONDITIONS==================== - assertEq(_admin_manager, IProtocolAdminRegistry(proxy_helper).protocol_manager(uint256(0x01))); + address postProtocolManager = IProtocolAdminRegistry(proxy_helper).getProtocolManager(uint256(0x01)); + assertEq(prevProtocolManager, postProtocolManager); + + } + function test__unit__addPoolMustRevertOnInvalidContext() public { + //===================PRE-CONDITIONS============================= + test__unit__initializeMustSucceed(); + //======================TEST==================================== + vm.prank(any_caller); + vm.expectRevert(); + IProtocolAdminRegistry(proxy_helper).setProtocolManager(uint256(0x01),any_caller); + //===================POST-CONDITIONS========================== } diff --git a/contracts/test/protocol-pkg/ProtocolFactoryFacet.t.sol b/contracts/test/protocol-pkg/ProtocolFactoryFacet.t.sol index 5a18e7edd..05116f86a 100644 --- a/contracts/test/protocol-pkg/ProtocolFactoryFacet.t.sol +++ b/contracts/test/protocol-pkg/ProtocolFactoryFacet.t.sol @@ -2,24 +2,29 @@ pragma solidity 0.8.30; import {Test, console2} from "forge-std/Test.sol"; -import {ProtocolFactoryFacet, IProtocolFactory} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; +import {ProtocolFactoryFacet, IProtocolFactory, IProtocolAdminPanelConsumer} from "@hook-bazaar/protocol-pkg/src/ProtocolFactoryFacet.sol"; +import {ProtocolAdminRegistry,IProtocolAdminRegistry} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminRegistry.sol"; import {ProxyHelper} from "./helpers/ProxyHelper.sol"; import {ProtocolAdminManager, IComponent} from "@hook-bazaar/protocol-pkg/src/ProtocolAdminManager.sol"; import {IERC1155} from "Compose/interfaces/IERC1155.sol"; +import {GenericFactory} from "@euler/GenericFactory/GenericFactory.sol"; contract ProtocolFactoryFacetTest is Test{ address admin = makeAddr("admin"); address proxy_helper; address any_caller = makeAddr("anyCaller"); - + address protocol_factory_facet; address protocol_admin_manager_impl; + address protocolAdminRegistry; + address adminManagerDeployer; function setUp() public{ - + protocolAdminRegistry = address(new ProtocolAdminRegistry()); protocol_factory_facet = address(new ProtocolFactoryFacet()); proxy_helper = address(new ProxyHelper(protocol_factory_facet)); protocol_admin_manager_impl = address(new ProtocolAdminManager()); + } function test__unit__initializeMustSucceed() public{ @@ -31,32 +36,44 @@ contract ProtocolFactoryFacetTest is Test{ vm.stopPrank(); //============POST-CONDITIONS============= - assertEq(IProtocolFactory(proxy_helper).adminPanel(), proxy_helper); + assertEq(proxy_helper,IProtocolAdminPanelConsumer(proxy_helper).adminPanel()); assertEq(keccak256(bytes("http://localhost:3000/metadata/")), keccak256(bytes(IProtocolFactory(proxy_helper).baseURI()))); } - function test__unit__createProtocolMustSucceed() public { - //============PRE-CONDITIONS============= + function test__unit__initializeMustRevertDoubleInitialization() public { + //=====================PRE-CONDTIONS====================== test__unit__initializeMustSucceed(); - // - vm.startPrank(proxy_helper); - IComponent(protocol_admin_manager_impl).initialize(any_caller); + //=======================TEST================================= + vm.startPrank(admin); + vm.expectRevert(); + IProtocolFactory(proxy_helper).__initialize("http://localhost:3000/metadata/"); vm.stopPrank(); - uint256 beforeProtocolsBalance = IERC1155(proxy_helper).balanceOf(protocol_admin_manager_impl, uint256(0x01)); + //======================POST-CONDITIONS====================== + + } + + function test__unit__createProtocolMustRevertOnInvalidContext() public { + //============PRE-CONDITIONS============= + test__unit__initializeMustSucceed(); + + vm.startPrank(admin); + adminManagerDeployer = address(new GenericFactory(admin)); + GenericFactory(adminManagerDeployer).setImplementation(protocol_admin_manager_impl); + address adminManager = GenericFactory(adminManagerDeployer).createProxy(protocol_admin_manager_impl,false,abi.encode(msg.sender)); + + vm.stopPrank(); + //===============TEST==================== vm.startPrank(any_caller); - IProtocolFactory(proxy_helper).create_protocol("DeFi Hub",protocol_admin_manager_impl,uint256(0x01)); + vm.expectRevert(); + IProtocolFactory(proxy_helper).create_protocol("MyProtocol1", adminManager, uint256(0x01)); vm.stopPrank(); - + //=========POST-CONDITIONS=============== - uint256 afterProtocolBalance = IERC1155(proxy_helper).balanceOf(protocol_admin_manager_impl, uint256(0x01)); - assertEq(afterProtocolBalance, uint256(0x01) +beforeProtocolsBalance); - // assertEq(uint256(0x01),IERC1155(proxy_helper).balanceOf(protocol_admin_manager_impl, uint256(0x01))); - // // assertEq(keccak256(bytes("DeFi Hub")),keccak256(bytes(IERC1155(proxy_helper).uri(uint256(0x01))))); } diff --git a/contracts/test/protocol-pkg/helpers/ProxyHelper.sol b/contracts/test/protocol-pkg/helpers/ProxyHelper.sol index 6a8021da3..8d21271fe 100644 --- a/contracts/test/protocol-pkg/helpers/ProxyHelper.sol +++ b/contracts/test/protocol-pkg/helpers/ProxyHelper.sol @@ -49,9 +49,10 @@ abstract contract Proxy { * * This function does not return to its internall call site, it will return directly to the external caller. */ - function _fallback() internal virtual { + function _fallback() public virtual { _beforeFallback(); _delegate(_implementation()); + } /** @@ -87,6 +88,7 @@ contract ProxyHelper is Proxy{ impl = _impl; } + function implementation() public view returns (address){ return _implementation(); } @@ -95,4 +97,6 @@ contract ProxyHelper is Proxy{ return impl; } + + } \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 4543eb0ae..689f80ab6 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,6 +6,9 @@ out = "contracts/out/" libs = ["contracts/lib", "node_modules"] script = "contracts/script" ffi=true +via_ir = true +optimizer = true +optimizer_runs = 200 fs_permissions = [ { access = "read", path = "./contracts/broadcast" }, @@ -34,12 +37,13 @@ remappings = [ "@euler/=contracts/lib/compose-extensions/lib/euler-vault-kit/src/" ] -compiler_restrictions = [ - {path = "contracts/src/**", solc_version = ">=0.8.30", evm_version = "prague"}, - {path = "contracts/lib/v4-periphery/**", solc_version = "=0.8.26", evm_version = "cancun"}, - {path = "contracts/lib/compose-extensions/**", solc_version = "=0.8.30"} - -] +# Note: compiler_restrictions is not a standard Foundry config - using via_ir = true globally instead +# compiler_restrictions = [ +# {path = "contracts/src/**", solc_version = ">=0.8.30", evm_version = "prague"}, +# {path = "contracts/src/protocol-pkg/ProtocolAdminClient.sol", solc_version = ">=0.8.30", evm_version = "prague", viaIR = true }, +# {path = "contracts/lib/v4-periphery/**", solc_version = "=0.8.26", evm_version = "cancun"}, +# {path = "contracts/lib/compose-extensions/**", solc_version = "=0.8.30"} +# ] [rpc_endpoints]