diff --git a/.github/workflows/forge-pr.yaml b/.github/workflows/forge-pr.yaml index c7d3f53c..c289f0ab 100644 --- a/.github/workflows/forge-pr.yaml +++ b/.github/workflows/forge-pr.yaml @@ -39,14 +39,15 @@ jobs: git submodule update --init --recursive - name: Generate coverage report run: | + forge build forge coverage --report lcov sudo apt-get install lcov lcov --remove lcov.info -o lcov.info 'tests/*' - name: Report code coverage - uses: zgosalvez/github-actions-report-lcov@v1 + uses: zgosalvez/github-actions-report-lcov@v4.1.22 with: coverage-files: lcov.info - minimum-coverage: 90 + minimum-coverage: 85 artifact-name: code-coverage-report github-token: ${{ secrets.GITHUB_TOKEN }} working-directory: ./ diff --git a/.github/workflows/forge.yaml b/.github/workflows/forge.yaml index 1f38411d..19903589 100644 --- a/.github/workflows/forge.yaml +++ b/.github/workflows/forge.yaml @@ -41,14 +41,15 @@ jobs: git submodule update --init --recursive - name: Generate coverage report run: | + forge build forge coverage --report lcov sudo apt-get install lcov lcov --remove lcov.info -o lcov.info 'tests/*' - name: Report code coverage - uses: zgosalvez/github-actions-report-lcov@v1 + uses: zgosalvez/github-actions-report-lcov@v4.1.22 with: coverage-files: lcov.info - minimum-coverage: 90 + minimum-coverage: 85 artifact-name: code-coverage-report github-token: ${{ secrets.GITHUB_TOKEN }} working-directory: ./ diff --git a/contracts/MaplePool.sol b/contracts/MaplePool.sol index dfbe84e7..2fc2e54d 100644 --- a/contracts/MaplePool.sol +++ b/contracts/MaplePool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { ERC20 } from "../modules/erc20/contracts/ERC20.sol"; import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol"; diff --git a/contracts/MaplePoolDelegateCover.sol b/contracts/MaplePoolDelegateCover.sol index 01c9b201..db834dbf 100644 --- a/contracts/MaplePoolDelegateCover.sol +++ b/contracts/MaplePoolDelegateCover.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol"; diff --git a/contracts/MaplePoolDeployer.sol b/contracts/MaplePoolDeployer.sol index 47e0bc89..273d35ac 100644 --- a/contracts/MaplePoolDeployer.sol +++ b/contracts/MaplePoolDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol"; import { IMapleProxyFactory } from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxyFactory.sol"; @@ -37,7 +37,8 @@ contract MaplePoolDeployer is IMaplePoolDeployer { function deployPool( address poolManagerFactory_, address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_, address asset_, address poolPermissionManager_, string memory name_, @@ -47,6 +48,8 @@ contract MaplePoolDeployer is IMaplePoolDeployer { external override returns (address poolManager_) { + require(strategyDeploymentData_.length == strategyFactories_.length, "PD:DP:MISMATCHING_ARRAYS"); + IGlobalsLike globals_ = IGlobalsLike(globals); require(globals_.isPoolDelegate(msg.sender), "PD:DP:INVALID_PD"); @@ -69,13 +72,13 @@ contract MaplePoolDeployer is IMaplePoolDeployer { keccak256(abi.encode(poolManager_)) ); - address[] memory loanManagers_ = new address[](loanManagerFactories_.length); + address[] memory strategies_ = new address[](strategyFactories_.length); - for (uint256 i_; i_ < loanManagerFactories_.length; ++i_) { - loanManagers_[i_] = IPoolManagerLike(poolManager_).addLoanManager(loanManagerFactories_[i_]); + for (uint256 i_; i_ < strategyFactories_.length; ++i_) { + strategies_[i_] = IPoolManagerLike(poolManager_).addStrategy(strategyFactories_[i_], strategyDeploymentData_[i_]); } - emit PoolDeployed(pool_, poolManager_, withdrawalManager_, loanManagers_); + emit PoolDeployed(pool_, poolManager_, withdrawalManager_, strategies_); uint256 coverAmount_ = configParams_[2]; @@ -95,7 +98,8 @@ contract MaplePoolDeployer is IMaplePoolDeployer { function deployPool( address poolManagerFactory_, address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_, address asset_, address poolPermissionManager_, string memory name_, @@ -105,6 +109,8 @@ contract MaplePoolDeployer is IMaplePoolDeployer { external override returns (address poolManager_) { + require(strategyDeploymentData_.length == strategyFactories_.length, "PD:DP:MISMATCHING_ARRAYS"); + IGlobalsLike globals_ = IGlobalsLike(globals); require(globals_.isPoolDelegate(msg.sender), "PD:DP:INVALID_PD"); @@ -127,13 +133,13 @@ contract MaplePoolDeployer is IMaplePoolDeployer { keccak256(abi.encode(poolManager_)) ); - address[] memory loanManagers_ = new address[](loanManagerFactories_.length); + address[] memory strategies_ = new address[](strategyFactories_.length); - for (uint256 i_; i_ < loanManagerFactories_.length; ++i_) { - loanManagers_[i_] = IPoolManagerLike(poolManager_).addLoanManager(loanManagerFactories_[i_]); + for (uint256 i_; i_ < strategyFactories_.length; ++i_) { + strategies_[i_] = IPoolManagerLike(poolManager_).addStrategy(strategyFactories_[i_], strategyDeploymentData_[i_]); } - emit PoolDeployed(pool_, poolManager_, withdrawalManager_, loanManagers_); + emit PoolDeployed(pool_, poolManager_, withdrawalManager_, strategies_); uint256 coverAmount_ = configParams_[2]; @@ -150,85 +156,118 @@ contract MaplePoolDeployer is IMaplePoolDeployer { IPoolManagerLike(poolManager_).completeConfiguration(); } - function getDeploymentAddresses( - address poolDelegate_, - address poolManagerFactory_, - address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, - address asset_, - string memory name_, - string memory symbol_, - uint256[7] memory configParams_ + function getPoolDeploymentAddresses( + address poolManagerFactory_, + address poolDelegate_, + address asset_, + uint256 initialSupply_, + string memory name_, + string memory symbol_ ) - public view override - returns ( - address poolManager_, - address pool_, - address poolDelegateCover_, - address withdrawalManager_, - address[] memory loanManagers_ - ) + external view override returns (address poolManager_, address pool_, address poolDelegateCover_) { - poolManager_ = IMapleProxyFactory(poolManagerFactory_).getInstanceAddress( - abi.encode(poolDelegate_, asset_, configParams_[5], name_, symbol_), - keccak256(abi.encode(poolDelegate_)) + ( pool_, poolManager_, poolDelegateCover_ ) = _getPoolAddresses( + poolManagerFactory_, poolDelegate_, asset_, initialSupply_, name_, symbol_ ); + } - pool_ = _addressFrom(poolManager_, 1); - poolDelegateCover_ = _addressFrom(poolManager_, 2); - - withdrawalManager_ = IMapleProxyFactory(withdrawalManagerFactory_).getInstanceAddress( - abi.encode(pool_, configParams_[6], configParams_[3], configParams_[4]), - keccak256(abi.encode(poolManager_)) + function getCyclicalWithdrawalManagerAddress( + address withdrawalManagerFactory_, + address pool_, + address poolManager_, + uint256 startTime_, + uint256 cycleDuration_, + uint256 windowDuration_ + ) + external view override returns (address withdrawalManager_) + { + return _getCyclicalWithdrawalManagerAddress( + withdrawalManagerFactory_, pool_, poolManager_, startTime_, cycleDuration_, windowDuration_ ); + } - loanManagers_ = new address[](loanManagerFactories_.length); + function getQueueWithdrawalManagerAddress( + address withdrawalManagerFactory_, + address pool_, + address poolManager_ + ) + external view override returns (address withdrawalManager_) + { + return _getQueueWithdrawalManagerAddress(withdrawalManagerFactory_, pool_, poolManager_); + } - for (uint256 i_; i_ < loanManagerFactories_.length; ++i_) { - loanManagers_[i_] = IMapleProxyFactory(loanManagerFactories_[i_]).getInstanceAddress( - abi.encode(poolManager_), - keccak256(abi.encode(poolManager_, i_)) - ); - } + function getStrategiesAddresses( + address poolManager_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_ + ) + public view returns (address[] memory strategies_) + { + return _getStrategiesAddresses(poolManager_, strategyFactories_, strategyDeploymentData_); } - function getDeploymentAddresses( - address poolDelegate_, - address poolManagerFactory_, - address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, - address asset_, - string memory name_, - string memory symbol_, - uint256[4] memory configParams_ + function _getCyclicalWithdrawalManagerAddress( + address withdrawalManagerFactory_, + address pool_, + address poolManager_, + uint256 startTime_, + uint256 cycleDuration_, + uint256 windowDuration_ ) - public view override - returns ( - address poolManager_, - address pool_, - address poolDelegateCover_, - address withdrawalManager_, - address[] memory loanManagers_ - ) + internal view + returns (address cyclicalWithdrawalManager_) { - poolManager_ = IMapleProxyFactory(poolManagerFactory_).getInstanceAddress( - abi.encode(poolDelegate_, asset_, configParams_[3], name_, symbol_), - keccak256(abi.encode(poolDelegate_)) + cyclicalWithdrawalManager_ = IMapleProxyFactory(withdrawalManagerFactory_).getInstanceAddress( + abi.encode(pool_, startTime_, cycleDuration_, windowDuration_), + keccak256(abi.encode(poolManager_)) ); + } - pool_ = _addressFrom(poolManager_, 1); - poolDelegateCover_ = _addressFrom(poolManager_, 2); - - withdrawalManager_ = IMapleProxyFactory(withdrawalManagerFactory_).getInstanceAddress( + function _getQueueWithdrawalManagerAddress( + address withdrawalManagerFactory_, + address pool_, + address poolManager_ + ) + internal view + returns (address queueWithdrawalManager_) + { + queueWithdrawalManager_ = IMapleProxyFactory(withdrawalManagerFactory_).getInstanceAddress( abi.encode(pool_), keccak256(abi.encode(poolManager_)) ); + } + + function _getPoolAddresses( + address poolManagerFactory_, + address poolDelegate_, + address asset_, + uint256 initialSupply_, + string memory name_, + string memory symbol_ + ) + internal view returns (address pool_, address poolManager_, address poolDelegateCover_) + { + bytes memory constructorArgs = abi.encode(poolDelegate_, asset_, initialSupply_, name_, symbol_); + bytes32 salt = keccak256(abi.encode(poolDelegate_)); - loanManagers_ = new address[](loanManagerFactories_.length); + poolManager_ = IMapleProxyFactory(poolManagerFactory_).getInstanceAddress(constructorArgs, salt); + pool_ = _addressFrom(poolManager_, 1); + poolDelegateCover_ = _addressFrom(poolManager_, 2); + } + + function _getStrategiesAddresses( + address poolManager_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_ + ) + internal view + returns (address[] memory strategiesAddresses_) + { + strategiesAddresses_ = new address[](strategyFactories_.length); - for (uint256 i_; i_ < loanManagerFactories_.length; ++i_) { - loanManagers_[i_] = IMapleProxyFactory(loanManagerFactories_[i_]).getInstanceAddress( - abi.encode(poolManager_), + for (uint256 i_; i_ < strategyFactories_.length; ++i_) { + strategiesAddresses_[i_] = IMapleProxyFactory(strategyFactories_[i_]).getInstanceAddress( + bytes.concat(abi.encode(poolManager_), strategyDeploymentData_[i_]), keccak256(abi.encode(poolManager_, i_)) ); } diff --git a/contracts/MaplePoolManager.sol b/contracts/MaplePoolManager.sol index 827b8815..abbc386f 100644 --- a/contracts/MaplePoolManager.sol +++ b/contracts/MaplePoolManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol"; import { IMapleProxyFactory } from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxyFactory.sol"; @@ -16,6 +16,7 @@ import { IPoolDelegateCoverLike, IPoolLike, IPoolPermissionManagerLike, + IStrategyLike, IWithdrawalManagerLike } from "./interfaces/Interfaces.sol"; @@ -63,8 +64,8 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool _; } - modifier onlyPoolDelegateOrNotConfigured() { - _revertIfConfiguredAndNotPoolDelegate(); + modifier onlyProtocolAdminsOrNotConfigured() { + _revertIfConfiguredAndNotProtocolAdmins(); _; } @@ -166,45 +167,45 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool /*** Pool Delegate Admin Functions ***/ /**************************************************************************************************************************************/ - function addLoanManager(address loanManagerFactory_) - external override whenNotPaused onlyPoolDelegateOrNotConfigured returns (address loanManager_) + function addStrategy(address strategyFactory_, bytes calldata extraDeploymentData_) + external override whenNotPaused onlyProtocolAdminsOrNotConfigured returns (address strategy_) { - require(IGlobalsLike(globals()).isInstanceOf("LOAN_MANAGER_FACTORY", loanManagerFactory_), "PM:ALM:INVALID_FACTORY"); + require(IGlobalsLike(globals()).isInstanceOf("STRATEGY_FACTORY", strategyFactory_), "PM:AS:INVALID_FACTORY"); - // NOTE: If removing loan managers is allowed in the future, there will be a need to rethink salts here due to collisions. - loanManager_ = IMapleProxyFactory(loanManagerFactory_).createInstance( - abi.encode(address(this)), - keccak256(abi.encode(address(this), loanManagerList.length)) + // NOTE: If removing strategies is allowed in the future, there will be a need to rethink salts here due to collisions. + strategy_ = IMapleProxyFactory(strategyFactory_).createInstance( + bytes.concat(abi.encode(address(this)), extraDeploymentData_), + keccak256(abi.encode(address(this), strategyList.length)) ); - isLoanManager[loanManager_] = true; + isStrategy[strategy_] = true; - loanManagerList.push(loanManager_); + strategyList.push(strategy_); - emit LoanManagerAdded(loanManager_); + emit StrategyAdded(strategy_); } function setDelegateManagementFeeRate(uint256 delegateManagementFeeRate_) - external override whenNotPaused onlyPoolDelegateOrNotConfigured + external override whenNotPaused onlyProtocolAdminsOrNotConfigured { require(delegateManagementFeeRate_ <= HUNDRED_PERCENT, "PM:SDMFR:OOB"); emit DelegateManagementFeeRateSet(delegateManagementFeeRate = delegateManagementFeeRate_); } - function setIsLoanManager(address loanManager_, bool isLoanManager_) external override whenNotPaused onlyPoolDelegate { - emit IsLoanManagerSet(loanManager_, isLoanManager[loanManager_] = isLoanManager_); + function setIsStrategy(address strategy_, bool isStrategy_) external override whenNotPaused onlyPoolDelegateOrProtocolAdmins { + emit IsStrategySet(strategy_, isStrategy[strategy_] = isStrategy_); - // Check LoanManager is in the list. - // NOTE: The factory and instance check are not required as the mapping is being updated for a LoanManager that is in the list. - for (uint256 i_; i_ < loanManagerList.length; ++i_) { - if (loanManagerList[i_] == loanManager_) return; + // Check Strategy is in the list. + // NOTE: The factory and instance check are not required as the mapping is being updated for a Strategy that is in the list. + for (uint256 i_; i_ < strategyList.length; ++i_) { + if (strategyList[i_] == strategy_) return; } - revert("PM:SILM:INVALID_LM"); + revert("PM:SIS:INVALID_STRATEGY"); } - function setLiquidityCap(uint256 liquidityCap_) external override whenNotPaused onlyPoolDelegateOrNotConfigured { + function setLiquidityCap(uint256 liquidityCap_) external override whenNotPaused onlyProtocolAdminsOrNotConfigured { emit LiquidityCapSet(liquidityCap = liquidityCap_); } @@ -217,7 +218,7 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool emit WithdrawalManagerSet(withdrawalManager = withdrawalManager_); } - function setPoolPermissionManager(address poolPermissionManager_) external override whenNotPaused onlyPoolDelegateOrNotConfigured { + function setPoolPermissionManager(address poolPermissionManager_) external override whenNotPaused onlyProtocolAdminsOrNotConfigured { require(IGlobalsLike(globals()).isInstanceOf("POOL_PERMISSION_MANAGER", poolPermissionManager_), "PM:SPPM:INVALID_INSTANCE"); emit PoolPermissionManagerSet(poolPermissionManager = poolPermissionManager_); @@ -234,13 +235,13 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool IGlobalsLike globals_ = IGlobalsLike(globals()); - // NOTE: Do not need to check isInstance() as the LoanManager is added to the list on `addLoanManager()` or `configure()`. - require(principal_ != 0, "PM:RF:INVALID_PRINCIPAL"); - require(globals_.isInstanceOf("LOAN_MANAGER_FACTORY", factory_), "PM:RF:INVALID_FACTORY"); - require(IMapleProxyFactory(factory_).isInstance(msg.sender), "PM:RF:INVALID_INSTANCE"); - require(isLoanManager[msg.sender], "PM:RF:NOT_LM"); - require(IERC20Like(pool_).totalSupply() != 0, "PM:RF:ZERO_SUPPLY"); - require(_hasSufficientCover(address(globals_), asset_), "PM:RF:INSUFFICIENT_COVER"); + // NOTE: Do not need to check isInstance() as the Strategy is added to the list on `addStrategy()` or `configure()`. + require(principal_ != 0, "PM:RF:INVALID_PRINCIPAL"); + require(globals_.isInstanceOf("STRATEGY_FACTORY", factory_), "PM:RF:INVALID_FACTORY"); + require(IMapleProxyFactory(factory_).isInstance(msg.sender), "PM:RF:INVALID_INSTANCE"); + require(isStrategy[msg.sender], "PM:RF:NOT_STRATEGY"); + require(IERC20Like(pool_).totalSupply() != 0, "PM:RF:ZERO_SUPPLY"); + require(_hasSufficientCover(address(globals_), asset_), "PM:RF:INSUFFICIENT_COVER"); // Fetching locked liquidity needs to be done prior to transferring the tokens. uint256 lockedLiquidity_ = IWithdrawalManagerLike(withdrawalManager).lockedLiquidity(); @@ -437,17 +438,17 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool implementation_ = _implementation(); } - function loanManagerListLength() external view override returns (uint256 loanManagerListLength_) { - loanManagerListLength_ = loanManagerList.length; + function strategyListLength() external view override returns (uint256 strategyListLength_) { + strategyListLength_ = strategyList.length; } function totalAssets() public view override returns (uint256 totalAssets_) { totalAssets_ = IERC20Like(asset).balanceOf(pool); - uint256 length_ = loanManagerList.length; + uint256 length_ = strategyList.length; for (uint256 i_; i_ < length_;) { - totalAssets_ += ILoanManagerLike(loanManagerList[i_]).assetsUnderManagement(); + totalAssets_ += IStrategyLike(strategyList[i_]).assetsUnderManagement(); unchecked { ++i_; } } } @@ -495,10 +496,10 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool } function unrealizedLosses() public view override returns (uint256 unrealizedLosses_) { - uint256 length_ = loanManagerList.length; + uint256 length_ = strategyList.length; for (uint256 i_; i_ < length_;) { - unrealizedLosses_ += ILoanManagerLike(loanManagerList[i_]).unrealizedLosses(); + unrealizedLosses_ += IStrategyLike(strategyList[i_]).unrealizedLosses(); unchecked { ++i_; } } @@ -513,7 +514,7 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool function _getLoanManager(address loan_) internal view returns (address loanManager_) { loanManager_ = ILoanLike(loan_).lender(); - require(isLoanManager[loanManager_], "PM:GLM:INVALID_LOAN_MANAGER"); + require(isStrategy[loanManager_], "PM:GLM:INVALID_LOAN_MANAGER"); } function _handleCover(uint256 losses_, uint256 platformFees_) internal { @@ -578,8 +579,14 @@ contract MaplePoolManager is IMaplePoolManager, MapleProxiedInternals, MaplePool require(!configured, "PM:ALREADY_CONFIGURED"); } - function _revertIfConfiguredAndNotPoolDelegate() internal view { - require(!configured || msg.sender == poolDelegate, "PM:NO_AUTH"); + function _revertIfConfiguredAndNotProtocolAdmins() internal view { + require( + !configured || + msg.sender == poolDelegate || + msg.sender == governor() || + msg.sender == IGlobalsLike(globals()).operationalAdmin(), + "PM:NOT_PA_OR_NOT_CONFIGURED" + ); } function _revertIfNotPool() internal view { diff --git a/contracts/interfaces/IERC4626.sol b/contracts/interfaces/IERC4626.sol index 0c11f287..15ee463f 100644 --- a/contracts/interfaces/IERC4626.sol +++ b/contracts/interfaces/IERC4626.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { IERC20 } from "../../modules/erc20/contracts/interfaces/IERC20.sol"; diff --git a/contracts/interfaces/IMaplePool.sol b/contracts/interfaces/IMaplePool.sol index 0946336a..0ff3fd28 100644 --- a/contracts/interfaces/IMaplePool.sol +++ b/contracts/interfaces/IMaplePool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { IERC20 } from "../../modules/erc20/contracts/interfaces/IERC20.sol"; diff --git a/contracts/interfaces/IMaplePoolDelegateCover.sol b/contracts/interfaces/IMaplePoolDelegateCover.sol index c0ec91e0..0766d883 100644 --- a/contracts/interfaces/IMaplePoolDelegateCover.sol +++ b/contracts/interfaces/IMaplePoolDelegateCover.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; interface IMaplePoolDelegateCover { diff --git a/contracts/interfaces/IMaplePoolDeployer.sol b/contracts/interfaces/IMaplePoolDeployer.sol index a99e3be7..0b151446 100644 --- a/contracts/interfaces/IMaplePoolDeployer.sol +++ b/contracts/interfaces/IMaplePoolDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; interface IMaplePoolDeployer { @@ -8,15 +8,17 @@ interface IMaplePoolDeployer { * @param pool_ The address of the Pool deployed. * @param poolManager_ The address of the PoolManager deployed. * @param withdrawalManager_ The address of the WithdrawalManager deployed. - * @param loanManagers_ An array of the addresses of the LoanManagers deployed. + * @param strategies_ An array of the addresses of the Strategies deployed. */ - event PoolDeployed(address indexed pool_, address indexed poolManager_, address indexed withdrawalManager_, address[] loanManagers_); + event PoolDeployed(address indexed pool_, address indexed poolManager_, address indexed withdrawalManager_, address[] strategies_); /** * @dev Deploys a pool along with its dependencies. + * NOTE: The PoolManager address is encoded and prepended to the strategyDeploymentData. * @param poolManagerFactory_ The address of the PoolManager factory to use. * @param withdrawalManagerFactory_ The address of the WithdrawalManager factory to use. - * @param loanManagerFactories_ An array of LoanManager factories to use. + * @param strategyFactories_ An array of Strategy factories to use. + * @param strategyDeploymentData_ An array of bytes to use to construct the strategies. * @param asset_ The address of the asset to use. * @param poolPermissionManager_ The address of the PoolPermissionManager to use. * @param name_ The name of the Pool. @@ -34,7 +36,8 @@ interface IMaplePoolDeployer { function deployPool( address poolManagerFactory_, address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_, address asset_, address poolPermissionManager_, string memory name_, @@ -46,9 +49,11 @@ interface IMaplePoolDeployer { /** * @dev Deploys a pool along with its dependencies. + * NOTE: The PoolManager address is encoded and prepended to the strategyDeploymentData. * @param poolManagerFactory_ The address of the PoolManager factory to use. * @param withdrawalManagerFactory_ The address of the WithdrawalManager factory to use. - * @param loanManagerFactories_ An array of LoanManager factories to use. + * @param strategyFactories_ An array of Strategy factories to use. + * @param strategyDeploymentData_ An array of bytes to use to construct the strategies. * @param asset_ The address of the asset to use. * @param poolPermissionManager_ The address of the PoolPermissionManager to use. * @param name_ The name of the Pool. @@ -63,7 +68,8 @@ interface IMaplePoolDeployer { function deployPool( address poolManagerFactory_, address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_, address asset_, address poolPermissionManager_, string memory name_, @@ -74,86 +80,75 @@ interface IMaplePoolDeployer { returns (address poolManager_); /** - * @dev Gets the addresses that would result from a deployment. - * @param poolDelegate_ The address of the PoolDelegate that will deploy the Pool. - * @param poolManagerFactory_ The address of the PoolManager factory to use. - * @param withdrawalManagerFactory_ The address of the WithdrawalManager factory to use. - * @param loanManagerFactories_ An array of LoanManager factories to use. - * @param asset_ The address of the asset to use. - * @param name_ The name of the Pool. - * @param symbol_ The symbol of the Pool. - * @param configParams_ Array of uint256 config parameters. Array used to avoid stack too deep issues. - * [0]: liquidityCap - * [1]: delegateManagementFeeRate - * [2]: coverAmountRequired - * [3]: cycleDuration - * [4]: windowDuration - * [5]: initialSupply - * [6]: startTime - * @return poolManager_ The address of the PoolManager contract that will be deployed. - * @return pool_ The address of the Pool contract that will be deployed. - * @return poolDelegateCover_ The address of the PoolDelegateCover contract that will be deployed. - * @return withdrawalManager_ The address of the WithdrawalManager contract that will be deployed. - * @return loanManagers_ The address of the LoanManager contracts that will be deployed. + * @dev Gets the addresses that would result from a deployment. + * @param poolManagerFactory_ The address of the PoolManager factory to use. + * @param poolDelegate_ The address of the PoolDelegate that will deploy the Pool. + * @param asset_ The address of the asset to use. + * @param initialSupply_ The initial supply of the Pool. + * @param name_ The name of the Pool. + * @param symbol_ The symbol of the Pool. + * @return poolManager_ The address of the PoolManager contract that will be deployed. + * @return pool_ The address of the Pool contract that will be deployed. + * @return poolDelegateCover_ The address of the PoolDelegateCover contract that will be deployed. */ - function getDeploymentAddresses( - address poolDelegate_, - address poolManagerFactory_, - address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, - address asset_, - string memory name_, - string memory symbol_, - uint256[7] memory configParams_ - ) - external view - returns ( - address poolManager_, - address pool_, - address poolDelegateCover_, - address withdrawalManager_, - address[] memory loanManagers_ - ); + function getPoolDeploymentAddresses( + address poolManagerFactory_, + address poolDelegate_, + address asset_, + uint256 initialSupply_, + string memory name_, + string memory symbol_ + ) external view returns (address poolManager_, address pool_, address poolDelegateCover_); /** - * @dev Gets the addresses that would result from a deployment. - * @param poolDelegate_ The address of the PoolDelegate that will deploy the Pool. - * @param poolManagerFactory_ The address of the PoolManager factory to use. - * @param withdrawalManagerFactory_ The address of the WithdrawalManager factory to use. - * @param loanManagerFactories_ An array of LoanManager factories to use. - * @param asset_ The address of the asset to use. - * @param name_ The name of the Pool. - * @param symbol_ The symbol of the Pool. - * @param configParams_ Array of uint256 config parameters. Array used to avoid stack too deep issues. - * [0]: liquidityCap - * [1]: delegateManagementFeeRate - * [2]: coverAmountRequired - * [3]: initialSupply - * @return poolManager_ The address of the PoolManager contract that will be deployed. - * @return pool_ The address of the Pool contract that will be deployed. - * @return poolDelegateCover_ The address of the PoolDelegateCover contract that will be deployed. - * @return withdrawalManager_ The address of the WithdrawalManager contract that will be deployed. - * @return loanManagers_ The address of the LoanManager contracts that will be deployed. + * @dev Gets the address of the Cyclical Withdrawal Manager that would result from a deployment. + * @param withdrawalManagerFactory_ The address of the WithdrawalManager factory to use. + * @param pool_ The address of the Pool to use. + * @param poolManager_ The address of the PoolManager to use. + * @param startTime_ The start time of the WithdrawalManager. + * @param cycleDuration_ The cycle duration of the WithdrawalManager. + * @param windowDuration_ The window duration of the WithdrawalManager. + * @return withdrawalManager_ The address of the WithdrawalManager contract that will be deployed. */ - function getDeploymentAddresses( - address poolDelegate_, - address poolManagerFactory_, - address withdrawalManagerFactory_, - address[] memory loanManagerFactories_, - address asset_, - string memory name_, - string memory symbol_, - uint256[4] memory configParams_ - ) - external view - returns ( - address poolManager_, - address pool_, - address poolDelegateCover_, - address withdrawalManager_, - address[] memory loanManagers_ - ); + function getCyclicalWithdrawalManagerAddress( + address withdrawalManagerFactory_, + address pool_, + address poolManager_, + uint256 startTime_, + uint256 cycleDuration_, + uint256 windowDuration_ + ) external view returns (address withdrawalManager_); + + /** + * @dev Gets the address of the Queue Withdrawal Manager that would result from a deployment. + * @param withdrawalManagerFactory_ The address of the WithdrawalManager factory to use. + * @param pool_ The address of the Pool to use. + * @param poolManager_ The address of the PoolManager to use. + * @return withdrawalManager_ The address of the WithdrawalManager contract that will be deployed. + */ + function getQueueWithdrawalManagerAddress( + address withdrawalManagerFactory_, + address pool_, + address poolManager_ + ) external view returns (address withdrawalManager_); + /** + * @dev Gets the addresses of the Strategies that would result from a deployment. + * @param poolManager_ The address of the PoolManager to use. + * @param strategyFactories_ An array of Strategy factories to use. + * @param strategyDeploymentData_ An array of bytes to use to construct the strategies. + * @return strategies_ The addresses of the Strategy contracts that will be deployed. + */ + function getStrategiesAddresses( + address poolManager_, + address[] memory strategyFactories_, + bytes[] memory strategyDeploymentData_ + ) external view returns (address[] memory strategies_); + + /** + * @dev Gets the address of the Globals contract. + * @return globals_ The address of the Globals contract. + */ function globals() external view returns (address globals_); } diff --git a/contracts/interfaces/IMaplePoolManager.sol b/contracts/interfaces/IMaplePoolManager.sol index 0fd8bc22..b82fa2e0 100644 --- a/contracts/interfaces/IMaplePoolManager.sol +++ b/contracts/interfaces/IMaplePoolManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { IMapleProxied } from "../../modules/maple-proxy-factory/contracts/interfaces/IMapleProxied.sol"; @@ -50,11 +50,11 @@ interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage { event DelegateManagementFeeRateSet(uint256 managementFeeRate_); /** - * @dev Emitted when a loan manager is set as valid. - * @param loanManager_ The address of the loan manager. - * @param isLoanManager_ Whether the loan manager is valid. + * @dev Emitted when a strategy is set as valid. + * @param strategy_ The address of the strategy. + * @param isStrategy_ Whether the strategy is valid. */ - event IsLoanManagerSet(address indexed loanManager_, bool isLoanManager_); + event IsStrategySet(address indexed strategy_, bool isStrategy_); /** * @dev Emitted when a new liquidity cap is set. @@ -63,10 +63,10 @@ interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage { event LiquidityCapSet(uint256 liquidityCap_); /** - * @dev Emitted when a new loan manager is added. - * @param loanManager_ The address of the new loan manager. + * @dev Emitted when a new strategy is added. + * @param strategy_ The address of the new strategy. */ - event LoanManagerAdded(address indexed loanManager_); + event StrategyAdded(address indexed strategy_); /** * @dev Emitted when the pending pool delegate accepts the ownership transfer. @@ -155,11 +155,13 @@ interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage { /**************************************************************************************************************************************/ /** - * @dev Adds a new loan manager. - * @param loanManagerFactory_ The address of the loan manager factory to use. - * @return loanManager_ The address of the new loan manager. + * @dev Adds a new strategy. + * NOTE: The PoolManager address is encoded and prepended to the extraDeploymentData. + * @param strategyFactory_ The address of the strategy factory to use. + * @param extraDeploymentData_ The data to construct the strategy. + * @return strategy_ The address of the new strategy. */ - function addLoanManager(address loanManagerFactory_) external returns (address loanManager_); + function addStrategy(address strategyFactory_, bytes calldata extraDeploymentData_) external returns (address strategy_); /** * @dev Complete the configuration. @@ -179,11 +181,11 @@ interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage { function setDelegateManagementFeeRate(uint256 delegateManagementFeeRate_) external; /** - * @dev Sets if the loanManager is valid in the isLoanManager mapping. - * @param loanManager_ The address of the loanManager - * @param isLoanManager_ Whether the loanManager is valid. + * @dev Sets if the strategy is valid in the isStrategy mapping. + * @param strategy_ The address of the strategy + * @param isStrategy_ Whether the strategy is valid. */ - function setIsLoanManager(address loanManager_, bool isLoanManager_) external; + function setIsStrategy(address strategy_, bool isStrategy_) external; /** * @dev Sets the value for liquidity cap. @@ -208,9 +210,9 @@ interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage { /**************************************************************************************************************************************/ /** - * @dev LoanManager can request funds from the pool via the poolManager. + * @dev Strategy can request funds from the pool via the poolManager. * @param destination_ The address to send the funds to. - * @param principal_ The principal amount to fund the loan with. + * @param principal_ The principal amount to fund the strategy with. */ function requestFunds(address destination_, uint256 principal_) external; @@ -400,10 +402,10 @@ interface IMaplePoolManager is IMapleProxied, IMaplePoolManagerStorage { function hasSufficientCover() external view returns (bool hasSufficientCover_); /** - * @dev Returns the length of the `loanManagerList`. - * @return loanManagerListLength_ The length of the `loanManagerList`. + * @dev Returns the length of the `strategyList`. + * @return strategyListLength_ The length of the `strategyList`. */ - function loanManagerListLength() external view returns (uint256 loanManagerListLength_); + function strategyListLength() external view returns (uint256 strategyListLength_); /** * @dev Returns the amount of total assets. diff --git a/contracts/interfaces/IMaplePoolManagerFactory.sol b/contracts/interfaces/IMaplePoolManagerFactory.sol index 3e4b22f3..fea0971d 100644 --- a/contracts/interfaces/IMaplePoolManagerFactory.sol +++ b/contracts/interfaces/IMaplePoolManagerFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { IMapleProxyFactory } from "../../modules/maple-proxy-factory/contracts/MapleProxyFactory.sol"; diff --git a/contracts/interfaces/IMaplePoolManagerInitializer.sol b/contracts/interfaces/IMaplePoolManagerInitializer.sol index b73b11a7..b5489a96 100644 --- a/contracts/interfaces/IMaplePoolManagerInitializer.sol +++ b/contracts/interfaces/IMaplePoolManagerInitializer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; interface IMaplePoolManagerInitializer { diff --git a/contracts/interfaces/IMaplePoolManagerStorage.sol b/contracts/interfaces/IMaplePoolManagerStorage.sol index 4d11be0b..c4423d90 100644 --- a/contracts/interfaces/IMaplePoolManagerStorage.sol +++ b/contracts/interfaces/IMaplePoolManagerStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; interface IMaplePoolManagerStorage { @@ -28,11 +28,11 @@ interface IMaplePoolManagerStorage { function delegateManagementFeeRate() external view returns (uint256 delegateManagementFeeRate_); /** - * @dev Returns whether or not the given address is a loan manager. - * @param loan_ The address of the loan. - * @return isLoanManager_ True if the address is a loan manager. + * @dev Returns whether or not the given address is a strategy. + * @param strategy_ The address of the strategy. + * @return isStrategy_ True if the address is a strategy. */ - function isLoanManager(address loan_) external view returns (bool isLoanManager_); + function isStrategy(address strategy_) external view returns (bool isStrategy_); /** * @dev Gets the liquidity cap for the pool. @@ -41,11 +41,11 @@ interface IMaplePoolManagerStorage { function liquidityCap() external view returns (uint256 liquidityCap_); /** - * @dev Gets the address of the loan manager in the list. - * @param index_ The index to get the address of. - * @return loanManager_ The address in the list. + * @dev Gets the address of the strategy in the list. + * @param index_ The index to get the address of. + * @return strategy_ The address in the list. */ - function loanManagerList(uint256 index_) external view returns (address loanManager_); + function strategyList(uint256 index_) external view returns (address strategy_); /** * @dev Gets the address of the pending pool delegate. diff --git a/contracts/interfaces/Interfaces.sol b/contracts/interfaces/Interfaces.sol index ff7c1be1..2a33d68e 100644 --- a/contracts/interfaces/Interfaces.sol +++ b/contracts/interfaces/Interfaces.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; interface IERC20Like { @@ -51,18 +51,23 @@ interface IGlobalsLike { } -interface ILoanManagerLike { +interface IStrategyLike { function assetsUnderManagement() external view returns (uint256 assetsUnderManagement_); + function unrealizedLosses() external view returns (uint256 unrealizedLosses_); + +} + +interface ILoanManagerLike { + + function finishCollateralLiquidation(address loan_) external returns (uint256 remainingLosses_, uint256 serviceFee_); function triggerDefault(address loan_, address liquidatorFactory_) external returns (bool liquidationComplete_, uint256 remainingLosses_, uint256 platformFees_); - function unrealizedLosses() external view returns (uint256 unrealizedLosses_); - } interface ILoanLike { @@ -97,7 +102,7 @@ interface IPoolLike is IERC20Like { interface IPoolManagerLike { - function addLoanManager(address loanManagerFactory_) external returns (address loanManager_); + function addStrategy(address strategyFactory_, bytes calldata deploymentData_) external returns (address strategy_); function canCall(bytes32 functionId_, address caller_, bytes memory data_) external view diff --git a/contracts/proxy/MaplePoolManagerFactory.sol b/contracts/proxy/MaplePoolManagerFactory.sol index e16cc103..1a040da2 100644 --- a/contracts/proxy/MaplePoolManagerFactory.sol +++ b/contracts/proxy/MaplePoolManagerFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { IMapleProxyFactory, MapleProxyFactory } from "../../modules/maple-proxy-factory/contracts/MapleProxyFactory.sol"; diff --git a/contracts/proxy/MaplePoolManagerInitializer.sol b/contracts/proxy/MaplePoolManagerInitializer.sol index c67a84f0..cb550f04 100644 --- a/contracts/proxy/MaplePoolManagerInitializer.sol +++ b/contracts/proxy/MaplePoolManagerInitializer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { IGlobalsLike, IMapleProxyFactoryLike } from "../interfaces/Interfaces.sol"; import { IMaplePoolManagerInitializer } from "../interfaces/IMaplePoolManagerInitializer.sol"; diff --git a/contracts/proxy/MaplePoolManagerMigrator.sol b/contracts/proxy/MaplePoolManagerMigrator.sol index 395e16ad..8331fc86 100644 --- a/contracts/proxy/MaplePoolManagerMigrator.sol +++ b/contracts/proxy/MaplePoolManagerMigrator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { MapleProxiedInternals } from "../../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol"; diff --git a/contracts/proxy/MaplePoolManagerStorage.sol b/contracts/proxy/MaplePoolManagerStorage.sol index 7e42a290..7433ed12 100644 --- a/contracts/proxy/MaplePoolManagerStorage.sol +++ b/contracts/proxy/MaplePoolManagerStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { IMaplePoolManagerStorage } from "../interfaces/IMaplePoolManagerStorage.sol"; @@ -24,11 +24,11 @@ abstract contract MaplePoolManagerStorage is IMaplePoolManagerStorage { uint256 public override liquidityCap; uint256 public override delegateManagementFeeRate; - mapping(address => bool) public override isLoanManager; + mapping(address => bool) public override isStrategy; mapping(address => bool) __deprecated_isValidLender; - address[] public override loanManagerList; + address[] public override strategyList; address public override poolPermissionManager; diff --git a/contracts/proxy/MaplePoolManagerWMMigrator.sol b/contracts/proxy/MaplePoolManagerWMMigrator.sol deleted file mode 100644 index 41d0068a..00000000 --- a/contracts/proxy/MaplePoolManagerWMMigrator.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; - -import { MapleProxiedInternals } from "../../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol"; - -import { IMapleProxyFactoryLike, IGlobalsLike, IWithdrawalManagerLike } from "../interfaces/Interfaces.sol"; - -import { MaplePoolManagerStorage } from "./MaplePoolManagerStorage.sol"; - -contract MaplePoolManagerWMMigrator is MapleProxiedInternals, MaplePoolManagerStorage { - - event WithdrawalManagerSet(address withdrawalManager_); - - fallback() external { - address withdrawalManager_ = abi.decode(msg.data, (address)); - address globals_ = IMapleProxyFactoryLike(_factory()).mapleGlobals(); - address factory_ = IWithdrawalManagerLike(withdrawalManager_).factory(); - - require(IGlobalsLike(globals_).isInstanceOf("QUEUE_POOL_MANAGER", address(this)), "PMM:INVALID_PM"); - require(IGlobalsLike(globals_).isInstanceOf("WITHDRAWAL_MANAGER_QUEUE_FACTORY", factory_), "PMM:INVALID_WM_FACTORY"); - - require(IMapleProxyFactoryLike(factory_).isInstance(withdrawalManager_), "PMM:INVALID_WM"); - - withdrawalManager = withdrawalManager_; - - emit WithdrawalManagerSet(withdrawalManager_); - } - -} diff --git a/foundry.toml b/foundry.toml index 05293fe4..01852341 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,7 +2,6 @@ contracts = 'contracts' # The contract directory test = 'tests' # The test directory libs = ['modules'] # A list of library directories -solc_version = '0.8.7' # Override for the solc version (setting this ignores `auto_detect_solc`) optimizer = false # Enable or disable the solc optimizer verbosity = 3 # The verbosity of tests block_timestamp = 1_622_400_000 # Timestamp for tests (non-zero) diff --git a/modules/erc20 b/modules/erc20 index b2fd236e..baf791a9 160000 --- a/modules/erc20 +++ b/modules/erc20 @@ -1 +1 @@ -Subproject commit b2fd236e9a69a96d8eb3d5ac86e3260904d1d04b +Subproject commit baf791a9f894b0b319a2d42d5b9f8d30349ebaad diff --git a/modules/maple-proxy-factory b/modules/maple-proxy-factory index c5405f96..78057cd6 160000 --- a/modules/maple-proxy-factory +++ b/modules/maple-proxy-factory @@ -1 +1 @@ -Subproject commit c5405f964e10385b46c4c00e53a606d74679b93f +Subproject commit 78057cd6415ed2938ffa02b155fa02e0169bc240 diff --git a/tests/ERC20.t.sol b/tests/ERC20.t.sol index 00d51ea9..4e243fdb 100644 --- a/tests/ERC20.t.sol +++ b/tests/ERC20.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.25; import { ERC20BaseTest } from "../modules/erc20/contracts/test/ERC20.t.sol"; import { ERC20PermitTest } from "../modules/erc20/contracts/test/ERC20.t.sol"; diff --git a/tests/MaplePool.t.sol b/tests/MaplePool.t.sol index ed696567..726d23a7 100644 --- a/tests/MaplePool.t.sol +++ b/tests/MaplePool.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { stdError } from "../modules/forge-std/src/StdError.sol"; @@ -19,9 +19,9 @@ import { MockWithdrawalManager } from "./mocks/Mocks.sol"; -import { GlobalsBootstrapper } from "./bootstrap/GlobalsBootstrapper.sol"; +import { TestBase } from "./utils/TestBase.sol"; -contract TestBase is Test, GlobalsBootstrapper { +contract PoolTestBase is TestBase { address POOL_DELEGATE = makeAddr("POOL_DELEGATE"); @@ -43,8 +43,8 @@ contract TestBase is Test, GlobalsBootstrapper { factory = new MaplePoolManagerFactory(address(globals)); - implementation = address(new MaplePoolManager()); - initializer = address(new MaplePoolManagerInitializer()); + implementation = deploy("MaplePoolManager"); + initializer = deploy("MaplePoolManagerInitializer"); vm.startPrank(GOVERNOR); factory.registerImplementation(1, implementation, initializer); @@ -90,7 +90,7 @@ contract TestBase is Test, GlobalsBootstrapper { // Returns a valid `permit` signature signed by this contract's `owner` address function _getValidPermitSignature(address owner_, address spender_, uint256 value_, uint256 nonce_, uint256 deadline_, uint256 ownerSk_) - internal returns (uint8 v_, bytes32 r_, bytes32 s_) + internal view returns (uint8 v_, bytes32 r_, bytes32 s_) { return vm.sign(ownerSk_, _getDigest(owner_, spender_, value_, nonce_, deadline_)); } @@ -121,7 +121,7 @@ contract TestBase is Test, GlobalsBootstrapper { } -contract ConstructorTests is TestBase { +contract ConstructorTests is PoolTestBase { function setUp() public override {} @@ -162,7 +162,7 @@ contract ConstructorTests is TestBase { } -contract DepositTests is TestBase { +contract DepositTests is PoolTestBase { uint256 DEPOSIT_AMOUNT = 1e18; @@ -227,7 +227,7 @@ contract DepositTests is TestBase { } -contract DepositWithPermitTests is TestBase { +contract DepositWithPermitTests is PoolTestBase { address STAKER; address NOT_STAKER; @@ -369,7 +369,7 @@ contract DepositWithPermitTests is TestBase { } -contract MintTests is TestBase { +contract MintTests is PoolTestBase { uint256 MINT_AMOUNT = 1e18; @@ -432,7 +432,7 @@ contract MintTests is TestBase { } -contract MintWithPermitTests is TestBase { +contract MintWithPermitTests is PoolTestBase { address STAKER; address NOT_STAKER; @@ -579,7 +579,7 @@ contract MintWithPermitTests is TestBase { } -contract RedeemTests is TestBase { +contract RedeemTests is PoolTestBase { uint256 depositAmount = 1_000e6; @@ -731,7 +731,7 @@ contract RedeemTests is TestBase { } -contract RemoveSharesTests is TestBase { +contract RemoveSharesTests is PoolTestBase { uint256 depositAmount = 1_000e6; @@ -794,7 +794,7 @@ contract RemoveSharesTests is TestBase { } -contract RequestRedeemTests is TestBase { +contract RequestRedeemTests is PoolTestBase { uint256 depositAmount = 1_000e6; @@ -876,7 +876,7 @@ contract RequestRedeemTests is TestBase { } -contract RequestWithdraw is TestBase { +contract RequestWithdraw is PoolTestBase { uint256 depositAmount = 1_000e6; @@ -946,7 +946,7 @@ contract RequestWithdraw is TestBase { } -contract TransferTests is TestBase { +contract TransferTests is PoolTestBase { address RECIPIENT = makeAddr("RECIPIENT"); @@ -963,7 +963,7 @@ contract TransferTests is TestBase { } -contract TransferFromTests is TestBase { +contract TransferFromTests is PoolTestBase { address RECIPIENT = makeAddr("RECIPIENT"); address OWNER = makeAddr("OWNER"); @@ -986,7 +986,7 @@ contract TransferFromTests is TestBase { } -contract WithdrawTests is TestBase { +contract WithdrawTests is PoolTestBase { uint256 depositAmount = 1_000e6; @@ -1025,7 +1025,7 @@ contract WithdrawTests is TestBase { } -contract PreviewDepositTests is TestBase { +contract PreviewDepositTests is PoolTestBase { function test_previewDeposit_initialState() public { _setupPool({ totalSupply_: 0, totalAssets_: 0, unrealizedLosses_: 0 }); @@ -1102,7 +1102,7 @@ contract PreviewDepositTests is TestBase { } -contract PreviewMintTests is TestBase { +contract PreviewMintTests is PoolTestBase { function test_previewMint_initialState() public { _setupPool({ totalSupply_: 0, totalAssets_: 0, unrealizedLosses_: 0 }); @@ -1174,7 +1174,7 @@ contract PreviewMintTests is TestBase { } -contract ConvertToExitAssetsTests is TestBase { +contract ConvertToExitAssetsTests is PoolTestBase { function test_convertToExitAssets_zeroSupply() external { assertEq(pool.convertToExitAssets(0), 0); @@ -1395,7 +1395,7 @@ contract ConvertToExitAssetsTests is TestBase { // } -contract ConvertToAssetsTests is TestBase { +contract ConvertToAssetsTests is PoolTestBase { function test_convertToAssets_initialState() public { _setupPool({ totalSupply_: 0, totalAssets_: 0, unrealizedLosses_: 0 }); @@ -1462,7 +1462,7 @@ contract ConvertToAssetsTests is TestBase { } } -contract ConvertToSharesTests is TestBase { +contract ConvertToSharesTests is PoolTestBase { function test_convertToShares_initialState() public { _setupPool({ totalSupply_: 0, totalAssets_: 0, unrealizedLosses_: 0 }); diff --git a/tests/MaplePoolDelegateCover.t.sol b/tests/MaplePoolDelegateCover.t.sol index 9d17badc..bcc7fa65 100644 --- a/tests/MaplePoolDelegateCover.t.sol +++ b/tests/MaplePoolDelegateCover.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { MockERC20 } from "../modules/erc20/contracts/test/mocks/MockERC20.sol"; diff --git a/tests/MaplePoolDeployer.t.sol b/tests/MaplePoolDeployer.t.sol index 930e4dc5..d0238b2e 100644 --- a/tests/MaplePoolDeployer.t.sol +++ b/tests/MaplePoolDeployer.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { MockERC20 } from "../modules/erc20/contracts/test/mocks/MockERC20.sol"; @@ -13,9 +13,9 @@ import { IMaplePoolManager } from "../contracts/interfaces/IMaplePoolManager.sol import { MockGlobals, MockMigrator, MockPoolPermissionManager, MockProxied } from "./mocks/Mocks.sol"; -import { GlobalsBootstrapper } from "./bootstrap/GlobalsBootstrapper.sol"; +import { TestBase } from "./utils/TestBase.sol"; -contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { +contract MaplePoolDeployerTests is TestBase { address asset; address poolDelegate; @@ -29,7 +29,8 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { uint256 coverAmountRequired = 10e18; - address[] loanManagerFactories; + address[] strategyFactories; + bytes[] strategyDeploymentData; uint256[7] configParamsCycle = [ 1_000_000e18, @@ -48,34 +49,45 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { 0 ]; + uint256[7] noCoverConfigParamsCycle = [ + 1_000_000e18, + 0.1e6, + 0, + 3 days, + 1 days, + 0, + block.timestamp + 10 days + ]; + function setUp() public virtual { asset = address(new MockERC20("Asset", "AT", 18)); poolDelegate = makeAddr("poolDelegate"); _deployAndBootstrapGlobals(asset, poolDelegate); - for (uint256 i; i < 2; ++i) { - loanManagerFactories.push(address(new MapleProxyFactory(globals))); - } - poolManagerFactory = address(new MapleProxyFactory(globals)); withdrawalManagerFactory = address(new MapleProxyFactory(globals)); + for (uint256 i; i < 2; ++i) { + strategyFactories.push(address(new MapleProxyFactory(globals))); + strategyDeploymentData.push(new bytes(0)); + } + poolPermissionManager = address(new MockPoolPermissionManager()); vm.startPrank(GOVERNOR); IMapleProxyFactory(poolManagerFactory).registerImplementation( 1, - address(new MaplePoolManager()), - address(new MaplePoolManagerInitializer()) + deploy("MaplePoolManager"), + deploy("MaplePoolManagerInitializer") ); IMapleProxyFactory(poolManagerFactory).setDefaultVersion(1); - for (uint256 i; i < loanManagerFactories.length; ++i) { - IMapleProxyFactory(loanManagerFactories[i]).registerImplementation(1, address(new MockProxied()), address(new MockMigrator())); - IMapleProxyFactory(loanManagerFactories[i]).setDefaultVersion(1); + for (uint256 i; i < strategyFactories.length; ++i) { + IMapleProxyFactory(strategyFactories[i]).registerImplementation(1, address(new MockProxied()), address(new MockMigrator())); + IMapleProxyFactory(strategyFactories[i]).setDefaultVersion(1); } IMapleProxyFactory(withdrawalManagerFactory).registerImplementation(1, address(new MockProxied()), address(new MockMigrator())); @@ -87,18 +99,21 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { MockGlobals(globals).setValidPoolDeployer(poolDeployer, true); } - function test_deployPool_transferFailed() external { - MockERC20(asset).mint(poolDelegate, coverAmountRequired - 1); + function test_deployPool_mismatchingArrays() external { + MockERC20(asset).mint(poolDelegate, coverAmountRequired); vm.prank(poolDelegate); MockERC20(asset).approve(poolDeployer, coverAmountRequired); + strategyDeploymentData.push(""); + vm.prank(poolDelegate); - vm.expectRevert("PD:DP:TRANSFER_FAILED"); + vm.expectRevert("PD:DP:MISMATCHING_ARRAYS"); MaplePoolDeployer(poolDeployer).deployPool( poolManagerFactory, withdrawalManagerFactory, - loanManagerFactories, + strategyFactories, + strategyDeploymentData, asset, poolPermissionManager, name, @@ -107,17 +122,19 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { ); } - function test_deployPool_invalidPoolDelegate() external { - MockERC20(asset).mint(poolDelegate, coverAmountRequired); + function test_deployPool_transferFailed() external { + MockERC20(asset).mint(poolDelegate, coverAmountRequired - 1); vm.prank(poolDelegate); MockERC20(asset).approve(poolDeployer, coverAmountRequired); - vm.expectRevert("PD:DP:INVALID_PD"); + vm.prank(poolDelegate); + vm.expectRevert("PD:DP:TRANSFER_FAILED"); MaplePoolDeployer(poolDeployer).deployPool( poolManagerFactory, withdrawalManagerFactory, - loanManagerFactories, + strategyFactories, + strategyDeploymentData, asset, poolPermissionManager, name, @@ -126,33 +143,64 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { ); } - function test_deployPool_success_withCoverRequired() external { + function test_deployPool_invalidPoolDelegate() external { + MockERC20(asset).mint(poolDelegate, coverAmountRequired); + vm.prank(poolDelegate); MockERC20(asset).approve(poolDeployer, coverAmountRequired); - MockERC20(asset).mint(poolDelegate, coverAmountRequired); - ( - address expectedPoolManager_, - address expectedPool_, - address expectedPoolDelegateCover_, - address expectedWithdrawalManager_, - address[] memory expectedLoanManagers_ - ) = MaplePoolDeployer(poolDeployer).getDeploymentAddresses( - poolDelegate, + vm.expectRevert("PD:DP:INVALID_PD"); + MaplePoolDeployer(poolDeployer).deployPool( poolManagerFactory, withdrawalManagerFactory, - loanManagerFactories, + strategyFactories, + strategyDeploymentData, asset, + poolPermissionManager, name, symbol, configParamsCycle ); + } + + function test_deployPool_success_withCoverRequired_cyclicalWM() external { + vm.prank(poolDelegate); + MockERC20(asset).approve(poolDeployer, coverAmountRequired); + MockERC20(asset).mint(poolDelegate, coverAmountRequired); + + (address expectedPoolManager_, address expectedPool_, address expectedPoolDelegateCover_) = + MaplePoolDeployer(poolDeployer).getPoolDeploymentAddresses( + poolManagerFactory, + poolDelegate, + asset, + 0, + name, + symbol + ); + + address expectedWithdrawalManager_ = + MaplePoolDeployer(poolDeployer).getCyclicalWithdrawalManagerAddress( + withdrawalManagerFactory, + expectedPool_, + expectedPoolManager_, + configParamsCycle[6], + configParamsCycle[3], + configParamsCycle[4] + ); + + address[] memory expectedStrategies_ = + MaplePoolDeployer(poolDeployer).getStrategiesAddresses( + expectedPoolManager_, + strategyFactories, + strategyDeploymentData + ); vm.prank(poolDelegate); address poolManager_ = MaplePoolDeployer(poolDeployer).deployPool( poolManagerFactory, withdrawalManagerFactory, - loanManagerFactories, + strategyFactories, + strategyDeploymentData, asset, poolPermissionManager, name, @@ -165,44 +213,45 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { assertEq(IMaplePoolManager(poolManager_).poolDelegateCover(), expectedPoolDelegateCover_); assertEq(IMaplePoolManager(poolManager_).withdrawalManager(), expectedWithdrawalManager_); - for (uint256 i_; i_ < loanManagerFactories.length; ++i_) { - assertEq(IMaplePoolManager(poolManager_).loanManagerList(i_), expectedLoanManagers_[i_]); + for (uint256 i_; i_ < strategyFactories.length; ++i_) { + assertEq(IMaplePoolManager(poolManager_).strategyList(i_), expectedStrategies_[i_]); } } - function test_deployPool_success_withoutCoverRequired() external { - uint256[7] memory noCoverConfigParamsCycle = [ - uint256(1_000_000e18), - 0.1e6, - 0, - 3 days, - 1 days, - 0, - block.timestamp + 10 days - ]; - - ( - address expectedPoolManager_, - address expectedPool_, - address expectedPoolDelegateCover_, - address expectedWithdrawalManager_, - address[] memory expectedLoanManagers_ - ) = MaplePoolDeployer(poolDeployer).getDeploymentAddresses( - poolDelegate, - poolManagerFactory, - withdrawalManagerFactory, - loanManagerFactories, - asset, - name, - symbol, - configParamsCycle - ); + function test_deployPool_success_withoutCoverRequired_cyclicalWM() external { + (address expectedPoolManager_, address expectedPool_, address expectedPoolDelegateCover_) = + MaplePoolDeployer(poolDeployer).getPoolDeploymentAddresses( + poolManagerFactory, + poolDelegate, + asset, + 0, + name, + symbol + ); + + address expectedWithdrawalManager_ = + MaplePoolDeployer(poolDeployer).getCyclicalWithdrawalManagerAddress( + withdrawalManagerFactory, + expectedPool_, + expectedPoolManager_, + configParamsCycle[6], + configParamsCycle[3], + configParamsCycle[4] + ); + + address[] memory expectedStrategies_ = + MaplePoolDeployer(poolDeployer).getStrategiesAddresses( + expectedPoolManager_, + strategyFactories, + strategyDeploymentData + ); vm.prank(poolDelegate); address poolManager_ = MaplePoolDeployer(poolDeployer).deployPool( poolManagerFactory, withdrawalManagerFactory, - loanManagerFactories, + strategyFactories, + strategyDeploymentData, asset, poolPermissionManager, name, @@ -215,8 +264,8 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { assertEq(IMaplePoolManager(poolManager_).poolDelegateCover(), expectedPoolDelegateCover_); assertEq(IMaplePoolManager(poolManager_).withdrawalManager(), expectedWithdrawalManager_); - for (uint256 i_; i_ < loanManagerFactories.length; ++i_) { - assertEq(IMaplePoolManager(poolManager_).loanManagerList(i_), expectedLoanManagers_[i_]); + for (uint256 i_; i_ < strategyFactories.length; ++i_) { + assertEq(IMaplePoolManager(poolManager_).strategyList(i_), expectedStrategies_[i_]); } } @@ -225,28 +274,36 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { MockERC20(asset).approve(poolDeployer, coverAmountRequired); MockERC20(asset).mint(poolDelegate, coverAmountRequired); - ( - address expectedPoolManager_, - address expectedPool_, - address expectedPoolDelegateCover_, - address expectedWithdrawalManager_, - address[] memory expectedLoanManagers_ - ) = MaplePoolDeployer(poolDeployer).getDeploymentAddresses( - poolDelegate, - poolManagerFactory, - withdrawalManagerFactory, - loanManagerFactories, - asset, - name, - symbol, - configParamsQueue - ); + (address expectedPoolManager_, address expectedPool_, address expectedPoolDelegateCover_) = + MaplePoolDeployer(poolDeployer).getPoolDeploymentAddresses( + poolManagerFactory, + poolDelegate, + asset, + 0, + name, + symbol + ); + + address expectedWithdrawalManager_ = + MaplePoolDeployer(poolDeployer).getQueueWithdrawalManagerAddress( + withdrawalManagerFactory, + expectedPool_, + expectedPoolManager_ + ); + + address[] memory expectedStrategies_ = + MaplePoolDeployer(poolDeployer).getStrategiesAddresses( + expectedPoolManager_, + strategyFactories, + strategyDeploymentData + ); vm.prank(poolDelegate); address poolManager_ = MaplePoolDeployer(poolDeployer).deployPool( poolManagerFactory, withdrawalManagerFactory, - loanManagerFactories, + strategyFactories, + strategyDeploymentData, asset, poolPermissionManager, name, @@ -259,8 +316,8 @@ contract MaplePoolDeployerTests is Test, GlobalsBootstrapper { assertEq(IMaplePoolManager(poolManager_).poolDelegateCover(), expectedPoolDelegateCover_); assertEq(IMaplePoolManager(poolManager_).withdrawalManager(), expectedWithdrawalManager_); - for (uint256 i_; i_ < loanManagerFactories.length; ++i_) { - assertEq(IMaplePoolManager(poolManager_).loanManagerList(i_), expectedLoanManagers_[i_]); + for (uint256 i_; i_ < strategyFactories.length; ++i_) { + assertEq(IMaplePoolManager(poolManager_).strategyList(i_), expectedStrategies_[i_]); } } diff --git a/tests/MaplePoolManager.t.sol b/tests/MaplePoolManager.t.sol index 0d3ec512..3f34b0a8 100644 --- a/tests/MaplePoolManager.t.sol +++ b/tests/MaplePoolManager.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { MockERC20 } from "../modules/erc20/contracts/test/mocks/MockERC20.sol"; @@ -23,9 +23,9 @@ import { import { MaplePoolManagerHarness } from "./harnesses/MaplePoolManagerHarness.sol"; -import { GlobalsBootstrapper } from "./bootstrap/GlobalsBootstrapper.sol"; +import { TestBase } from "./utils/TestBase.sol"; -contract TestBase is Test, GlobalsBootstrapper { +contract PoolManagerTestBase is TestBase { address internal POOL_DELEGATE = makeAddr("POOL_DELEGATE"); @@ -102,7 +102,7 @@ contract TestBase is Test, GlobalsBootstrapper { } -contract CompleteConfigurationTests is TestBase { +contract CompleteConfigurationTests is PoolManagerTestBase { function test_completeConfiguration_paused() external { MockGlobals(globals).__setFunctionPaused(true); @@ -126,7 +126,7 @@ contract CompleteConfigurationTests is TestBase { } -contract MigrateTests is TestBase { +contract MigrateTests is PoolManagerTestBase { address internal invalidMigrator = address(new MockPoolManagerMigratorInvalidPoolDelegateCover()); address internal migrator = address(new MockPoolManagerMigrator()); @@ -166,9 +166,9 @@ contract MigrateTests is TestBase { } -contract SetImplementationTests is TestBase { +contract SetImplementationTests is PoolManagerTestBase { - address internal newImplementation = address(new MaplePoolManager()); + address internal newImplementation = deploy("MaplePoolManager"); function test_setImplementation_paused() external { MockGlobals(globals).__setFunctionPaused(true); @@ -193,11 +193,11 @@ contract SetImplementationTests is TestBase { } -contract UpgradeTests is TestBase { +contract UpgradeTests is PoolManagerTestBase { address internal SECURITY_ADMIN = makeAddr("SECURITY_ADMIN"); - address internal newImplementation = address(new MaplePoolManager()); + address internal newImplementation = deploy("MaplePoolManager"); function setUp() public override { super.setUp(); @@ -257,7 +257,7 @@ contract UpgradeTests is TestBase { } -contract AcceptPoolDelegate_SetterTests is TestBase { +contract AcceptPoolDelegate_SetterTests is PoolManagerTestBase { address internal SET_ADDRESS = makeAddr("SET_ADDRESS"); @@ -302,7 +302,7 @@ contract AcceptPoolDelegate_SetterTests is TestBase { } -contract SetPendingPoolDelegate_SetterTests is TestBase { +contract SetPendingPoolDelegate_SetterTests is PoolManagerTestBase { address internal SET_ADDRESS = makeAddr("SET_ADDRESS"); @@ -348,7 +348,7 @@ contract SetPendingPoolDelegate_SetterTests is TestBase { } -contract SetActive_SetterTests is TestBase { +contract SetActive_SetterTests is PoolManagerTestBase { function setUp() public override { super.setUp(); @@ -386,7 +386,7 @@ contract SetActive_SetterTests is TestBase { } } -contract SetLiquidityCap_SetterTests is TestBase { +contract SetLiquidityCap_SetterTests is PoolManagerTestBase { function test_setLiquidityCap_paused() external { MockGlobals(globals).__setFunctionPaused(true); @@ -399,7 +399,7 @@ contract SetLiquidityCap_SetterTests is TestBase { function test_setLiquidityCap_notPoolDelegate() external { poolManager.__setConfigured(true); - vm.expectRevert("PM:NO_AUTH"); + vm.expectRevert("PM:NOT_PA_OR_NOT_CONFIGURED"); poolManager.setLiquidityCap(1000); } @@ -418,9 +418,23 @@ contract SetLiquidityCap_SetterTests is TestBase { assertEq(poolManager.liquidityCap(), 1000); } + function test_setLiquidityCap_success_asGovernor() external { + poolManager.__setConfigured(true); + + vm.prank(GOVERNOR); + poolManager.setLiquidityCap(1000); + } + + function test_setLiquidityCap_success_asOperationalAdmin() external { + poolManager.__setConfigured(true); + + vm.prank(MockGlobals(globals).operationalAdmin()); + poolManager.setLiquidityCap(1000); + } + } -contract SetDelegateManagementFeeRate_SetterTests is TestBase { +contract SetDelegateManagementFeeRate_SetterTests is PoolManagerTestBase { uint256 internal newManagementFeeRate = 10_0000; @@ -435,7 +449,7 @@ contract SetDelegateManagementFeeRate_SetterTests is TestBase { function test_setDelegateManagementFeeRate_notPoolDelegate() external { poolManager.__setConfigured(true); - vm.expectRevert("PM:NO_AUTH"); + vm.expectRevert("PM:NOT_PA_OR_NOT_CONFIGURED"); poolManager.setDelegateManagementFeeRate(newManagementFeeRate); } @@ -461,66 +475,105 @@ contract SetDelegateManagementFeeRate_SetterTests is TestBase { assertEq(poolManager.delegateManagementFeeRate(), newManagementFeeRate); } + function test_setDelegateManagementFeeRate_success_asGovernor() external { + poolManager.__setConfigured(true); + + vm.prank(GOVERNOR); + poolManager.setDelegateManagementFeeRate(newManagementFeeRate); + } + + function test_setDelegateManagementFeeRate_success_asOperationalAdmin() external { + poolManager.__setConfigured(true); + + vm.prank(MockGlobals(globals).operationalAdmin()); + poolManager.setDelegateManagementFeeRate(newManagementFeeRate); + } + } -contract SetIsLoanManager_SetterTests is TestBase { +contract SetIsStrategy_SetterTests is PoolManagerTestBase { - address loanManager1; - address loanManager2; + address strategy1; + address strategy2; function setUp() public override { super.setUp(); - loanManager1 = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); - loanManager2 = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); + strategy1 = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); + strategy2 = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); - poolManager.__setIsLoanManager(loanManager1, true); - poolManager.__setIsLoanManager(loanManager2, true); - poolManager.__pushToLoanManagerList(loanManager1); - poolManager.__pushToLoanManagerList(loanManager2); + poolManager.__setIsStrategy(strategy1, true); + poolManager.__setIsStrategy(strategy2, true); + poolManager.__pushToStrategyList(strategy1); + poolManager.__pushToStrategyList(strategy2); } - function test_setIsLoanManager_paused() external { + function test_setIsStrategy_paused() external { MockGlobals(globals).__setFunctionPaused(true); vm.expectRevert("PM:PAUSED"); - poolManager.setIsLoanManager(loanManager2, false); + poolManager.setIsStrategy(strategy2, false); } - function test_setIsLoanManager_notPoolDelegate() external { - vm.expectRevert("PM:NOT_PD"); - poolManager.setIsLoanManager(loanManager2, false); + function test_setIsStrategy_notPoolDelegate() external { + vm.expectRevert("PM:NOT_PD_OR_GOV_OR_OA"); + poolManager.setIsStrategy(strategy2, false); } - function test_setIsLoanManager_invalidLM() external { - address invalidLoanManager = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); + function test_setIsStrategy_invalidLM() external { + address invalidStrategy = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); vm.startPrank(POOL_DELEGATE); - vm.expectRevert("PM:SILM:INVALID_LM"); - poolManager.setIsLoanManager(invalidLoanManager, false); + vm.expectRevert("PM:SIS:INVALID_STRATEGY"); + poolManager.setIsStrategy(invalidStrategy, false); } - function test_setIsLoanManager_success() external { - assertTrue(poolManager.isLoanManager(loanManager2)); + function test_setIsStrategy_successWithPoolDelegate() external { + assertTrue(poolManager.isStrategy(strategy2)); vm.startPrank(POOL_DELEGATE); - poolManager.setIsLoanManager(loanManager2, false); + poolManager.setIsStrategy(strategy2, false); + + assertTrue(!poolManager.isStrategy(strategy2)); + + poolManager.setIsStrategy(strategy2, true); + + assertTrue(poolManager.isStrategy(strategy2)); + } + + function test_setIsStrategy_success_asGovernor() external { + assertTrue(poolManager.isStrategy(strategy2)); + + vm.startPrank(GOVERNOR); + poolManager.setIsStrategy(strategy2, false); + + assertTrue(!poolManager.isStrategy(strategy2)); + + poolManager.setIsStrategy(strategy2, true); + + assertTrue(poolManager.isStrategy(strategy2)); + } + + function test_setIsStrategy_success_asOperationalAdmin() external { + assertTrue(poolManager.isStrategy(strategy2)); - assertTrue(!poolManager.isLoanManager(loanManager2)); + vm.startPrank(OPERATIONAL_ADMIN); + poolManager.setIsStrategy(strategy2, false); - poolManager.setIsLoanManager(loanManager2, true); + assertTrue(!poolManager.isStrategy(strategy2)); - assertTrue(poolManager.isLoanManager(loanManager2)); + poolManager.setIsStrategy(strategy2, true); + + assertTrue(poolManager.isStrategy(strategy2)); } } -contract TriggerDefault is TestBase { +contract TriggerDefault is PoolManagerTestBase { - address internal AUCTIONEER = makeAddr("AUCTIONEER"); - address internal BORROWER = makeAddr("BORROWER"); - address internal LP = makeAddr("LP"); - address internal OPERATIONAL_ADMIN = makeAddr("OPERATIONAL_ADMIN"); + address internal AUCTIONEER = makeAddr("AUCTIONEER"); + address internal BORROWER = makeAddr("BORROWER"); + address internal LP = makeAddr("LP"); address internal loan; address internal poolDelegateCover; @@ -554,8 +607,8 @@ contract TriggerDefault is TestBase { loanFactory.__setIsLoan(loan, true); vm.startPrank(POOL_DELEGATE); - poolManager.__setIsLoanManager(address(loanManager), true); - poolManager.__pushToLoanManagerList(address(loanManager)); + poolManager.__setIsStrategy(address(loanManager), true); + poolManager.__pushToStrategyList(address(loanManager)); poolManager.setWithdrawalManager(withdrawalManager); vm.stopPrank(); } @@ -605,12 +658,11 @@ contract TriggerDefault is TestBase { } -contract FinishCollateralLiquidation is TestBase { +contract FinishCollateralLiquidation is PoolManagerTestBase { - address internal BORROWER = makeAddr("BORROWER"); - address internal LOAN = makeAddr("LOAN"); - address internal LP = makeAddr("LP"); - address internal OPERATIONAL_ADMIN = makeAddr("OPERATIONAL_ADMIN"); + address internal BORROWER = makeAddr("BORROWER"); + address internal LOAN = makeAddr("LOAN"); + address internal LP = makeAddr("LP"); address internal loan; address internal poolDelegateCover; @@ -647,8 +699,8 @@ contract FinishCollateralLiquidation is TestBase { loanFactory.__setIsLoan(loan, true); vm.startPrank(POOL_DELEGATE); - poolManager.__setIsLoanManager(address(loanManager), true); - poolManager.__pushToLoanManagerList(address(loanManager)); + poolManager.__setIsStrategy(address(loanManager), true); + poolManager.__pushToStrategyList(address(loanManager)); poolManager.setWithdrawalManager(withdrawalManager); vm.stopPrank(); } @@ -863,7 +915,7 @@ contract FinishCollateralLiquidation is TestBase { } -contract ProcessRedeemTests is TestBase { +contract ProcessRedeemTests is PoolManagerTestBase { function setUp() public override { super.setUp(); @@ -910,63 +962,91 @@ contract ProcessRedeemTests is TestBase { } -contract AddLoanManager_SetterTests is TestBase { +contract AddStrategy_SetterTests is PoolManagerTestBase { address loanManagerFactory; + bytes deploymentData; + function setUp() public override { super.setUp(); loanManagerFactory = address(new MockFactory()); - MockGlobals(globals).setValidInstance("LOAN_MANAGER_FACTORY", loanManagerFactory, true); + MockGlobals(globals).setValidInstance("STRATEGY_FACTORY", loanManagerFactory, true); + + deploymentData = abi.encode(address(poolManager)); } - function test_addLoanManager_paused() external { + function test_addStrategy_paused() external { MockGlobals(globals).__setFunctionPaused(true); vm.prank(POOL_DELEGATE); vm.expectRevert("PM:PAUSED"); - poolManager.addLoanManager(address(0)); + poolManager.addStrategy(address(0), deploymentData); } - function test_addLoanManager_notPoolDelegate() external { + function test_addStrategy_notPoolDelegate() external { poolManager.__setConfigured(true); - vm.expectRevert("PM:NO_AUTH"); - poolManager.addLoanManager(address(0)); + vm.expectRevert("PM:NOT_PA_OR_NOT_CONFIGURED"); + poolManager.addStrategy(address(0), deploymentData); } - function test_addLoanManager_invalidFactory() external { + function test_addStrategy_invalidFactory() external { vm.prank(POOL_DELEGATE); - vm.expectRevert("PM:ALM:INVALID_FACTORY"); - poolManager.addLoanManager(address(0)); + vm.expectRevert("PM:AS:INVALID_FACTORY"); + poolManager.addStrategy(address(0), deploymentData); } - function test_addLoanManager_success_whenNotConfigured() external { - address loanManager_ = poolManager.addLoanManager(loanManagerFactory); + function test_addStrategy_success_whenNotConfigured() external { + address strategy_ = poolManager.addStrategy(loanManagerFactory, deploymentData); - assertTrue(loanManager_ == poolManager.__getLoanManagerListValue(0)); - assertTrue(poolManager.__getLoanManagerListValue(0) != address(0)); + assertTrue(strategy_ == poolManager.__getStrategyListValue(0)); + assertTrue(poolManager.__getStrategyListValue(0) != address(0)); - assertEq(poolManager.loanManagerListLength(), 1); + assertEq(poolManager.strategyListLength(), 1); } - function test_addLoanManager_success_asPoolDelegate() external { + function test_addStrategy_success_asPoolDelegate() external { poolManager.__setConfigured(true); vm.startPrank(POOL_DELEGATE); - address loanManager_ = poolManager.addLoanManager(loanManagerFactory); + address strategy_ = poolManager.addStrategy(loanManagerFactory, deploymentData); + + assertTrue(strategy_ == poolManager.__getStrategyListValue(0)); + assertTrue(poolManager.__getStrategyListValue(0) != address(0)); + + assertEq(poolManager.strategyListLength(), 1); + } + + function test_addStrategy_success_asGovernor() external { + poolManager.__setConfigured(true); + + vm.startPrank(GOVERNOR); + address strategy_ = poolManager.addStrategy(loanManagerFactory, deploymentData); - assertTrue(loanManager_ == poolManager.__getLoanManagerListValue(0)); - assertTrue(poolManager.__getLoanManagerListValue(0) != address(0)); + assertTrue(strategy_ == poolManager.__getStrategyListValue(0)); + assertTrue(poolManager.__getStrategyListValue(0) != address(0)); - assertEq(poolManager.loanManagerListLength(), 1); + assertEq(poolManager.strategyListLength(), 1); + } + + function test_addStrategy_success_asOperationalAdmin() external { + poolManager.__setConfigured(true); + + vm.startPrank(OPERATIONAL_ADMIN); + address strategy_ = poolManager.addStrategy(loanManagerFactory, deploymentData); + + assertTrue(strategy_ == poolManager.__getStrategyListValue(0)); + assertTrue(poolManager.__getStrategyListValue(0) != address(0)); + + assertEq(poolManager.strategyListLength(), 1); } } -contract SetWithdrawalManager_SetterTests is TestBase { +contract SetWithdrawalManager_SetterTests is PoolManagerTestBase { function test_setWithdrawalManager_paused() external { MockGlobals(globals).__setFunctionPaused(true); @@ -1008,7 +1088,7 @@ contract SetWithdrawalManager_SetterTests is TestBase { } -contract CanCallTests is TestBase { +contract CanCallTests is PoolManagerTestBase { function test_canCall_deposit_notActive() external { bytes32 functionId_ = bytes32("P:deposit"); @@ -1434,7 +1514,7 @@ contract CanCallTests is TestBase { } -contract DepositCoverTests is TestBase { +contract DepositCoverTests is PoolManagerTestBase { function setUp() public override { super.setUp(); @@ -1479,7 +1559,7 @@ contract DepositCoverTests is TestBase { } -contract HandleCoverTests is TestBase { +contract HandleCoverTests is PoolManagerTestBase { address loanManager; @@ -1490,8 +1570,8 @@ contract HandleCoverTests is TestBase { loanManager = makeAddr("loanManager"); - poolManager.__setIsLoanManager(loanManager, true); - poolManager.__pushToLoanManagerList(loanManager); + poolManager.__setIsStrategy(loanManager, true); + poolManager.__pushToStrategyList(loanManager); } function test_handleCover_noCover() external { @@ -1571,7 +1651,7 @@ contract HandleCoverTests is TestBase { } -contract WithdrawCoverTests is TestBase { +contract WithdrawCoverTests is PoolManagerTestBase { function test_withdrawCover_paused() external { MockGlobals(globals).__setFunctionPaused(true); @@ -1654,7 +1734,7 @@ contract WithdrawCoverTests is TestBase { } -contract MaxDepositTests is TestBase { +contract MaxDepositTests is PoolManagerTestBase { function setUp() public override { super.setUp(); @@ -1729,7 +1809,7 @@ contract MaxDepositTests is TestBase { } -contract MaxMintTests is TestBase { +contract MaxMintTests is PoolManagerTestBase { function setUp() public override { super.setUp(); @@ -1872,7 +1952,7 @@ contract MaxMintTests is TestBase { } -contract MaxWithdrawTests is TestBase { +contract MaxWithdrawTests is PoolManagerTestBase { function test_maxWithdraw() external { uint256 assets_ = pool.maxWithdraw(address(this)); @@ -1888,25 +1968,25 @@ contract MaxWithdrawTests is TestBase { } -contract RequestFundsTests is TestBase { +contract RequestFundsTests is PoolManagerTestBase { - address loanManager; - address loanManagerFactory; + address strategy; + address strategyFactory; function setUp() public override { super.setUp(); - loanManager = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); - loanManagerFactory = address(new MockFactory()); + strategy = address(new MockLoanManager(address(pool), address(0), POOL_DELEGATE)); + strategyFactory = address(new MockFactory()); - MockGlobals(globals).setValidInstance("LOAN_MANAGER_FACTORY", loanManagerFactory, true); + MockGlobals(globals).setValidInstance("STRATEGY_FACTORY", strategyFactory, true); MockGlobals(globals).setValidInstance("WITHDRAWAL_MANAGER_FACTORY", address(withdrawalManagerFactory), true); - MockLoanManager(loanManager).__setFactory(loanManagerFactory); + MockLoanManager(strategy).__setFactory(strategyFactory); - poolManager.__setIsLoanManager(loanManager, true); + poolManager.__setIsStrategy(strategy, true); - MockFactory(loanManagerFactory).__setIsInstance(address(loanManager), true); + MockFactory(strategyFactory).__setIsInstance(address(strategy), true); vm.prank(POOL_DELEGATE); poolManager.setWithdrawalManager(withdrawalManager); @@ -1916,45 +1996,45 @@ contract RequestFundsTests is TestBase { MockGlobals(globals).__setFunctionPaused(true); vm.expectRevert("PM:PAUSED"); - poolManager.requestFunds(loanManager, 1); + poolManager.requestFunds(strategy, 1); } function test_requestFunds_zeroPrincipal() external { vm.expectRevert("PM:RF:INVALID_PRINCIPAL"); - vm.prank(loanManager); - poolManager.requestFunds(loanManager, 0); + vm.prank(strategy); + poolManager.requestFunds(strategy, 0); } function test_requestFunds_invalidFactory() external { - MockLoanManager(loanManager).__setFactory(address(0)); + MockLoanManager(strategy).__setFactory(address(0)); vm.expectRevert("PM:RF:INVALID_FACTORY"); - vm.prank(loanManager); - poolManager.requestFunds(loanManager, 1); + vm.prank(strategy); + poolManager.requestFunds(strategy, 1); } function test_requestFunds_invalidInstance() external { - MockFactory(loanManagerFactory).__setIsInstance(address(loanManager), false); + MockFactory(strategyFactory).__setIsInstance(address(strategy), false); vm.expectRevert("PM:RF:INVALID_INSTANCE"); - vm.prank(loanManager); - poolManager.requestFunds(address(loanManager), 1); + vm.prank(strategy); + poolManager.requestFunds(address(strategy), 1); } function test_requestFunds_notLM() external { - poolManager.__setIsLoanManager(loanManager, false); + poolManager.__setIsStrategy(strategy, false); - vm.expectRevert("PM:RF:NOT_LM"); - vm.prank(loanManager); - poolManager.requestFunds(loanManager, 1); + vm.expectRevert("PM:RF:NOT_STRATEGY"); + vm.prank(strategy); + poolManager.requestFunds(strategy, 1); } function test_requestFunds_zeroSupply() external { pool.burn(address(1), 1); vm.expectRevert("PM:RF:ZERO_SUPPLY"); - vm.prank(loanManager); - poolManager.requestFunds(loanManager, 1); + vm.prank(strategy); + poolManager.requestFunds(strategy, 1); } function test_requestFunds_insufficientCoverBoundary() external { @@ -1963,41 +2043,41 @@ contract RequestFundsTests is TestBase { asset.mint(poolManager.poolDelegateCover(), 1000e18 - 1); vm.expectRevert("PM:RF:INSUFFICIENT_COVER"); - vm.startPrank(loanManager); - poolManager.requestFunds(loanManager, 1); + vm.startPrank(strategy); + poolManager.requestFunds(strategy, 1); asset.mint(poolManager.poolDelegateCover(), 1); - poolManager.requestFunds(loanManager, 1); + poolManager.requestFunds(strategy, 1); } function test_requestFunds_lockedLiquidityBoundary() external { MockWithdrawalManager(withdrawalManager).__setLockedLiquidity(1_000_000e18); vm.expectRevert("PM:RF:LOCKED_LIQUIDITY"); - vm.startPrank(loanManager); - poolManager.requestFunds(loanManager, 1); + vm.startPrank(strategy); + poolManager.requestFunds(strategy, 1); asset.mint(poolManager.pool(), 1); - poolManager.requestFunds(loanManager, 1); + poolManager.requestFunds(strategy, 1); } function test_requestFunds_zeroAddress() external { vm.expectRevert("PM:RF:INVALID_DESTINATION"); - vm.prank(loanManager); + vm.prank(strategy); poolManager.requestFunds(address(0), 1000e18); } function test_requestFunds_success() external { assertEq(asset.balanceOf(address(pool)), 1_000_000e18); - assertEq(asset.balanceOf(loanManager), 0); + assertEq(asset.balanceOf(strategy), 0); - vm.prank(loanManager); - poolManager.requestFunds(loanManager, 1000e18); + vm.prank(strategy); + poolManager.requestFunds(strategy, 1000e18); assertEq(asset.balanceOf(address(pool)), 1_000_000e18 - 1000e18); - assertEq(asset.balanceOf(loanManager), 1000e18); + assertEq(asset.balanceOf(strategy), 1000e18); } } diff --git a/tests/MaplePoolManagerFactory.t.sol b/tests/MaplePoolManagerFactory.t.sol index 66daea7c..961184e1 100644 --- a/tests/MaplePoolManagerFactory.t.sol +++ b/tests/MaplePoolManagerFactory.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { MockERC20 } from "../modules/erc20/contracts/test/mocks/MockERC20.sol"; @@ -12,9 +12,9 @@ import { MaplePoolManager } from "../contracts/MaplePoolManager.sol"; import { MockGlobals } from "./mocks/Mocks.sol"; -import { GlobalsBootstrapper } from "./bootstrap/GlobalsBootstrapper.sol"; +import { TestBase } from "./utils/TestBase.sol"; -contract TestBase is Test, GlobalsBootstrapper { +contract PoolManagerFactoryTestBase is TestBase { address internal PD = makeAddr("PD"); @@ -30,8 +30,8 @@ contract TestBase is Test, GlobalsBootstrapper { factory = new MaplePoolManagerFactory(address(globals)); - implementation = address(new MaplePoolManager()); - initializer = address(new MaplePoolManagerInitializer()); + implementation = deploy("MaplePoolManager"); + initializer = deploy("MaplePoolManagerInitializer"); vm.startPrank(GOVERNOR); factory.registerImplementation(1, implementation, initializer); @@ -43,7 +43,7 @@ contract TestBase is Test, GlobalsBootstrapper { } -contract PoolManagerFactoryTest is TestBase { +contract PoolManagerFactoryTest is PoolManagerFactoryTestBase { function test_createInstance() external { address migrationAdmin = makeAddr("migrationAdmin"); @@ -86,7 +86,7 @@ contract PoolManagerFactoryTest is TestBase { } -contract PoolManagerFactoryFailureTest is TestBase { +contract PoolManagerFactoryFailureTest is PoolManagerFactoryTestBase { function test_createInstance_notPoolDeployer() external { bytes memory arguments = abi.encode(PD, address(asset), 0, "Pool", "P2"); diff --git a/tests/MaplePoolManagerMigrator.t.sol b/tests/MaplePoolManagerMigrator.t.sol index 664b15b2..36789c9b 100644 --- a/tests/MaplePoolManagerMigrator.t.sol +++ b/tests/MaplePoolManagerMigrator.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { MockERC20 } from "../modules/erc20/contracts/test/mocks/MockERC20.sol"; @@ -11,7 +11,9 @@ import { MaplePoolManagerMigrator } from "../contracts/proxy/MaplePoolManager import { MockGlobals, MockPoolPermissionManager } from "./mocks/Mocks.sol"; -contract MaplePoolManagerMigratorTests is Test { +import { TestBase } from "./utils/TestBase.sol"; + +contract MaplePoolManagerMigratorTests is TestBase { address governor; address poolDelegate; @@ -22,7 +24,7 @@ contract MaplePoolManagerMigratorTests is Test { address migrator; MockERC20 asset; - MockGlobals globals; + MockGlobals globals_; MockPoolPermissionManager ppm; MaplePoolManager poolManager; @@ -32,21 +34,21 @@ contract MaplePoolManagerMigratorTests is Test { governor = makeAddr("governor"); poolDelegate = makeAddr("poolDelegate"); - implementationV1 = address(new MaplePoolManager()); - implementationV2 = address(new MaplePoolManager()); - initializer = address(new MaplePoolManagerInitializer()); - migrator = address(new MaplePoolManagerMigrator()); + implementationV1 = deploy("MaplePoolManager"); + implementationV2 = deploy("MaplePoolManager"); + initializer = deploy("MaplePoolManagerInitializer"); + migrator = deploy("MaplePoolManagerMigrator"); - asset = new MockERC20("USD Coin", "USDC", 6); - globals = new MockGlobals(governor); - ppm = new MockPoolPermissionManager(); + asset = new MockERC20("USD Coin", "USDC", 6); + globals_ = new MockGlobals(governor); + ppm = new MockPoolPermissionManager(); - globals.setValidPoolDeployer(address(this), true); - globals.setValidPoolAsset(address(asset), true); - globals.setValidPoolDelegate(poolDelegate, true); - globals.__setIsValidScheduledCall(true); + globals_.setValidPoolDeployer(address(this), true); + globals_.setValidPoolAsset(address(asset), true); + globals_.setValidPoolDelegate(poolDelegate, true); + globals_.__setIsValidScheduledCall(true); - factory = new MaplePoolManagerFactory(address(globals)); + factory = new MaplePoolManagerFactory(address(globals_)); vm.startPrank(governor); factory.registerImplementation(100, implementationV1, initializer); @@ -62,7 +64,7 @@ contract MaplePoolManagerMigratorTests is Test { } function test_migrator_failure() external { - globals.setValidInstance("POOL_PERMISSION_MANAGER", address(ppm), false); + globals_.setValidInstance("POOL_PERMISSION_MANAGER", address(ppm), false); vm.prank(poolDelegate); vm.expectRevert("MPF:UI:FAILED"); @@ -70,7 +72,7 @@ contract MaplePoolManagerMigratorTests is Test { } function test_migrator_success() external { - globals.setValidInstance("POOL_PERMISSION_MANAGER", address(ppm), true); + globals_.setValidInstance("POOL_PERMISSION_MANAGER", address(ppm), true); assertEq(factory.versionOf(poolManager.implementation()), 100); diff --git a/tests/MaplePoolManagerQueueMigrator.t.sol b/tests/MaplePoolManagerQueueMigrator.t.sol deleted file mode 100644 index a0836513..00000000 --- a/tests/MaplePoolManagerQueueMigrator.t.sol +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; - -import { Test } from "../modules/forge-std/src/Test.sol"; -import { MockERC20 } from "../modules/erc20/contracts/test/mocks/MockERC20.sol"; - -import { MaplePoolManager } from "../contracts/MaplePoolManager.sol"; -import { MaplePoolManagerFactory } from "../contracts/proxy/MaplePoolManagerFactory.sol"; -import { MaplePoolManagerInitializer } from "../contracts/proxy/MaplePoolManagerInitializer.sol"; -import { MaplePoolManagerWMMigrator } from "../contracts/proxy/MaplePoolManagerWMMigrator.sol"; - -import { MockFactory, MockGlobals, MockWithdrawalManager } from "./mocks/Mocks.sol"; - -contract MaplePoolManagerWMMigratorTests is Test { - - address governor; - address poolDelegate; - - address implementationV1; - address implementationV2; - address initializer; - address migrator; - - MockERC20 asset; - MockFactory withdrawalManagerfactory; - MockGlobals globals; - MockWithdrawalManager withdrawalManager; - - MaplePoolManager poolManager; - MaplePoolManagerFactory factory; - - function setUp() public virtual { - governor = makeAddr("governor"); - poolDelegate = makeAddr("poolDelegate"); - - implementationV1 = address(new MaplePoolManager()); - implementationV2 = address(new MaplePoolManager()); - initializer = address(new MaplePoolManagerInitializer()); - migrator = address(new MaplePoolManagerWMMigrator()); - - asset = new MockERC20("USD Coin", "USDC", 6); - globals = new MockGlobals(governor); - withdrawalManager = new MockWithdrawalManager(); - withdrawalManagerfactory = new MockFactory(); - - globals.setValidPoolDeployer(address(this), true); - globals.setValidPoolAsset(address(asset), true); - globals.setValidPoolDelegate(poolDelegate, true); - globals.__setIsValidScheduledCall(true); - - withdrawalManager.__setFactory(address(withdrawalManagerfactory)); - - factory = new MaplePoolManagerFactory(address(globals)); - - vm.startPrank(governor); - factory.registerImplementation(200, implementationV1, initializer); - factory.registerImplementation(300, implementationV2, initializer); - factory.enableUpgradePath(200, 300, migrator); - factory.setDefaultVersion(200); - vm.stopPrank(); - - poolManager = MaplePoolManager(MaplePoolManagerFactory(factory).createInstance( - abi.encode(poolDelegate, address(asset), 0, "Maple Pool", "MP"), - "salt" - )); - } - - function test_migrator_invalidPoolManager() external { - globals.setValidInstance("QUEUE_POOL_MANAGER", address(poolManager), false); - - vm.prank(poolDelegate); - vm.expectRevert("MPF:UI:FAILED"); - poolManager.upgrade(300, abi.encode(address(withdrawalManager))); - } - - function test_migrator_invalidFactory() external { - globals.setValidInstance("QUEUE_POOL_MANAGER", address(poolManager), true); - globals.setValidInstance("WITHDRAWAL_MANAGER_QUEUE_FACTORY", address(withdrawalManagerfactory), false); - - vm.prank(poolDelegate); - vm.expectRevert("MPF:UI:FAILED"); - poolManager.upgrade(300, abi.encode(address(withdrawalManager))); - } - - function test_migrator_invalidInstance() external { - globals.setValidInstance("QUEUE_POOL_MANAGER", address(poolManager), true); - globals.setValidInstance("WITHDRAWAL_MANAGER_QUEUE_FACTORY", address(withdrawalManagerfactory), true); - - withdrawalManagerfactory.__setIsInstance(address(withdrawalManager), false); - - vm.prank(poolDelegate); - vm.expectRevert("MPF:UI:FAILED"); - poolManager.upgrade(300, abi.encode(address(withdrawalManager))); - } - - function test_migrator_success() external { - globals.setValidInstance("QUEUE_POOL_MANAGER", address(poolManager), true); - globals.setValidInstance("WITHDRAWAL_MANAGER_QUEUE_FACTORY", address(withdrawalManagerfactory), true); - - withdrawalManagerfactory.__setIsInstance(address(withdrawalManager), true); - - assertEq(factory.versionOf(poolManager.implementation()), 200); - - assertEq(poolManager.withdrawalManager(), address(0)); - - vm.prank(poolDelegate); - poolManager.upgrade(300, abi.encode(address(withdrawalManager))); - - assertEq(factory.versionOf(poolManager.implementation()), 300); - - assertEq(poolManager.withdrawalManager(), address(withdrawalManager)); - } - -} diff --git a/tests/MaplePoolMintFrontrunTests.t.sol b/tests/MaplePoolMintFrontrunTests.t.sol index 71f2b2ec..882ecf1c 100644 --- a/tests/MaplePoolMintFrontrunTests.t.sol +++ b/tests/MaplePoolMintFrontrunTests.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../modules/forge-std/src/Test.sol"; import { stdError } from "../modules/forge-std/src/StdError.sol"; @@ -13,9 +13,9 @@ import { MaplePoolManagerInitializer } from "../contracts/proxy/MaplePoolManager import { MockGlobals, MockPoolManager, MockWithdrawalManager } from "./mocks/Mocks.sol"; -import { GlobalsBootstrapper } from "./bootstrap/GlobalsBootstrapper.sol"; +import { TestBase } from "./utils/TestBase.sol"; -contract MaplePoolMintFrontrunTests is Test, GlobalsBootstrapper { +contract MaplePoolMintFrontrunTests is TestBase { address POOL_DELEGATE = makeAddr("POOL_DELEGATE"); address USER1 = makeAddr("USER1"); @@ -37,8 +37,8 @@ contract MaplePoolMintFrontrunTests is Test, GlobalsBootstrapper { factory = new MaplePoolManagerFactory(globals); - implementation = address(new MaplePoolManager()); - initializer = address(new MaplePoolManagerInitializer()); + implementation = deploy("MaplePoolManager"); + initializer = deploy("MaplePoolManagerInitializer"); vm.startPrank(GOVERNOR); factory.registerImplementation(1, implementation, initializer); diff --git a/tests/harnesses/MaplePoolManagerHarness.sol b/tests/harnesses/MaplePoolManagerHarness.sol index 43b58181..523ec0b5 100644 --- a/tests/harnesses/MaplePoolManagerHarness.sol +++ b/tests/harnesses/MaplePoolManagerHarness.sol @@ -9,24 +9,24 @@ contract MaplePoolManagerHarness is MaplePoolManager { _handleCover(losses_, platformFees_); } - function __setIsLoanManager(address loanManager_, bool isLoanManager_) external { - isLoanManager[loanManager_] = isLoanManager_; + function __setIsStrategy(address strategy_, bool isStrategy_) external { + isStrategy[strategy_] = isStrategy_; } function __setPoolPermissionManager(address poolPermissionManager_) external { poolPermissionManager = poolPermissionManager_; } - function __pushToLoanManagerList(address loanManager_) external { - loanManagerList.push(loanManager_); + function __pushToStrategyList(address strategy_) external { + strategyList.push(strategy_); } function __setConfigured(bool configured_) external { configured = configured_; } - function __getLoanManagerListValue(uint256 index_) external view returns (address value_) { - value_ = index_ < loanManagerList.length ? loanManagerList[index_] : address(0); + function __getStrategyListValue(uint256 index_) external view returns (address value_) { + value_ = index_ < strategyList.length ? strategyList[index_] : address(0); } } diff --git a/tests/mocks/Mocks.sol b/tests/mocks/Mocks.sol index b2d6998d..b873521d 100644 --- a/tests/mocks/Mocks.sol +++ b/tests/mocks/Mocks.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { MapleProxiedInternals } from "../../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol"; import { MockERC20 } from "../../modules/erc20/contracts/test/mocks/MockERC20.sol"; @@ -339,7 +339,7 @@ contract MockPoolManager is MockProxied, MaplePoolManagerStorage { mapping(address => uint256) public maxRedeem; mapping(address => uint256) public maxWithdraw; - function addLoanManager(address loanManagerFactory_) external view returns (address loanManager_) {} + function addStrategy(address strategyFactory_, bytes calldata deploymentData_) external view returns (address strategy_) {} function canCall(bytes32, address, bytes memory) external view returns (bool canCall_, string memory errorMessage_) { canCall_ = _canCall; diff --git a/tests/utils/CompilerResolver.sol b/tests/utils/CompilerResolver.sol new file mode 100644 index 00000000..2204b50d --- /dev/null +++ b/tests/utils/CompilerResolver.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.7; + +import { MockPoolManager } from "../mocks/Mocks.sol"; diff --git a/tests/bootstrap/GlobalsBootstrapper.sol b/tests/utils/GlobalsBootstrapper.sol similarity index 76% rename from tests/bootstrap/GlobalsBootstrapper.sol rename to tests/utils/GlobalsBootstrapper.sol index 41c47207..44d7042b 100644 --- a/tests/bootstrap/GlobalsBootstrapper.sol +++ b/tests/utils/GlobalsBootstrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.7; +pragma solidity ^0.8.7; import { Test } from "../../modules/forge-std/src/Test.sol"; import { MockGlobals } from "../mocks/Mocks.sol"; @@ -9,8 +9,9 @@ import { MockGlobals } from "../mocks/Mocks.sol"; */ contract GlobalsBootstrapper is Test { - address internal GOVERNOR = makeAddr("GOVERNOR"); - address internal TREASURY = makeAddr("TREASURY"); + address internal GOVERNOR = makeAddr("GOVERNOR"); + address internal OPERATIONAL_ADMIN = makeAddr("OPERATIONAL_ADMIN"); + address internal TREASURY = makeAddr("TREASURY"); address internal globals; @@ -19,6 +20,7 @@ contract GlobalsBootstrapper is Test { MockGlobals(globals).setValidPoolAsset(address(liquidityAsset_), true); MockGlobals(globals).setValidPoolDelegate(poolDelegate_, true); MockGlobals(globals).setMapleTreasury(TREASURY); + MockGlobals(globals).__setOperationalAdmin(OPERATIONAL_ADMIN); vm.stopPrank(); } diff --git a/tests/utils/TestBase.sol b/tests/utils/TestBase.sol new file mode 100644 index 00000000..1123e1cd --- /dev/null +++ b/tests/utils/TestBase.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.7; + +import { Test } from "../../modules/forge-std/src/Test.sol"; +import { GlobalsBootstrapper } from "./GlobalsBootstrapper.sol"; + +contract TestBase is Test, GlobalsBootstrapper { + + function deploy(string memory contractName) internal returns (address contract_) { + contract_ = deployCode(string(abi.encodePacked("./out/", contractName, ".sol/", contractName, ".json"))); + } + +} +