diff --git a/contracts/test/MiladyPoolOrderManager.t.sol b/contracts/test/MiladyPoolOrderManager.t.sol index 85daac1..a507826 100644 --- a/contracts/test/MiladyPoolOrderManager.t.sol +++ b/contracts/test/MiladyPoolOrderManager.t.sol @@ -6,9 +6,10 @@ import "forge-std/Script.sol"; import "forge-std/StdJson.sol"; import "forge-std/console.sol"; import "forge-std/console2.sol"; +import {Vm} from "forge-std/Vm.sol"; // Uniswap V4 Core -import {IHooks} from "v4-core/interfaces/IHooks.sol"; + import {Hooks} from "v4-core/libraries/Hooks.sol"; import {TickMath} from "v4-core/libraries/TickMath.sol"; import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol"; @@ -22,77 +23,35 @@ import {IERC20Minimal} from "v4-core/interfaces/external/IERC20Minimal.sol"; // Permit2 import {ISignatureTransfer} from "permit2/src/interfaces/ISignatureTransfer.sol"; +import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; +import {ECDSA} from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; // MiladyPool import {MiladyPoolOrderManager} from "../src/MiladyPoolOrderManager.sol"; import {PublicValuesStruct} from "../src/base/Structs.sol"; -import {HookMiner} from "../script/utils/HookMiner.sol"; -import {Utils} from "../script/utils/Utils.sol"; import {IMiladyPoolOrderManager} from "../src/interfaces/IMiladyPoolOrderManager.sol"; -import {MiladyPoolServiceManager, IServiceManager} from "../src/MiladyPoolServiceManager.sol"; - -// For Eigenlyer -import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -import "@eigenlayer/contracts/permissions/PauserRegistry.sol"; -import {IDelegationManager} from "@eigenlayer/contracts/interfaces/IDelegationManager.sol"; -import {IAVSDirectory} from "@eigenlayer/contracts/interfaces/IAVSDirectory.sol"; -import {IStrategyManager, IStrategy} from "@eigenlayer/contracts/interfaces/IStrategyManager.sol"; -import {ISlasher} from "@eigenlayer/contracts/interfaces/ISlasher.sol"; -import {StrategyBaseTVLLimits} from "@eigenlayer/contracts/strategies/StrategyBaseTVLLimits.sol"; -import "@eigenlayer/test/mocks/EmptyContract.sol"; - -import "@eigenlayer-middleware/src/RegistryCoordinator.sol" as regCoord; -import {IBLSApkRegistry, IIndexRegistry, IStakeRegistry} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; -import {BLSApkRegistry} from "@eigenlayer-middleware/src/BLSApkRegistry.sol"; -import {IndexRegistry} from "@eigenlayer-middleware/src/IndexRegistry.sol"; -import {StakeRegistry} from "@eigenlayer-middleware/src/StakeRegistry.sol"; -import "@eigenlayer-middleware/src/OperatorStateRetriever.sol"; -import "../src/ERC20Mock.sol"; - -contract MiladyPoolOrderManagerTest is Test, Deployers, Utils { + +import {MiladyPoolDeployer} from "./utils/MiladyPoolDeployer.sol"; + +contract MiladyPoolOrderManagerTest is MiladyPoolDeployer, Deployers { using PoolIdLibrary for PoolKey; using CurrencyLibrary for Currency; ISignatureTransfer PERMIT2; - IPoolManager POOL_MANAGER; Currency token0; Currency token1; address constant CREATE2_DEPLOYER = address(0x4e59b44847b379578588920cA78FbF26c0B4956C); - ERC20Mock public erc20Mock; - StrategyBaseTVLLimits public erc20MockStrategy; - - ProxyAdmin public miladyPoolProxyAdmin; - PauserRegistry public miladyPoolPauserReg; - - regCoord.RegistryCoordinator public registryCoordinator; - regCoord.IRegistryCoordinator public registryCoordinatorImplementation; - - IBLSApkRegistry public blsApkRegistry; - IBLSApkRegistry public blsApkRegistryImplementation; - - IIndexRegistry public indexRegistry; - IIndexRegistry public indexRegistryImplementation; - - IStakeRegistry public stakeRegistry; - IStakeRegistry public stakeRegistryImplementation; - - OperatorStateRetriever public operatorStateRetriever; + bytes32 public constant TOKEN_PERMISSIONS_TYPEHASH = + keccak256("TokenPermissions(address token,uint256 amount)"); - MiladyPoolServiceManager public miladyPoolServiceManager; - IServiceManager public miladyPoolServiceManagerImplementation; - - MiladyPoolOrderManager public miladyPoolOrderManager; - IMiladyPoolOrderManager public miladyPoolOrderManagerImplementation; - IHooks public hooksUseable; - - address miladyPoolCommunityMultisig = - 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; - address miladyPoolPauser = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + bytes32 public constant PERMIT_TRANSFER_FROM_TYPEHASH = + keccak256( + "PermitTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)" + ); function setUp() public { // Permit2 Setup @@ -106,62 +65,19 @@ contract MiladyPoolOrderManagerTest is Test, Deployers, Utils { POOL_MANAGER = manager; + _setUpMiladyPool(); + // Mock Tokens Setup (token0, token1) = deployMintAndApprove2Currencies(); - vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); - - string memory eigenlayerDeployedContracts = readOutput( - "eigenlayer_deployment_output" - ); - IStrategyManager strategyManager = IStrategyManager( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.strategyManager" - ) - ); - IDelegationManager delegationManager = IDelegationManager( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.delegation" - ) - ); - IAVSDirectory avsDirectory = IAVSDirectory( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.avsDirectory" - ) - ); - ProxyAdmin eigenLayerProxyAdmin = ProxyAdmin( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.eigenLayerProxyAdmin" - ) - ); - PauserRegistry eigenLayerPauserReg = PauserRegistry( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.eigenLayerPauserReg" - ) - ); - StrategyBaseTVLLimits baseStrategyImplementation = StrategyBaseTVLLimits( - stdJson.readAddress( - eigenlayerDeployedContracts, - ".addresses.baseStrategyImplementation" - ) - ); - - _deployErc20AndStrategyAndWhitelistStrategy( - eigenLayerProxyAdmin, - eigenLayerPauserReg, - baseStrategyImplementation, - strategyManager + IERC20Minimal(Currency.unwrap(key.currency0)).approve( + address(hooksUseable), + 1000 ether ); - _deployMiladyPoolContracts( - delegationManager, - avsDirectory, - erc20MockStrategy + IERC20Minimal(Currency.unwrap(key.currency1)).approve( + address(hooksUseable), + 1000 ether ); (key, ) = initPool( @@ -173,18 +89,6 @@ contract MiladyPoolOrderManagerTest is Test, Deployers, Utils { ZERO_BYTES ); - vm.stopPrank(); - - IERC20Minimal(Currency.unwrap(key.currency0)).approve( - address(hooksUseable), - 1000 ether - ); - - IERC20Minimal(Currency.unwrap(key.currency1)).approve( - address(hooksUseable), - 1000 ether - ); - modifyLiquidityRouter.modifyLiquidity( key, IPoolManager.ModifyLiquidityParams({ @@ -218,33 +122,12 @@ contract MiladyPoolOrderManagerTest is Test, Deployers, Utils { ); } - /** - 1. Get permit2 signature for the trade you want to do - 2. Take the permit2 details and create an order - 3. Take the order and create a hash - 4. Sign the hash and store it somewhere - 5. Call swap with the order details, hash, etc. - 6. See how it goes down! - */ - - function _getTransferDetails( - address to, - uint256 amount - ) - private - pure - returns (ISignatureTransfer.SignatureTransferDetails memory) - { - return - ISignatureTransfer.SignatureTransferDetails({ - to: to, - requestedAmount: amount - }); - } - function test__createOffchainOrderDetails() public { address trader = address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); uint256 totalAmount = type(uint256).max; + + vm.startPrank(trader); + // Approve tokens for PERMIT2 IERC20Minimal(Currency.unwrap(token0)).approve( address(PERMIT2), totalAmount @@ -254,269 +137,97 @@ contract MiladyPoolOrderManagerTest is Test, Deployers, Utils { address(PERMIT2), totalAmount ); - } - function _deployErc20AndStrategyAndWhitelistStrategy( - ProxyAdmin eigenLayerProxyAdmin, - PauserRegistry eigenLayerPauserReg, - StrategyBaseTVLLimits baseStrategyImplementation, - IStrategyManager strategyManager - ) internal { - erc20Mock = new ERC20Mock(); - - erc20MockStrategy = StrategyBaseTVLLimits( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector( - StrategyBaseTVLLimits.initialize.selector, - 1 ether, // maxPerDeposit - 100 ether, // maxDeposits - IERC20(erc20Mock), - eigenLayerPauserReg - ) - ) - ) - ); - IStrategy[] memory strats = new IStrategy[](1); - strats[0] = erc20MockStrategy; - bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); - thirdPartyTransfersForbiddenValues[0] = false; - strategyManager.addStrategiesToDepositWhitelist( - strats, - thirdPartyTransfersForbiddenValues - ); - } + // Swap amount: 100 * 10e18 tokens + uint256 swapAmount = 100 * 10 ** 18; - function _deployMiladyPoolContracts( - IDelegationManager delegationManager, - IAVSDirectory avsDirectory, - IStrategy strat - ) internal { - IStrategy[1] memory deployedStrategyArray = [strat]; - uint numStrategies = deployedStrategyArray.length; - miladyPoolProxyAdmin = new ProxyAdmin(); - - { - address[] memory pausers = new address[](2); - pausers[0] = miladyPoolPauser; - pausers[1] = miladyPoolCommunityMultisig; - miladyPoolPauserReg = new PauserRegistry( - pausers, - miladyPoolCommunityMultisig + ISignatureTransfer.TokenPermissions + memory permittedToken0 = _getTokenPermissions( + Currency.unwrap(token0), + swapAmount ); - } - - EmptyContract emptyContract = new EmptyContract(); - - miladyPoolServiceManager = MiladyPoolServiceManager( - address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(miladyPoolProxyAdmin), - "" - ) - ) - ); - - miladyPoolOrderManager = MiladyPoolOrderManager( - address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(miladyPoolProxyAdmin), - "" - ) - ) - ); - - registryCoordinator = regCoord.RegistryCoordinator( - address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(miladyPoolProxyAdmin), - "" - ) - ) - ); - - blsApkRegistry = IBLSApkRegistry( - address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(miladyPoolProxyAdmin), - "" - ) - ) - ); - - indexRegistry = IIndexRegistry( - address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(miladyPoolProxyAdmin), - "" - ) - ) - ); - - stakeRegistry = IStakeRegistry( - address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(miladyPoolProxyAdmin), - "" - ) - ) - ); - - operatorStateRetriever = new OperatorStateRetriever(); - - // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - { - stakeRegistryImplementation = new StakeRegistry( - registryCoordinator, - delegationManager - ); - - miladyPoolProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(stakeRegistry))), - address(stakeRegistryImplementation) - ); - - blsApkRegistryImplementation = new BLSApkRegistry( - registryCoordinator - ); - - miladyPoolProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(blsApkRegistry))), - address(blsApkRegistryImplementation) + ISignatureTransfer.PermitTransferFrom + memory permit = _getPermitTransferFrom( + permittedToken0, + 0, + block.timestamp + 1 days ); + bytes32 msgHash = _getPermitTransferMsgHash( + permit, + PERMIT2.DOMAIN_SEPARATOR() + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + // Need to pass in a pk (generic one from Anvil / Foundry) + 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80, + msgHash + ); + + PublicValuesStruct memory order = PublicValuesStruct({ + walletAddress: trader, + permit2Signature: abi.encode(v, r, s), + permit2Nonce: 0, + permit2Deadline: block.timestamp + 1 days + }); + } - indexRegistryImplementation = new IndexRegistry( - registryCoordinator - ); + function _getTransferDetails( + address to, + uint256 amount + ) + private + pure + returns (ISignatureTransfer.SignatureTransferDetails memory) + { + return + ISignatureTransfer.SignatureTransferDetails({ + to: to, + requestedAmount: amount + }); + } - miladyPoolProxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(indexRegistry))), - address(indexRegistryImplementation) - ); - } + function _getTokenPermissions( + address token, + uint256 amount + ) internal returns (ISignatureTransfer.TokenPermissions memory) { + return + ISignatureTransfer.TokenPermissions({token: token, amount: amount}); + } - registryCoordinatorImplementation = new regCoord.RegistryCoordinator( - miladyPoolServiceManager, - regCoord.IStakeRegistry(address(stakeRegistry)), - regCoord.IBLSApkRegistry(address(blsApkRegistry)), - regCoord.IIndexRegistry(address(indexRegistry)) - ); + function _getPermitTransferFrom( + ISignatureTransfer.TokenPermissions memory permitted, + uint256 nonce, + uint256 deadline + ) internal returns (ISignatureTransfer.PermitTransferFrom memory) { + return + ISignatureTransfer.PermitTransferFrom({ + permitted: permitted, + nonce: nonce, + deadline: deadline + }); + } - { - // For each quorum to setup, we need to define - // QuorumOperatorSetParam, minimumStakeForQuorum, and strategyParams - uint numQuorums = 1; - - regCoord.IRegistryCoordinator.OperatorSetParam[] - memory quorumsOperatorSetParams = new regCoord.IRegistryCoordinator.OperatorSetParam[]( - numQuorums - ); - - for (uint i = 0; i < numQuorums; i++) { - quorumsOperatorSetParams[i] = regCoord - .IRegistryCoordinator - .OperatorSetParam({ - maxOperatorCount: 10000, - kickBIPsOfOperatorStake: 15000, - kickBIPsOfTotalStake: 100 - }); - } - - uint96[] memory quorumsMinimumStake = new uint96[](numQuorums); - IStakeRegistry.StrategyParams[][] - memory quorumsStrategyParams = new IStakeRegistry.StrategyParams[][]( - numQuorums - ); - - for (uint i = 0; i < numQuorums; i++) { - quorumsStrategyParams[i] = new IStakeRegistry.StrategyParams[]( - numStrategies - ); - for (uint j = 0; j < numStrategies; j++) { - quorumsStrategyParams[i][j] = IStakeRegistry - .StrategyParams({ - strategy: deployedStrategyArray[j], - // setting this to 1 ether since the divisor is also 1 ether - // therefore this allows an operator to register with even just 1 token - // see https://github.com/Layr-Labs/eigenlayer-middleware/blob/m2-mainnet/src/StakeRegistry.sol#L484 - // weight += uint96(sharesAmount * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); - multiplier: 1 ether - }); - } - } - miladyPoolProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy( - payable(address(registryCoordinator)) - ), - address(registryCoordinatorImplementation), - abi.encodeWithSelector( - regCoord.RegistryCoordinator.initialize.selector, - // we set churnApprover and ejector to communityMultisig because we don't need them - miladyPoolCommunityMultisig, - miladyPoolCommunityMultisig, - miladyPoolCommunityMultisig, - miladyPoolPauserReg, - 0, // 0 initialPausedStatus means everything unpaused - quorumsOperatorSetParams, - quorumsMinimumStake, - quorumsStrategyParams + function _getPermitTransferMsgHash( + ISignatureTransfer.PermitTransferFrom memory permit, + bytes32 domainSeparator + ) internal view returns (bytes32 msgHash) { + bytes32 tokenPermissions = keccak256( + abi.encode(TOKEN_PERMISSIONS_TYPEHASH, permit.permitted) + ); + + msgHash = keccak256( + abi.encodePacked( + "\x19\x01", + domainSeparator, + keccak256( + abi.encode( + PERMIT_TRANSFER_FROM_TYPEHASH, + tokenPermissions, + address(this), + permit.nonce, + permit.deadline + ) ) - ); - } - - miladyPoolServiceManagerImplementation = new MiladyPoolServiceManager( - avsDirectory, - registryCoordinator, - stakeRegistry, - miladyPoolOrderManager - ); - - miladyPoolProxyAdmin.upgrade( - TransparentUpgradeableProxy( - payable(address(miladyPoolServiceManager)) - ), - address(miladyPoolServiceManagerImplementation) - ); - - uint160 flags = uint160( - Hooks.AFTER_INITIALIZE_FLAG | - Hooks.BEFORE_SWAP_FLAG | - Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG | - Hooks.AFTER_SWAP_FLAG - ); - - // NOTE: Hook miner has to use vm.prank's address instead of - // CREATE2_DEPLOYER address because of how Foundry works - (address hookAddress, bytes32 salt) = HookMiner.find( - address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266), - flags, - type(MiladyPoolOrderManager).creationCode, - abi.encode(registryCoordinator, POOL_MANAGER) - ); - - miladyPoolOrderManagerImplementation = new MiladyPoolOrderManager{ - salt: salt - }(registryCoordinator, POOL_MANAGER); - - miladyPoolProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy( - payable(address(miladyPoolOrderManager)) - ), - address(miladyPoolOrderManagerImplementation), - abi.encodeWithSelector( - miladyPoolOrderManager.initialize.selector, - miladyPoolPauserReg, - miladyPoolCommunityMultisig ) ); - hooksUseable = IHooks(hookAddress); } } diff --git a/contracts/test/utils/MiladyPoolDeployer.sol b/contracts/test/utils/MiladyPoolDeployer.sol new file mode 100644 index 0000000..1d6ad3a --- /dev/null +++ b/contracts/test/utils/MiladyPoolDeployer.sol @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: VPL-1.0 +pragma solidity ^0.8.26; + +import "forge-std/Test.sol"; + +// For Eigenlyer +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@eigenlayer/contracts/permissions/PauserRegistry.sol"; +import {IDelegationManager} from "@eigenlayer/contracts/interfaces/IDelegationManager.sol"; +import {IAVSDirectory} from "@eigenlayer/contracts/interfaces/IAVSDirectory.sol"; +import {IStrategyManager, IStrategy} from "@eigenlayer/contracts/interfaces/IStrategyManager.sol"; +import {ISlasher} from "@eigenlayer/contracts/interfaces/ISlasher.sol"; +import {StrategyBaseTVLLimits} from "@eigenlayer/contracts/strategies/StrategyBaseTVLLimits.sol"; +import "@eigenlayer/test/mocks/EmptyContract.sol"; +import "@eigenlayer-middleware/src/RegistryCoordinator.sol" as regCoord; +import {IBLSApkRegistry, IIndexRegistry, IStakeRegistry} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; +import {BLSApkRegistry} from "@eigenlayer-middleware/src/BLSApkRegistry.sol"; +import {IndexRegistry} from "@eigenlayer-middleware/src/IndexRegistry.sol"; +import {StakeRegistry} from "@eigenlayer-middleware/src/StakeRegistry.sol"; +import "@eigenlayer-middleware/src/OperatorStateRetriever.sol"; +import "../../src/ERC20Mock.sol"; + +// Milady Pool +import {MiladyPoolServiceManager, IServiceManager} from "../../src/MiladyPoolServiceManager.sol"; +import {MiladyPoolOrderManager} from "../../src/MiladyPoolOrderManager.sol"; +import {IMiladyPoolOrderManager} from "../../src/interfaces/IMiladyPoolOrderManager.sol"; + +// Uniswap V4 +import {Hooks} from "v4-core/libraries/Hooks.sol"; +import {IHooks} from "v4-core/interfaces/IHooks.sol"; +import {HookMiner} from "../../script/utils/HookMiner.sol"; +import {Utils} from "../../script/utils/Utils.sol"; +import {PoolKey} from "v4-core/types/PoolKey.sol"; +import {PoolId, PoolIdLibrary} from "v4-core/types/PoolId.sol"; +import {IPoolManager} from "v4-core/interfaces/IPoolManager.sol"; + +contract MiladyPoolDeployer is Test, Utils { + using PoolIdLibrary for PoolKey; + IPoolManager POOL_MANAGER; + ERC20Mock public erc20Mock; + StrategyBaseTVLLimits public erc20MockStrategy; + + ProxyAdmin public miladyPoolProxyAdmin; + PauserRegistry public miladyPoolPauserReg; + + regCoord.RegistryCoordinator public registryCoordinator; + regCoord.IRegistryCoordinator public registryCoordinatorImplementation; + + IBLSApkRegistry public blsApkRegistry; + IBLSApkRegistry public blsApkRegistryImplementation; + + IIndexRegistry public indexRegistry; + IIndexRegistry public indexRegistryImplementation; + + IStakeRegistry public stakeRegistry; + IStakeRegistry public stakeRegistryImplementation; + + OperatorStateRetriever public operatorStateRetriever; + + MiladyPoolServiceManager public miladyPoolServiceManager; + IServiceManager public miladyPoolServiceManagerImplementation; + + MiladyPoolOrderManager public miladyPoolOrderManager; + IMiladyPoolOrderManager public miladyPoolOrderManagerImplementation; + + IHooks public hooksUseable; + + address miladyPoolCommunityMultisig = + 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + address miladyPoolPauser = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + + function _setUpMiladyPool() internal { + vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + + string memory eigenlayerDeployedContracts = readOutput( + "eigenlayer_deployment_output" + ); + IStrategyManager strategyManager = IStrategyManager( + stdJson.readAddress( + eigenlayerDeployedContracts, + ".addresses.strategyManager" + ) + ); + IDelegationManager delegationManager = IDelegationManager( + stdJson.readAddress( + eigenlayerDeployedContracts, + ".addresses.delegation" + ) + ); + IAVSDirectory avsDirectory = IAVSDirectory( + stdJson.readAddress( + eigenlayerDeployedContracts, + ".addresses.avsDirectory" + ) + ); + ProxyAdmin eigenLayerProxyAdmin = ProxyAdmin( + stdJson.readAddress( + eigenlayerDeployedContracts, + ".addresses.eigenLayerProxyAdmin" + ) + ); + PauserRegistry eigenLayerPauserReg = PauserRegistry( + stdJson.readAddress( + eigenlayerDeployedContracts, + ".addresses.eigenLayerPauserReg" + ) + ); + StrategyBaseTVLLimits baseStrategyImplementation = StrategyBaseTVLLimits( + stdJson.readAddress( + eigenlayerDeployedContracts, + ".addresses.baseStrategyImplementation" + ) + ); + + _deployErc20AndStrategyAndWhitelistStrategy( + eigenLayerProxyAdmin, + eigenLayerPauserReg, + baseStrategyImplementation, + strategyManager + ); + + _deployMiladyPoolContracts( + delegationManager, + avsDirectory, + erc20MockStrategy + ); + + vm.stopPrank(); + } + + function _deployErc20AndStrategyAndWhitelistStrategy( + ProxyAdmin eigenLayerProxyAdmin, + PauserRegistry eigenLayerPauserReg, + StrategyBaseTVLLimits baseStrategyImplementation, + IStrategyManager strategyManager + ) internal { + erc20Mock = new ERC20Mock(); + + erc20MockStrategy = StrategyBaseTVLLimits( + address( + new TransparentUpgradeableProxy( + address(baseStrategyImplementation), + address(eigenLayerProxyAdmin), + abi.encodeWithSelector( + StrategyBaseTVLLimits.initialize.selector, + 1 ether, // maxPerDeposit + 100 ether, // maxDeposits + IERC20(erc20Mock), + eigenLayerPauserReg + ) + ) + ) + ); + IStrategy[] memory strats = new IStrategy[](1); + strats[0] = erc20MockStrategy; + bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); + thirdPartyTransfersForbiddenValues[0] = false; + strategyManager.addStrategiesToDepositWhitelist( + strats, + thirdPartyTransfersForbiddenValues + ); + } + + function _deployMiladyPoolContracts( + IDelegationManager delegationManager, + IAVSDirectory avsDirectory, + IStrategy strat + ) internal { + IStrategy[1] memory deployedStrategyArray = [strat]; + uint numStrategies = deployedStrategyArray.length; + miladyPoolProxyAdmin = new ProxyAdmin(); + + { + address[] memory pausers = new address[](2); + pausers[0] = miladyPoolPauser; + pausers[1] = miladyPoolCommunityMultisig; + miladyPoolPauserReg = new PauserRegistry( + pausers, + miladyPoolCommunityMultisig + ); + } + + EmptyContract emptyContract = new EmptyContract(); + + miladyPoolServiceManager = MiladyPoolServiceManager( + address( + new TransparentUpgradeableProxy( + address(emptyContract), + address(miladyPoolProxyAdmin), + "" + ) + ) + ); + + miladyPoolOrderManager = MiladyPoolOrderManager( + address( + new TransparentUpgradeableProxy( + address(emptyContract), + address(miladyPoolProxyAdmin), + "" + ) + ) + ); + + registryCoordinator = regCoord.RegistryCoordinator( + address( + new TransparentUpgradeableProxy( + address(emptyContract), + address(miladyPoolProxyAdmin), + "" + ) + ) + ); + + blsApkRegistry = IBLSApkRegistry( + address( + new TransparentUpgradeableProxy( + address(emptyContract), + address(miladyPoolProxyAdmin), + "" + ) + ) + ); + + indexRegistry = IIndexRegistry( + address( + new TransparentUpgradeableProxy( + address(emptyContract), + address(miladyPoolProxyAdmin), + "" + ) + ) + ); + + stakeRegistry = IStakeRegistry( + address( + new TransparentUpgradeableProxy( + address(emptyContract), + address(miladyPoolProxyAdmin), + "" + ) + ) + ); + + operatorStateRetriever = new OperatorStateRetriever(); + + // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs + { + stakeRegistryImplementation = new StakeRegistry( + registryCoordinator, + delegationManager + ); + + miladyPoolProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(stakeRegistry))), + address(stakeRegistryImplementation) + ); + + blsApkRegistryImplementation = new BLSApkRegistry( + registryCoordinator + ); + + miladyPoolProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(blsApkRegistry))), + address(blsApkRegistryImplementation) + ); + + indexRegistryImplementation = new IndexRegistry( + registryCoordinator + ); + + miladyPoolProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(indexRegistry))), + address(indexRegistryImplementation) + ); + } + + registryCoordinatorImplementation = new regCoord.RegistryCoordinator( + miladyPoolServiceManager, + regCoord.IStakeRegistry(address(stakeRegistry)), + regCoord.IBLSApkRegistry(address(blsApkRegistry)), + regCoord.IIndexRegistry(address(indexRegistry)) + ); + + { + // For each quorum to setup, we need to define + // QuorumOperatorSetParam, minimumStakeForQuorum, and strategyParams + uint numQuorums = 1; + + regCoord.IRegistryCoordinator.OperatorSetParam[] + memory quorumsOperatorSetParams = new regCoord.IRegistryCoordinator.OperatorSetParam[]( + numQuorums + ); + + for (uint i = 0; i < numQuorums; i++) { + quorumsOperatorSetParams[i] = regCoord + .IRegistryCoordinator + .OperatorSetParam({ + maxOperatorCount: 10000, + kickBIPsOfOperatorStake: 15000, + kickBIPsOfTotalStake: 100 + }); + } + + uint96[] memory quorumsMinimumStake = new uint96[](numQuorums); + IStakeRegistry.StrategyParams[][] + memory quorumsStrategyParams = new IStakeRegistry.StrategyParams[][]( + numQuorums + ); + + for (uint i = 0; i < numQuorums; i++) { + quorumsStrategyParams[i] = new IStakeRegistry.StrategyParams[]( + numStrategies + ); + for (uint j = 0; j < numStrategies; j++) { + quorumsStrategyParams[i][j] = IStakeRegistry + .StrategyParams({ + strategy: deployedStrategyArray[j], + // setting this to 1 ether since the divisor is also 1 ether + // therefore this allows an operator to register with even just 1 token + // see https://github.com/Layr-Labs/eigenlayer-middleware/blob/m2-mainnet/src/StakeRegistry.sol#L484 + // weight += uint96(sharesAmount * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + multiplier: 1 ether + }); + } + } + miladyPoolProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy( + payable(address(registryCoordinator)) + ), + address(registryCoordinatorImplementation), + abi.encodeWithSelector( + regCoord.RegistryCoordinator.initialize.selector, + // we set churnApprover and ejector to communityMultisig because we don't need them + miladyPoolCommunityMultisig, + miladyPoolCommunityMultisig, + miladyPoolCommunityMultisig, + miladyPoolPauserReg, + 0, // 0 initialPausedStatus means everything unpaused + quorumsOperatorSetParams, + quorumsMinimumStake, + quorumsStrategyParams + ) + ); + } + + miladyPoolServiceManagerImplementation = new MiladyPoolServiceManager( + avsDirectory, + registryCoordinator, + stakeRegistry, + miladyPoolOrderManager + ); + + miladyPoolProxyAdmin.upgrade( + TransparentUpgradeableProxy( + payable(address(miladyPoolServiceManager)) + ), + address(miladyPoolServiceManagerImplementation) + ); + + uint160 flags = uint160( + Hooks.AFTER_INITIALIZE_FLAG | + Hooks.BEFORE_SWAP_FLAG | + Hooks.BEFORE_SWAP_RETURNS_DELTA_FLAG | + Hooks.AFTER_SWAP_FLAG + ); + + // NOTE: Hook miner has to use vm.prank's address instead of + // CREATE2_DEPLOYER address because of how Foundry works + (address hookAddress, bytes32 salt) = HookMiner.find( + address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266), + flags, + type(MiladyPoolOrderManager).creationCode, + abi.encode(registryCoordinator, POOL_MANAGER) + ); + + miladyPoolOrderManagerImplementation = new MiladyPoolOrderManager{ + salt: salt + }(registryCoordinator, POOL_MANAGER); + + miladyPoolProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy( + payable(address(miladyPoolOrderManager)) + ), + address(miladyPoolOrderManagerImplementation), + abi.encodeWithSelector( + miladyPoolOrderManager.initialize.selector, + miladyPoolPauserReg, + miladyPoolCommunityMultisig + ) + ); + hooksUseable = IHooks(hookAddress); + } +}