// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "../registry/UniversalAssetRegistry.sol"; /** * @title PoolManager * @notice Manages pool creation, configuration, and lifecycle * @dev Auto-creates pools when new assets are registered */ contract PoolManager is Initializable, AccessControlUpgradeable, UUPSUpgradeable { bytes32 public constant POOL_ADMIN_ROLE = keccak256("POOL_ADMIN_ROLE"); bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); struct PoolInfo { address pool; address provider; // DODO, Uniswap, etc. address tokenA; address tokenB; uint256 liquidityUSD; uint256 volume24h; uint256 createdAt; uint256 lastUpdateTime; bool isActive; } // Storage UniversalAssetRegistry public assetRegistry; mapping(address => PoolInfo[]) public tokenPools; // token => pools mapping(address => PoolInfo) public poolRegistry; // pool address => info address[] public allPools; // Provider addresses address public dodoProvider; address public uniswapV3Provider; address public curveProvider; event PoolCreated( address indexed pool, address indexed token, address provider, UniversalAssetRegistry.AssetType assetType ); event PoolHealthChecked( address indexed pool, bool isHealthy, string reason ); event PoolLiquidityUpdated( address indexed pool, uint256 newLiquidityUSD ); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize( address _assetRegistry, address admin ) external initializer { __AccessControl_init(); __UUPSUpgradeable_init(); require(_assetRegistry != address(0), "Zero registry"); assetRegistry = UniversalAssetRegistry(_assetRegistry); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(POOL_ADMIN_ROLE, admin); _grantRole(UPGRADER_ROLE, admin); } function _authorizeUpgrade(address newImplementation) internal override onlyRole(UPGRADER_ROLE) {} /** * @notice Auto-create pool when new asset registered */ function onAssetRegistered( address token, UniversalAssetRegistry.AssetType assetType ) external onlyRole(POOL_ADMIN_ROLE) returns (address pool) { // Determine optimal pool type based on asset type if (assetType == UniversalAssetRegistry.AssetType.Stablecoin || assetType == UniversalAssetRegistry.AssetType.ISO4217W || assetType == UniversalAssetRegistry.AssetType.GRU) { // Create DODO PMM pool (optimal for stable / GRU c* pairs) pool = _createDODOPool(token); } else if (assetType == UniversalAssetRegistry.AssetType.ERC20Standard || assetType == UniversalAssetRegistry.AssetType.GovernanceToken) { // Create Uniswap V3 pool (optimal for volatile pairs) pool = _createUniswapV3Pool(token); } else { // For other types (Security, Commodity), manual pool creation return address(0); } emit PoolCreated(pool, token, dodoProvider, assetType); return pool; } /** * @notice Create DODO PMM pool */ function _createDODOPool(address token) internal returns (address) { // In production, this would call DODOPMMIntegration to create actual pool // For now, placeholder return address(0); } /** * @notice Create Uniswap V3 pool */ function _createUniswapV3Pool(address token) internal returns (address) { // In production, this would deploy Uniswap V3 pool // For now, placeholder return address(0); } /** * @notice Register existing pool */ function registerPool( address pool, address provider, address tokenA, address tokenB, uint256 liquidityUSD ) external onlyRole(POOL_ADMIN_ROLE) { require(pool != address(0), "Zero address"); require(!poolRegistry[pool].isActive, "Already registered"); PoolInfo memory info = PoolInfo({ pool: pool, provider: provider, tokenA: tokenA, tokenB: tokenB, liquidityUSD: liquidityUSD, volume24h: 0, createdAt: block.timestamp, lastUpdateTime: block.timestamp, isActive: true }); poolRegistry[pool] = info; tokenPools[tokenA].push(info); if (tokenB != tokenA) { tokenPools[tokenB].push(info); } allPools.push(pool); } /** * @notice Check pool health */ function checkPoolHealth(address pool) external view returns ( bool isHealthy, string memory reason ) { PoolInfo memory info = poolRegistry[pool]; if (!info.isActive) { return (false, "Pool inactive"); } if (info.liquidityUSD < 1000e18) { return (false, "Insufficient liquidity"); } if (block.timestamp - info.lastUpdateTime > 7 days) { return (false, "Stale data"); } return (true, "Healthy"); } /** * @notice Update pool liquidity */ function updatePoolLiquidity( address pool, uint256 liquidityUSD ) external onlyRole(POOL_ADMIN_ROLE) { require(poolRegistry[pool].isActive, "Pool not registered"); poolRegistry[pool].liquidityUSD = liquidityUSD; poolRegistry[pool].lastUpdateTime = block.timestamp; emit PoolLiquidityUpdated(pool, liquidityUSD); } /** * @notice Set provider addresses */ function setProviders( address _dodoProvider, address _uniswapV3Provider, address _curveProvider ) external onlyRole(DEFAULT_ADMIN_ROLE) { dodoProvider = _dodoProvider; uniswapV3Provider = _uniswapV3Provider; curveProvider = _curveProvider; } // View functions function getPoolsForToken(address token) external view returns (PoolInfo[] memory) { return tokenPools[token]; } function getPoolInfo(address pool) external view returns (PoolInfo memory) { return poolRegistry[pool]; } function getAllPools() external view returns (address[] memory) { return allPools; } function getPoolCount() external view returns (uint256) { return allPools.length; } }