From 114d1ece8c32b225f4632de5af67c4188618faae Mon Sep 17 00:00:00 2001 From: MinisculeTarantula Date: Thu, 3 Oct 2024 14:15:47 -0700 Subject: [PATCH] feat: add checker, improve configs, cleanup - add Current_Config_Check.s.sol that checks the active governance config - fix configs by adding more addresses + renaming for clarity - delete (apparently) unused files --- .../eigenlayer_addresses_preprod.config.json | 2 +- .../eigenlayer_addresses_testnet.config.json | 10 +- .../holesky/eigenlayer_testnet.config.json | 1 + .../mainnet/mainnet-addresses.config.json | 10 +- .../deploy/holesky/Eigen_Token_Deploy.s.sol | 22 +- script/deploy/local/Deploy_From_Scratch.s.sol | 2 +- .../holesky/Current_Config_Check.s.sol | 113 ++++ .../holesky/Deploy_TimelockController.s.sol | 136 +++++ script/utils/ExistingDeploymentParser.sol | 18 +- script/whitelist/ERC20PresetMinterPauser.sol | 92 ---- script/whitelist/Staker.sol | 51 -- .../delegationFaucet/DelegationFaucet.sol | 216 -------- .../DelegationFaucetStaker.sol | 26 - .../DeployDelegationFaucet.sol | 84 --- .../interfaces/IDelegationFaucet.sol | 41 -- src/contracts/interfaces/IWhitelister.sol | 41 -- src/test/DelegationFaucet.t.sol | 513 ------------------ 17 files changed, 293 insertions(+), 1085 deletions(-) create mode 100644 script/upgrade/holesky/Current_Config_Check.s.sol create mode 100644 script/upgrade/holesky/Deploy_TimelockController.s.sol delete mode 100644 script/whitelist/ERC20PresetMinterPauser.sol delete mode 100644 script/whitelist/Staker.sol delete mode 100644 script/whitelist/delegationFaucet/DelegationFaucet.sol delete mode 100644 script/whitelist/delegationFaucet/DelegationFaucetStaker.sol delete mode 100644 script/whitelist/delegationFaucet/DeployDelegationFaucet.sol delete mode 100644 src/contracts/interfaces/IDelegationFaucet.sol delete mode 100644 src/contracts/interfaces/IWhitelister.sol delete mode 100644 src/test/DelegationFaucet.t.sol diff --git a/script/configs/holesky/eigenlayer_addresses_preprod.config.json b/script/configs/holesky/eigenlayer_addresses_preprod.config.json index fef339cb0..9913fb275 100644 --- a/script/configs/holesky/eigenlayer_addresses_preprod.config.json +++ b/script/configs/holesky/eigenlayer_addresses_preprod.config.json @@ -36,7 +36,7 @@ "bEIGENImpl": "0x3Ef8CcaD64043A57eeDEcC3900b819E6c80f5419", "eigenStrategy": "0xdcCF401fD121d8C542E96BC1d0078884422aFAD2", "eigenStrategyImpl": "0x59D13E7Fb0bC0e57c1fc6594ff701592A6e4dD2B", - "tokenProxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" + "eigenTokenProxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B" } }, "chainInfo": { diff --git a/script/configs/holesky/eigenlayer_addresses_testnet.config.json b/script/configs/holesky/eigenlayer_addresses_testnet.config.json index c9fc9cb7b..ad909e694 100644 --- a/script/configs/holesky/eigenlayer_addresses_testnet.config.json +++ b/script/configs/holesky/eigenlayer_addresses_testnet.config.json @@ -52,13 +52,16 @@ "strategyFactoryBeacon": "0xd3c6C6BA4E40dB9288c6a2077e5635344F8aFA4F", "strategyFactoryBeaconImplementation": "0xb637caeedfCBf88e0d019E7AE4691b554c994A1e", "token": { - "tokenProxyAdmin": "0x67482666771e82C9a73BB9e9A22B2B597f448BBf", + "eigenTokenProxyAdmin": "0x67482666771e82C9a73BB9e9A22B2B597f448BBf", + "beigenTokenProxyAdmin": "0x6B04F84780CdD42d02b079d1e7a36887bBff8679", "EIGEN": "0x3B78576F7D6837500bA3De27A60c7f594934027E", "bEIGEN": "0x275cCf9Be51f4a6C94aBa6114cdf2a4c45B9cb27", "EIGENImpl": "0x01cbB2ae8eFE46EEdB9f7575D91cA1EB38823050", "bEIGENImpl": "0x05adA1C66DdDD7c36705bC23a4d50dBa72E4E05c", "eigenStrategy": "0x43252609bff8a13dFe5e057097f2f45A24387a84", - "eigenStrategyImpl": "0x94650e09a471CEF96e7966cabf26718FBf352697" + "eigenStrategyImpl": "0x94650e09a471CEF96e7966cabf26718FBf352697", + "eigenTokenTimelockController": "0xf74BAF5e332D4B5F65cB85F863466d745a74918e", + "beigenTokenTimelockController": "0x1554003905e391d99126fF6b9f4ef6A425D8004a" } }, "chainInfo": { @@ -70,7 +73,8 @@ "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", "pauserMultisig": "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7", - "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" + "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D", + "foundationMultisig": "0x7Cb5d96A8D67304E51E022979Eb9C63a17484076" } } \ No newline at end of file diff --git a/script/configs/holesky/eigenlayer_testnet.config.json b/script/configs/holesky/eigenlayer_testnet.config.json index ddc6d2120..44222aa2a 100644 --- a/script/configs/holesky/eigenlayer_testnet.config.json +++ b/script/configs/holesky/eigenlayer_testnet.config.json @@ -8,6 +8,7 @@ "communityMultisig": "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7", "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", + "foundationMultisig": "0x7Cb5d96A8D67304E51E022979Eb9C63a17484076", "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" }, "strategies": { diff --git a/script/configs/mainnet/mainnet-addresses.config.json b/script/configs/mainnet/mainnet-addresses.config.json index f47b5d949..37daf26d9 100644 --- a/script/configs/mainnet/mainnet-addresses.config.json +++ b/script/configs/mainnet/mainnet-addresses.config.json @@ -56,13 +56,16 @@ "0x298aFB19A105D59E74658C4C334Ff360BadE6dd2" ], "token": { - "tokenProxyAdmin": "0x3f5Ab2D4418d38568705bFd6672630fCC3435CC9", + "eigenTokenProxyAdmin": "0x3f5Ab2D4418d38568705bFd6672630fCC3435CC9", + "beigenTokenProxyAdmin": "0x3f5Ab2D4418d38568705bFd6672630fCC3435CC9", "EIGEN": "0xec53bf9167f50cdeb3ae105f56099aaab9061f83", "bEIGEN": "0x83E9115d334D248Ce39a6f36144aEaB5b3456e75", "EIGENImpl": "0x17f56E911C279bad67eDC08acbC9cf3DC4eF26A0", "bEIGENImpl": "0xF2b225815F70c9b327DC9db758A36c92A4279b17", "eigenStrategy": "0xaCB55C530Acdb2849e6d4f36992Cd8c9D50ED8F7", - "eigenStrategyImpl": "0x27e7a3a81741b9fcc5ad7edcbf9f8a72a5c00428" + "eigenStrategyImpl": "0x27e7a3a81741b9fcc5ad7edcbf9f8a72a5c00428", + "eigenTokenTimelockController": "0x2520C6b2C1FBE1813AB5c7c1018CDa39529e9FF2", + "beigenTokenTimelockController": "0xd6EC41E453C5E7dA5494f4d51A053Ab571712E6f" } }, "numStrategies": 12, @@ -75,6 +78,7 @@ "executorMultisig": "0x369e6F597e22EaB55fFb173C6d9cD234BD699111", "operationsMultisig": "0xBE1685C81aA44FF9FB319dD389addd9374383e90", "pauserMultisig": "0x5050389572f2d220ad927CcbeA0D406831012390", - "timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF" + "timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF", + "foundationMultisig": "0xbb00DDa2832850a43840A3A86515E3Fe226865F2" } } \ No newline at end of file diff --git a/script/deploy/holesky/Eigen_Token_Deploy.s.sol b/script/deploy/holesky/Eigen_Token_Deploy.s.sol index bd130a034..b4e944c7c 100644 --- a/script/deploy/holesky/Eigen_Token_Deploy.s.sol +++ b/script/deploy/holesky/Eigen_Token_Deploy.s.sol @@ -19,7 +19,7 @@ contract Eigen_Token_Deploy is Script, Test { address operationsMultisig = 0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d; EmptyContract public emptyContract = EmptyContract(0x9690d52B1Ce155DB2ec5eCbF5a262ccCc7B3A6D2); - ProxyAdmin public tokenProxyAdmin; + ProxyAdmin public eigenTokenProxyAdmin; Eigen public EIGENImpl; Eigen public EIGEN; BackingEigen public bEIGENImpl; @@ -38,7 +38,7 @@ contract Eigen_Token_Deploy is Script, Test { emit log_string("====Deployed Contracts===="); - emit log_named_address("ProxyAdmin", address(tokenProxyAdmin)); + emit log_named_address("ProxyAdmin", address(eigenTokenProxyAdmin)); emit log_named_address("EIGEN", address(EIGEN)); emit log_named_address("bEIGEN", address(bEIGEN)); emit log_named_address("EIGENImpl", address(EIGENImpl)); @@ -47,14 +47,14 @@ contract Eigen_Token_Deploy is Script, Test { function _deployToken() internal { // Deploy ProxyAdmin, later set admins for all proxies to be executorMultisig - tokenProxyAdmin = new ProxyAdmin(); + eigenTokenProxyAdmin = new ProxyAdmin(); EIGEN = Eigen( - address(new TransparentUpgradeableProxy(address(emptyContract), address(tokenProxyAdmin), "")) + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenTokenProxyAdmin), "")) ); bEIGEN = BackingEigen( - address(new TransparentUpgradeableProxy(address(emptyContract), address(tokenProxyAdmin), "")) + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenTokenProxyAdmin), "")) ); // deploy impls @@ -70,7 +70,7 @@ contract Eigen_Token_Deploy is Script, Test { uint256[] memory mintAllowedAfters = new uint256[](1); // upgrade and initialize proxies - tokenProxyAdmin.upgradeAndCall( + eigenTokenProxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(EIGEN))), address(EIGENImpl), abi.encodeWithSelector( @@ -84,7 +84,7 @@ contract Eigen_Token_Deploy is Script, Test { EIGEN.mint(); - tokenProxyAdmin.upgradeAndCall( + eigenTokenProxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(bEIGEN))), address(bEIGENImpl), abi.encodeWithSelector( @@ -93,7 +93,7 @@ contract Eigen_Token_Deploy is Script, Test { ) ); - tokenProxyAdmin.transferOwnership(operationsMultisig); + eigenTokenProxyAdmin.transferOwnership(operationsMultisig); } function _verifyDeployment() internal view { @@ -106,9 +106,9 @@ contract Eigen_Token_Deploy is Script, Test { require(EIGEN.owner() == msg.sender, "Eigen_Token_Deploy: EIGEN owner mismatch"); require(bEIGEN.owner() == msg.sender, "Eigen_Token_Deploy: bEIGEN owner mismatch"); - require(tokenProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(EIGEN)))) == address(EIGENImpl), "Eigen_Token_Deploy: EIGEN implementation mismatch"); - require(tokenProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN)))) == address(bEIGENImpl), "Eigen_Token_Deploy: bEIGEN implementation mismatch"); + require(eigenTokenProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(EIGEN)))) == address(EIGENImpl), "Eigen_Token_Deploy: EIGEN implementation mismatch"); + require(eigenTokenProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(bEIGEN)))) == address(bEIGENImpl), "Eigen_Token_Deploy: bEIGEN implementation mismatch"); - require(tokenProxyAdmin.owner() == operationsMultisig, "Eigen_Token_Deploy: ProxyAdmin owner mismatch"); + require(eigenTokenProxyAdmin.owner() == operationsMultisig, "Eigen_Token_Deploy: ProxyAdmin owner mismatch"); } } diff --git a/script/deploy/local/Deploy_From_Scratch.s.sol b/script/deploy/local/Deploy_From_Scratch.s.sol index a6e56b723..a3c4c9a5a 100644 --- a/script/deploy/local/Deploy_From_Scratch.s.sol +++ b/script/deploy/local/Deploy_From_Scratch.s.sol @@ -412,7 +412,7 @@ contract DeployFromScratch is Script, Test { { // dummy token data - string memory token = '{"tokenProxyAdmin": "0x0000000000000000000000000000000000000000", "EIGEN": "0x0000000000000000000000000000000000000000","bEIGEN": "0x0000000000000000000000000000000000000000","EIGENImpl": "0x0000000000000000000000000000000000000000","bEIGENImpl": "0x0000000000000000000000000000000000000000","eigenStrategy": "0x0000000000000000000000000000000000000000","eigenStrategyImpl": "0x0000000000000000000000000000000000000000"}'; + string memory token = '{"eigenTokenProxyAdmin": "0x0000000000000000000000000000000000000000", "EIGEN": "0x0000000000000000000000000000000000000000","bEIGEN": "0x0000000000000000000000000000000000000000","EIGENImpl": "0x0000000000000000000000000000000000000000","bEIGENImpl": "0x0000000000000000000000000000000000000000","eigenStrategy": "0x0000000000000000000000000000000000000000","eigenStrategyImpl": "0x0000000000000000000000000000000000000000"}'; deployed_addresses_output = vm.serializeString(deployed_addresses, "token", token); } diff --git a/script/upgrade/holesky/Current_Config_Check.s.sol b/script/upgrade/holesky/Current_Config_Check.s.sol new file mode 100644 index 000000000..f4504ee6d --- /dev/null +++ b/script/upgrade/holesky/Current_Config_Check.s.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "../../utils/ExistingDeploymentParser.sol"; +import "../../utils/TimelockEncoding.sol"; + +/** + * forge script script/upgrade/holesky/Current_Config_Check.s.sol:Current_Config_Check -vvv + * + */ +contract Current_Config_Check is ExistingDeploymentParser, TimelockEncoding { + string deployedContractsConfig = "script/configs/holesky/eigenlayer_addresses_testnet.config.json"; + string intialDeploymentParams = "script/configs/holesky/eigenlayer_testnet.config.json"; + function run() external virtual { + string memory forkUrl = vm.envString("RPC_HOLESKY"); + uint256 forkId = vm.createFork(forkUrl); + vm.selectFork(forkId); + + // read and log the chainID + uint256 currentChainId = block.chainid; + emit log_named_uint("You are parsing on ChainID", currentChainId); + require(currentChainId == 17000, "script is only for mainnet"); + + _parseDeployedContracts(deployedContractsConfig); + _parseInitialDeploymentParams(intialDeploymentParams); + + // Sanity Checks + _verifyContractPointers(); + _verifyImplementations(); + _verifyContractsInitialized(false); + _verifyInitializationParams(); + + // bytes memory data = abi.encodeWithSelector(strategyFactory.transferOwnership.selector, operationsMultisig); + // bytes memory callToExecutor = encodeForExecutor({ + // from: communityMultisig, + // to: address(strategyFactory), + // value: 0, + // data: data, + // operation: ISafe.Operation.Call + // }); + + // vm.prank(communityMultisig); + // (bool success, /*bytes memory returndata*/) = executorMultisig.call(callToExecutor); + // require(success, "call to executorMultisig failed"); + + checkDesiredGovernanceConfiguration(); + } + + // check governance configuration + function checkDesiredGovernanceConfiguration() public { + assertEq(eigenLayerProxyAdmin.owner(), executorMultisig, + "eigenLayerProxyAdmin.owner() != executorMultisig"); + assertEq(delegationManager.owner(), executorMultisig, + "delegationManager.owner() != executorMultisig"); + assertEq(strategyManager.owner(), executorMultisig, + "strategyManager.owner() != executorMultisig"); + assertEq(strategyManager.strategyWhitelister(), address(strategyFactory), + "strategyManager.strategyWhitelister() != address(strategyFactory)"); + assertEq(strategyFactory.owner(), operationsMultisig, + "strategyFactory.owner() != operationsMultisig"); + assertEq(avsDirectory.owner(), executorMultisig, + "avsDirectory.owner() != executorMultisig"); + assertEq(rewardsCoordinator.owner(), operationsMultisig, + "rewardsCoordinator.owner() != operationsMultisig"); + assertEq(eigenLayerPauserReg.unpauser(), executorMultisig, + "eigenLayerPauserReg.unpauser() != operationsMultisig"); + require(eigenLayerPauserReg.isPauser(operationsMultisig), + "operationsMultisig does not have pausing permissions"); + require(eigenLayerPauserReg.isPauser(executorMultisig), + "executorMultisig does not have pausing permissions"); + require(eigenLayerPauserReg.isPauser(pauserMultisig), + "pauserMultisig does not have pausing permissions"); + + (bool success, bytes memory returndata) = timelock.staticcall(abi.encodeWithSignature("admin()")); + require(success, "call to timelock.admin() failed"); + address timelockAdmin = abi.decode(returndata, (address)); + assertEq(timelockAdmin, operationsMultisig, + "timelockAdmin != operationsMultisig"); + + (success, returndata) = executorMultisig.staticcall(abi.encodeWithSignature("getOwners()")); + require(success, "call to executorMultisig.getOwners() failed"); + address[] memory executorMultisigOwners = abi.decode(returndata, (address[])); + require(executorMultisigOwners.length == 2, + "executorMultisig owners wrong length"); + bool timelockInOwners; + bool communityMultisigInOwners; + for (uint256 i = 0; i < 2; ++i) { + if (executorMultisigOwners[i] == timelock) { + timelockInOwners = true; + } + if (executorMultisigOwners[i] == communityMultisig) { + communityMultisigInOwners = true; + } + } + require(timelockInOwners, "timelock not in executorMultisig owners"); + require(communityMultisigInOwners, "communityMultisig not in executorMultisig owners"); + + require(eigenTokenProxyAdmin != beigenTokenProxyAdmin, + "tokens must have different proxy admins to allow different timelock controllers"); + require(eigenTokenTimelockController != beigenTokenTimelockController, + "tokens must have different timelock controllers"); + + // note that proxy admin owners are different but _token_ owners are the same + assertEq(Ownable(address(EIGEN)).owner(), address(eigenTokenTimelockController), + "EIGEN.owner() != eigenTokenTimelockController"); + assertEq(Ownable(address(bEIGEN)).owner(), address(eigenTokenTimelockController), + "bEIGEN.owner() != eigenTokenTimelockController"); + assertEq(eigenTokenProxyAdmin.owner(), address(eigenTokenTimelockController), + "eigenTokenProxyAdmin.owner() != eigenTokenTimelockController"); + assertEq(beigenTokenProxyAdmin.owner(), address(beigenTokenTimelockController), + "beigenTokenProxyAdmin.owner() != beigenTokenTimelockController"); + } +} diff --git a/script/upgrade/holesky/Deploy_TimelockController.s.sol b/script/upgrade/holesky/Deploy_TimelockController.s.sol new file mode 100644 index 000000000..4525aac73 --- /dev/null +++ b/script/upgrade/holesky/Deploy_TimelockController.s.sol @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "../../utils/ExistingDeploymentParser.sol"; + +/** + * forge script script/upgrade/holesky/Deploy_TimelockController.s.sol:Deploy_TimelockController -vvv + * + */ +contract Deploy_TimelockController is ExistingDeploymentParser { + bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE"); + bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); + bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); + + string deployedContractsConfig = "script/configs/holesky/eigenlayer_addresses_testnet.config.json"; + string intialDeploymentParams = "script/configs/holesky/eigenlayer_testnet.config.json"; + + function run() external virtual { + string memory forkUrl = vm.envString("RPC_HOLESKY"); + uint256 forkId = vm.createFork(forkUrl); + vm.selectFork(forkId); + + // read and log the chainID + uint256 currentChainId = block.chainid; + emit log_named_uint("You are parsing on ChainID", currentChainId); + require(currentChainId == 17000, "script is only for mainnet"); + + _parseDeployedContracts(deployedContractsConfig); + _parseInitialDeploymentParams(intialDeploymentParams); + + // Sanity Checks + _verifyContractPointers(); + _verifyImplementations(); + _verifyContractsInitialized(false); + _verifyInitializationParams(); + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + uint256 minDelay = 1; + address[] memory proposers; + address[] memory executors; + TimelockController newTimelockController = new TimelockController({ + minDelay: minDelay, + proposers: proposers, + executors: executors + }); + + newTimelockController.grantRole(TIMELOCK_ADMIN_ROLE, executorMultisig); + newTimelockController.grantRole(CANCELLER_ROLE, operationsMultisig); + newTimelockController.grantRole(PROPOSER_ROLE, foundationMultisig); + newTimelockController.grantRole(EXECUTOR_ROLE, foundationMultisig); + newTimelockController.renounceRole(TIMELOCK_ADMIN_ROLE, msg.sender); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + + require(newTimelockController.hasRole(TIMELOCK_ADMIN_ROLE, executorMultisig), + "executorMultisig does not have TIMELOCK_ADMIN_ROLE"); + require(newTimelockController.hasRole(CANCELLER_ROLE, operationsMultisig), + "operationsMultisig does not have CANCELLER_ROLE"); + require(newTimelockController.hasRole(PROPOSER_ROLE, foundationMultisig), + "foundationMultisig does not have PROPOSER_ROLE"); + require(newTimelockController.hasRole(EXECUTOR_ROLE, foundationMultisig), + "foundationMultisig does not have EXECUTOR_ROLE"); + require(!newTimelockController.hasRole(TIMELOCK_ADMIN_ROLE, msg.sender), + "TIMELOCK_ADMIN_ROLE should have been renounced"); + + emit log_named_address("address(newTimelockController)", address(newTimelockController)); + } + + // check governance configuration + function checkDesiredGovernanceConfiguration() public { + assertEq(eigenLayerProxyAdmin.owner(), executorMultisig, + "eigenLayerProxyAdmin.owner() != executorMultisig"); + assertEq(delegationManager.owner(), executorMultisig, + "delegationManager.owner() != executorMultisig"); + assertEq(strategyManager.owner(), executorMultisig, + "strategyManager.owner() != executorMultisig"); + assertEq(strategyManager.strategyWhitelister(), address(strategyFactory), + "strategyManager.strategyWhitelister() != address(strategyFactory)"); + assertEq(strategyFactory.owner(), operationsMultisig, + "strategyFactory.owner() != operationsMultisig"); + assertEq(avsDirectory.owner(), executorMultisig, + "avsDirectory.owner() != executorMultisig"); + assertEq(rewardsCoordinator.owner(), operationsMultisig, + "rewardsCoordinator.owner() != operationsMultisig"); + assertEq(eigenLayerPauserReg.unpauser(), executorMultisig, + "eigenLayerPauserReg.unpauser() != operationsMultisig"); + require(eigenLayerPauserReg.isPauser(operationsMultisig), + "operationsMultisig does not have pausing permissions"); + require(eigenLayerPauserReg.isPauser(executorMultisig), + "executorMultisig does not have pausing permissions"); + require(eigenLayerPauserReg.isPauser(pauserMultisig), + "pauserMultisig does not have pausing permissions"); + + (bool success, bytes memory returndata) = timelock.staticcall(abi.encodeWithSignature("admin()")); + require(success, "call to timelock.admin() failed"); + address timelockAdmin = abi.decode(returndata, (address)); + assertEq(timelockAdmin, operationsMultisig, + "timelockAdmin != operationsMultisig"); + + (success, returndata) = executorMultisig.staticcall(abi.encodeWithSignature("getOwners()")); + require(success, "call to executorMultisig.getOwners() failed"); + address[] memory executorMultisigOwners = abi.decode(returndata, (address[])); + require(executorMultisigOwners.length == 2, + "executorMultisig owners wrong length"); + bool timelockInOwners; + bool communityMultisigInOwners; + for (uint256 i = 0; i < 2; ++i) { + if (executorMultisigOwners[i] == timelock) { + timelockInOwners = true; + } + if (executorMultisigOwners[i] == communityMultisig) { + communityMultisigInOwners = true; + } + } + require(timelockInOwners, "timelock not in executorMultisig owners"); + require(communityMultisigInOwners, "communityMultisig not in executorMultisig owners"); + + require(eigenTokenProxyAdmin != beigenTokenProxyAdmin, + "tokens must have different proxy admins to allow different timelock controllers"); + require(eigenTokenTimelockController != beigenTokenTimelockController, + "tokens must have different timelock controllers"); + + assertEq(Ownable(address(EIGEN)).owner(), address(eigenTokenTimelockController), + "EIGEN.owner() != eigenTokenTimelockController"); + assertEq(Ownable(address(bEIGEN)).owner(), address(beigenTokenTimelockController), + "bEIGEN.owner() != beigenTokenTimelockController"); + assertEq(eigenTokenProxyAdmin.owner(), foundationMultisig, + "eigenTokenProxyAdmin.owner() != foundationMultisig"); + assertEq(beigenTokenProxyAdmin.owner(), foundationMultisig, + "beigenTokenProxyAdmin.owner() != foundationMultisig"); + } +} diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index c0b2c71f3..d8cf69f0d 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import "@openzeppelin/contracts/governance/TimelockController.sol"; import "../../src/contracts/core/StrategyManager.sol"; import "../../src/contracts/core/Slasher.sol"; @@ -66,13 +67,16 @@ contract ExistingDeploymentParser is Script, Test { StrategyBase public strategyFactoryBeaconImplementation; // Token - ProxyAdmin public tokenProxyAdmin; + ProxyAdmin public eigenTokenProxyAdmin; + ProxyAdmin public beigenTokenProxyAdmin; IEigen public EIGEN; IEigen public EIGENImpl; IBackingEigen public bEIGEN; IBackingEigen public bEIGENImpl; EigenStrategy public eigenStrategy; EigenStrategy public eigenStrategyImpl; + TimelockController public eigenTokenTimelockController; + TimelockController public beigenTokenTimelockController; // EigenPods deployed address[] public multiValidatorPods; @@ -87,6 +91,7 @@ contract ExistingDeploymentParser is Script, Test { address operationsMultisig; address communityMultisig; address pauserMultisig; + address foundationMultisig; address timelock; // strategies deployed @@ -149,6 +154,7 @@ contract ExistingDeploymentParser is Script, Test { operationsMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.operationsMultisig"); communityMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.communityMultisig"); pauserMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.pauserMultisig"); + foundationMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.foundationMultisig"); timelock = stdJson.readAddress(existingDeploymentData, ".parameters.timelock"); eigenLayerProxyAdmin = ProxyAdmin( @@ -210,13 +216,18 @@ contract ExistingDeploymentParser is Script, Test { } // token - tokenProxyAdmin = ProxyAdmin(stdJson.readAddress(existingDeploymentData, ".addresses.token.tokenProxyAdmin")); + eigenTokenProxyAdmin = ProxyAdmin(stdJson.readAddress(existingDeploymentData, ".addresses.token.eigenTokenProxyAdmin")); + beigenTokenProxyAdmin = ProxyAdmin(stdJson.readAddress(existingDeploymentData, ".addresses.token.beigenTokenProxyAdmin")); EIGEN = IEigen(stdJson.readAddress(existingDeploymentData, ".addresses.token.EIGEN")); EIGENImpl = IEigen(stdJson.readAddress(existingDeploymentData, ".addresses.token.EIGENImpl")); bEIGEN = IBackingEigen(stdJson.readAddress(existingDeploymentData, ".addresses.token.bEIGEN")); bEIGENImpl = IBackingEigen(stdJson.readAddress(existingDeploymentData, ".addresses.token.bEIGENImpl")); eigenStrategy = EigenStrategy(stdJson.readAddress(existingDeploymentData, ".addresses.token.eigenStrategy")); eigenStrategyImpl = EigenStrategy(stdJson.readAddress(existingDeploymentData, ".addresses.token.eigenStrategyImpl")); + eigenTokenTimelockController = TimelockController( + payable(stdJson.readAddress(existingDeploymentData, ".addresses.token.eigenTokenTimelockController"))); + beigenTokenTimelockController = TimelockController( + payable(stdJson.readAddress(existingDeploymentData, ".addresses.token.beigenTokenTimelockController"))); } function _parseDeployedEigenPods(string memory existingDeploymentInfoPath) internal returns (DeployedEigenPods memory) { @@ -262,6 +273,7 @@ contract ExistingDeploymentParser is Script, Test { operationsMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.operationsMultisig"); communityMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.communityMultisig"); pauserMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.pauserMultisig"); + foundationMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.foundationMultisig"); // Strategies to Deploy, load strategy list numStrategiesToDeploy = stdJson.readUint(initialDeploymentData, ".strategies.numStrategies"); @@ -641,6 +653,7 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_address("operationsMultisig", operationsMultisig); emit log_named_address("communityMultisig", communityMultisig); emit log_named_address("pauserMultisig", pauserMultisig); + emit log_named_address("foundationMultisig", foundationMultisig); emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); emit log_named_address("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); @@ -738,6 +751,7 @@ contract ExistingDeploymentParser is Script, Test { vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); vm.serializeAddress(parameters, "communityMultisig", communityMultisig); vm.serializeAddress(parameters, "pauserMultisig", pauserMultisig); + vm.serializeAddress(parameters, "foundationMultisig", foundationMultisig); vm.serializeAddress(parameters, "timelock", timelock); string memory parameters_output = vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); diff --git a/script/whitelist/ERC20PresetMinterPauser.sol b/script/whitelist/ERC20PresetMinterPauser.sol deleted file mode 100644 index 9aa3fb4b1..000000000 --- a/script/whitelist/ERC20PresetMinterPauser.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/presets/ERC20PresetMinterPauser.sol) - -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; -import "@openzeppelin/contracts/utils/Context.sol"; -import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; - - -/** - * @dev {ERC20} token, including: - * - * - ability for holders to burn (destroy) their tokens - * - a minter role that allows for token minting (creation) - * - a pauser role that allows to stop all token transfers - * - * This contract uses {AccessControl} to lock permissioned functions using the - * different roles - head to its documentation for details. - * - * The account that deploys the contract will be granted the minter and pauser - * roles, as well as the default admin role, which will let it grant both minter - * and pauser roles to other accounts. - * - * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ - */ -contract ERC20PresetMinterPauser is Context, AccessControlEnumerable, ERC20Burnable { - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); - - /** - * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the - * account that deploys the contract. - * - * See {ERC20-constructor}. - */ - constructor(string memory name, string memory symbol) ERC20(name, symbol) { - _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); - - _setupRole(MINTER_ROLE, _msgSender()); - _setupRole(PAUSER_ROLE, _msgSender()); - } - - /** - * @dev Creates `amount` new tokens for `to`. - * - * See {ERC20-_mint}. - * - * Requirements: - * - * - the caller must have the `MINTER_ROLE`. - */ - function mint(address to, uint256 amount) public virtual { - require(hasRole(MINTER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have minter role to mint"); - _mint(to, amount); - } - - /** - * @dev Pauses all token transfers. - * - * See {ERC20Pausable} and {Pausable-_pause}. - * - * Requirements: - * - * - the caller must have the `PAUSER_ROLE`. - */ - function pause() public virtual { - require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to pause"); - - } - - /** - * @dev Unpauses all token transfers. - * - * See {ERC20Pausable} and {Pausable-_unpause}. - * - * Requirements: - * - * - the caller must have the `PAUSER_ROLE`. - */ - function unpause() public virtual { - require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to unpause"); - } - - function _beforeTokenTransfer( - address from, - address to, - uint256 amount - ) internal virtual override(ERC20) { - super._beforeTokenTransfer(from, to, amount); - } -} \ No newline at end of file diff --git a/script/whitelist/Staker.sol b/script/whitelist/Staker.sol deleted file mode 100644 index f353610ce..000000000 --- a/script/whitelist/Staker.sol +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "../../src/contracts/interfaces/IStrategyManager.sol"; -import "../../src/contracts/interfaces/IStrategy.sol"; -import "../../src/contracts/interfaces/IDelegationManager.sol"; -import "../../src/contracts/interfaces/ISignatureUtils.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "forge-std/Test.sol"; - -contract Staker is Ownable { - - constructor( - IStrategy strategy, - IStrategyManager strategyManager, - IDelegationManager delegation, - IERC20 token, - uint256 amount, - address operator - ) Ownable() { - token.approve(address(strategyManager), type(uint256).max); - strategyManager.depositIntoStrategy(strategy, token, amount); - ISignatureUtils.SignatureWithExpiry memory signatureWithExpiry; - delegation.delegateTo(operator, signatureWithExpiry, bytes32(0)); - } - - function callAddress(address implementation, bytes memory data) external onlyOwner returns(bytes memory) { - uint256 length = data.length; - bytes memory returndata; - assembly{ - let result := call( - gas(), - implementation, - callvalue(), - add(data, 32), - length, - 0, - 0 - ) - mstore(returndata, returndatasize()) - returndatacopy(add(returndata, 32), 0, returndatasize()) - } - - - return returndata; - - } - -} diff --git a/script/whitelist/delegationFaucet/DelegationFaucet.sol b/script/whitelist/delegationFaucet/DelegationFaucet.sol deleted file mode 100644 index 327e8e678..000000000 --- a/script/whitelist/delegationFaucet/DelegationFaucet.sol +++ /dev/null @@ -1,216 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IStrategyManager.sol"; -import "src/contracts/interfaces/IStrategy.sol"; -import "src/contracts/interfaces/IDelegationManager.sol"; -import "src/contracts/interfaces/IDelegationFaucet.sol"; -import "script/whitelist/delegationFaucet/DelegationFaucetStaker.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; -import "@openzeppelin/contracts/utils/Address.sol"; - -import "../ERC20PresetMinterPauser.sol"; - -/** - * @title DelegationFaucet for M2 - * @author Layr Labs, Inc. - * @notice Faucet contract setup with a dummy ERC20 token and strategy for M2 testnet release. - * Each operator address gets a staker contract assigned to them deterministically. - * This contract assumes minting role of the ERC20 token and that the ERC20 token has a whitelisted strategy. - */ -contract DelegationFaucet is IDelegationFaucet, Ownable { - IStrategyManager immutable strategyManager; - ERC20PresetMinterPauser immutable stakeToken; - IStrategy immutable stakeStrategy; - IDelegationManager immutable delegation; - - uint256 public constant DEFAULT_AMOUNT = 100e18; - - constructor( - IStrategyManager _strategyManager, - IDelegationManager _delegation, - ERC20PresetMinterPauser _token, - IStrategy _strategy - ) { - strategyManager = _strategyManager; - delegation = _delegation; - stakeToken = _token; - stakeStrategy = _strategy; - } - - /** - * Deploys a DelegationFaucetStaker contract if not already deployed for operator. DelegationFaucetStaker gets minted _depositAmount or - * DEFAULT_AMOUNT if _depositAmount is 0. Then DelegationFaucetStaker contract deposits into the strategy and delegates to operator. - * @param _operator The operator to delegate to - * @param _approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param _approverSalt A unique single use value tied to an individual signature. - * @param _depositAmount The amount to deposit into the strategy - */ - function mintDepositAndDelegate( - address _operator, - IDelegationManager.SignatureWithExpiry memory _approverSignatureAndExpiry, - bytes32 _approverSalt, - uint256 _depositAmount - ) public onlyOwner { - // Operator must be registered - require(delegation.isOperator(_operator), "DelegationFaucet: Operator not registered"); - address staker = getStaker(_operator); - // Set deposit amount - if (_depositAmount == 0) { - _depositAmount = DEFAULT_AMOUNT; - } - - // Deploy staker address if not already deployed, staker constructor will approve the StrategyManager to spend the stakeToken - if (!Address.isContract(staker)) { - Create2.deploy( - 0, - bytes32(uint256(uint160(_operator))), - abi.encodePacked(type(DelegationFaucetStaker).creationCode, abi.encode(strategyManager, stakeToken)) - ); - } - - // mint stakeToken to staker - stakeToken.mint(staker, _depositAmount); - // deposit into stakeToken strategy, which will increase delegated shares to operator if already delegated - _depositIntoStrategy(staker, stakeStrategy, stakeToken, _depositAmount); - // delegateTo operator if not delegated - if (!delegation.isDelegated(staker)) { - delegateTo(_operator, _approverSignatureAndExpiry, _approverSalt); - } - } - - /** - * Calls staker contract to deposit into designated strategy, mints staked token if stakeToken and stakeStrategy - * are specified. - * @param _staker address of staker contract for operator - * @param _strategy StakeToken strategy contract - * @param _token StakeToken - * @param _amount amount to get minted and to deposit - */ - function depositIntoStrategy( - address _staker, - IStrategy _strategy, - IERC20 _token, - uint256 _amount - ) public onlyOwner returns (bytes memory) { - // mint stakeToken to staker - if (_token == stakeToken && _strategy == stakeStrategy) { - stakeToken.mint(_staker, _amount); - } - return _depositIntoStrategy(_staker, _strategy, _token, _amount); - } - - /** - * Call staker to delegate to operator - * @param _operator operator to get staker address from and delegate to - * @param _approverSignatureAndExpiry Verifies the operator approves of this delegation - * @param _approverSalt A unique single use value tied to an individual signature. - */ - function delegateTo( - address _operator, - IDelegationManager.SignatureWithExpiry memory _approverSignatureAndExpiry, - bytes32 _approverSalt - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IDelegationManager.delegateTo.selector, - _operator, - _approverSignatureAndExpiry, - _approverSalt - ); - return DelegationFaucetStaker(getStaker(_operator)).callAddress(address(delegation), data); - } - - /** - * Call queueWithdrawal through staker contract - */ - function queueWithdrawal( - address staker, - IDelegationManager.QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IDelegationManager.queueWithdrawals.selector, - queuedWithdrawalParams - ); - return DelegationFaucetStaker(staker).callAddress(address(delegation), data); - } - - /** - * Call completeQueuedWithdrawal through staker contract - */ - function completeQueuedWithdrawal( - address staker, - IDelegationManager.Withdrawal calldata queuedWithdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IDelegationManager.completeQueuedWithdrawal.selector, - queuedWithdrawal, - tokens, - middlewareTimesIndex, - receiveAsTokens - ); - return DelegationFaucetStaker(staker).callAddress(address(delegation), data); - } - - /** - * Transfers tokens from staker contract to designated address - * @param staker staker contract to transfer from - * @param token ERC20 token - * @param to the to address - * @param amount transfer amount - */ - function transfer( - address staker, - address token, - address to, - uint256 amount - ) public onlyOwner returns (bytes memory) { - bytes memory data = abi.encodeWithSelector(IERC20.transfer.selector, to, amount); - return DelegationFaucetStaker(staker).callAddress(token, data); - } - - function callAddress(address to, bytes memory data) public payable onlyOwner returns (bytes memory) { - (bool ok, bytes memory res) = payable(to).call{value: msg.value}(data); - if (!ok) { - revert(string(res)); - } - return res; - } - - /** - * @notice Returns the deterministic staker contract address for the operator - * @param _operator The operator to get the staker contract address for - */ - function getStaker(address _operator) public view returns (address) { - return - Create2.computeAddress( - bytes32(uint256(uint160(_operator))), //salt - keccak256( - abi.encodePacked(type(DelegationFaucetStaker).creationCode, abi.encode(strategyManager, stakeToken)) - ) - ); - } - - /** - * @notice Internal function to deposit into a strategy, has same function signature as StrategyManager.depositIntoStrategy - */ - function _depositIntoStrategy( - address _staker, - IStrategy _strategy, - IERC20 _token, - uint256 _amount - ) internal returns (bytes memory) { - bytes memory data = abi.encodeWithSelector( - IStrategyManager.depositIntoStrategy.selector, - _strategy, - _token, - _amount - ); - return DelegationFaucetStaker(_staker).callAddress(address(strategyManager), data); - } -} diff --git a/script/whitelist/delegationFaucet/DelegationFaucetStaker.sol b/script/whitelist/delegationFaucet/DelegationFaucetStaker.sol deleted file mode 100644 index fac0e543c..000000000 --- a/script/whitelist/delegationFaucet/DelegationFaucetStaker.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IStrategyManager.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "forge-std/Test.sol"; - -contract DelegationFaucetStaker is Ownable { - constructor(IStrategyManager strategyManager, IERC20 token) Ownable() { - token.approve(address(strategyManager), type(uint256).max); - } - - function callAddress(address implementation, bytes memory data) external onlyOwner returns (bytes memory) { - uint256 length = data.length; - bytes memory returndata; - assembly { - let result := call(gas(), implementation, callvalue(), add(data, 32), length, 0, 0) - mstore(returndata, returndatasize()) - returndatacopy(add(returndata, 32), 0, returndatasize()) - } - - return returndata; - } -} diff --git a/script/whitelist/delegationFaucet/DeployDelegationFaucet.sol b/script/whitelist/delegationFaucet/DeployDelegationFaucet.sol deleted file mode 100644 index db458e99d..000000000 --- a/script/whitelist/delegationFaucet/DeployDelegationFaucet.sol +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "src/contracts/interfaces/IDelegationManager.sol"; -import "src/contracts/interfaces/IStrategyManager.sol"; -import "src/contracts/strategies/StrategyBase.sol"; -import "src/contracts/permissions/PauserRegistry.sol"; - -import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; - -import "./DelegationFaucet.sol"; - -import "forge-std/Script.sol"; -import "forge-std/StdJson.sol"; - -/** - * @notice Deploys the following contracts: - * - ERC20 Dummy token for testing - * - StrategyBase to be added to the StrategyManager whitelist - * - DelegationFaucet contract - */ -contract DeployDelegationFaucet is Script, DSTest { - // EigenLayer contracts - ProxyAdmin public eigenLayerProxyAdmin; - PauserRegistry public eigenLayerPauserReg; - IDelegationManager public delegation; - IStrategyManager public strategyManager; - - DelegationFaucet public delegationFaucet; - - // M2 testing/mock contracts - ERC20PresetMinterPauser public stakeToken; - StrategyBase public stakeTokenStrat; - StrategyBase public baseStrategyImplementation; - - address eigenLayerProxyAdminAddress; - address eigenLayerPauserRegAddress; - address delegationAddress; - address strategyManagerAddress; - address operationsMultisig; - address executorMultisig; - - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - - function run() external { - string memory goerliDeploymentConfig = vm.readFile("script/output/M1_deployment_goerli_2023_3_23.json"); - _setAddresses(goerliDeploymentConfig); - - vm.startBroadcast(); - // Deploy ERC20 stakeToken - stakeToken = new ERC20PresetMinterPauser("StakeToken", "STK"); - - // Deploy StrategyBase for stakeToken & whitelist it - baseStrategyImplementation = new StrategyBase(strategyManager); - stakeTokenStrat = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - eigenLayerProxyAdminAddress, - abi.encodeWithSelector(StrategyBase.initialize.selector, stakeToken, eigenLayerPauserRegAddress) - ) - ) - ); - - // Needs to be strategyManager.strategyWhitelister() to add STK strategy - // IStrategy[] memory _strategy = new IStrategy[](1); - // _strategy[0] = stakeTokenStrat; - // strategyManager.addStrategiesToDepositWhitelist(_strategy); - - // Deploy DelegationFaucet, grant it admin/mint/pauser roles, etc. - delegationFaucet = new DelegationFaucet(strategyManager, delegation, stakeToken, stakeTokenStrat); - stakeToken.grantRole(MINTER_ROLE, address(delegationFaucet)); - vm.stopBroadcast(); - } - - function _setAddresses(string memory config) internal { - eigenLayerProxyAdminAddress = stdJson.readAddress(config, ".addresses.eigenLayerProxyAdmin"); - eigenLayerPauserRegAddress = stdJson.readAddress(config, ".addresses.eigenLayerPauserReg"); - delegationAddress = stdJson.readAddress(config, ".addresses.delegation"); - strategyManagerAddress = stdJson.readAddress(config, ".addresses.strategyManager"); - operationsMultisig = stdJson.readAddress(config, ".parameters.operationsMultisig"); - executorMultisig = stdJson.readAddress(config, ".parameters.executorMultisig"); - } -} diff --git a/src/contracts/interfaces/IDelegationFaucet.sol b/src/contracts/interfaces/IDelegationFaucet.sol deleted file mode 100644 index 8741208db..000000000 --- a/src/contracts/interfaces/IDelegationFaucet.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0; - -import "src/contracts/interfaces/IDelegationManager.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -interface IDelegationFaucet { - function mintDepositAndDelegate( - address _operator, - IDelegationManager.SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt, - uint256 _depositAmount - ) external; - - function getStaker(address operator) external returns (address); - - function depositIntoStrategy( - address staker, - IStrategy strategy, - IERC20 token, - uint256 amount - ) external returns (bytes memory); - - function queueWithdrawal( - address staker, - IDelegationManager.QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) external returns (bytes memory); - - function completeQueuedWithdrawal( - address staker, - IDelegationManager.Withdrawal calldata queuedWithdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external returns (bytes memory); - - function transfer(address staker, address token, address to, uint256 amount) external returns (bytes memory); - - function callAddress(address to, bytes memory data) external payable returns (bytes memory); -} diff --git a/src/contracts/interfaces/IWhitelister.sol b/src/contracts/interfaces/IWhitelister.sol deleted file mode 100644 index da68992c8..000000000 --- a/src/contracts/interfaces/IWhitelister.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0; - -import "../../contracts/interfaces/IStrategyManager.sol"; -import "../../contracts/interfaces/IStrategy.sol"; -import "../../contracts/interfaces/IDelegationManager.sol"; -import "../../../script/whitelist/Staker.sol"; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; - -interface IWhitelister { - function whitelist(address operator) external; - - function getStaker(address operator) external returns (address); - - function depositIntoStrategy( - address staker, - IStrategy strategy, - IERC20 token, - uint256 amount - ) external returns (bytes memory); - - function queueWithdrawal( - address staker, - IDelegationManager.QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) external returns (bytes memory); - - function completeQueuedWithdrawal( - address staker, - IDelegationManager.Withdrawal calldata queuedWithdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external returns (bytes memory); - - function transfer(address staker, address token, address to, uint256 amount) external returns (bytes memory); - - function callAddress(address to, bytes memory data) external payable returns (bytes memory); -} diff --git a/src/test/DelegationFaucet.t.sol b/src/test/DelegationFaucet.t.sol deleted file mode 100644 index c611b8669..000000000 --- a/src/test/DelegationFaucet.t.sol +++ /dev/null @@ -1,513 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "script/whitelist/delegationFaucet/DelegationFaucet.sol"; -import "script/whitelist/ERC20PresetMinterPauser.sol"; - -import "src/test/EigenLayerTestHelper.t.sol"; - -contract DelegationFaucetTests is EigenLayerTestHelper { - // EigenLayer contracts - DelegationFaucet delegationFaucet; - - // M2 testing/mock contracts - ERC20PresetMinterPauser public stakeToken; - StrategyBase public stakeTokenStrat; - - bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); - uint256 public constant DEFAULT_AMOUNT = 100e18; - address owner = cheats.addr(1000); - - /// @notice Emitted when a queued withdrawal is completed - event WithdrawalCompleted(bytes32 withdrawalRoot); - - function setUp() public virtual override { - EigenLayerDeployer.setUp(); - - // Deploy ERC20 stakeToken, StrategyBase, and add StrategyBase to whitelist - stakeToken = new ERC20PresetMinterPauser("StakeToken", "STK"); - stakeTokenStrat = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(baseStrategyImplementation), - address(eigenLayerProxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, stakeToken, eigenLayerPauserReg) - ) - ) - ); - cheats.startPrank(strategyManager.strategyWhitelister()); - IStrategy[] memory _strategy = new IStrategy[](1); - bool[] memory _thirdPartyTransfersForbiddenValues = new bool[](1); - _strategy[0] = stakeTokenStrat; - strategyManager.addStrategiesToDepositWhitelist(_strategy, _thirdPartyTransfersForbiddenValues); - cheats.stopPrank(); - - // Deploy DelegationFaucet, grant it admin/mint/pauser roles, etc. - delegationFaucet = new DelegationFaucet(strategyManager, delegation, stakeToken, stakeTokenStrat); - targetContract(address(delegationFaucet)); - stakeToken.grantRole(MINTER_ROLE, address(delegationFaucet)); - } - - /** - * @notice Assertions in test - * - Checks staker contract is deployed - * - Checks token supply before/after minting - * - Checks token balances are updated correctly for staker and strategy contracts - * @param _operatorIndex is the index of the operator to use from the test-data/operators.json file - * @param _depositAmount is the amount of stakeToken to mint to the staker and deposit into the strategy - */ - function test_mintDepositAndDelegate_CheckBalancesAndDeploys(uint8 _operatorIndex, uint256 _depositAmount) public { - cheats.assume(_operatorIndex < 15 && _depositAmount < DEFAULT_AMOUNT); - if (_depositAmount == 0) { - // Passing 0 as amount param defaults the amount to DEFAULT_AMOUNT constant - _depositAmount = DEFAULT_AMOUNT; - } - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 supplyBefore = stakeToken.totalSupply(); - uint256 stratBalanceBefore = stakeToken.balanceOf(address(stakeTokenStrat)); - assertTrue( - !Address.isContract(stakerContract), - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: staker contract shouldn't be deployed" - ); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), _depositAmount); - assertTrue( - Address.isContract(stakerContract), - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: staker contract not deployed" - ); - uint256 supplyAfter = stakeToken.totalSupply(); - uint256 stratBalanceAfter = stakeToken.balanceOf(address(stakeTokenStrat)); - // Check token supply and balances - assertEq( - supplyAfter, - supplyBefore + _depositAmount, - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: token supply not updated correctly" - ); - assertEq( - stratBalanceAfter, - stratBalanceBefore + _depositAmount, - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: strategy balance not updated correctly" - ); - assertEq( - stakeToken.balanceOf(stakerContract), - 0, - "test_mintDepositAndDelegate_CheckBalancesAndDeploys: staker balance should be 0" - ); - } - - /** - * @notice Check the before/after values for strategy shares and operator shares - * @param _operatorIndex is the index of the operator to use from the test-data/operators.json file - * @param _depositAmount is the amount of stakeToken to mint to the staker and deposit into the strategy - */ - function test_mintDepositAndDelegate_StrategyAndOperatorShares( - uint8 _operatorIndex, - uint256 _depositAmount - ) public { - cheats.assume(_operatorIndex < 15 && _depositAmount < DEFAULT_AMOUNT); - if (_depositAmount == 0) { - _depositAmount = DEFAULT_AMOUNT; - } - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), _depositAmount); - - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - assertTrue( - delegation.delegatedTo(stakerContract) == operator, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated address not set appropriately" - ); - assertTrue( - delegation.isDelegated(stakerContract), - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated status not set appropriately" - ); - assertEq( - stakerSharesAfter, - stakerSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: operator shares not updated correctly" - ); - } - - /** - * @notice Invariant test the before/after values for strategy shares and operator shares from multiple runs - */ - /// forge-config: default.invariant.runs = 5 - /// forge-config: default.invariant.depth = 20 - function invariant_test_mintDepositAndDelegate_StrategyAndOperatorShares() public { - // Setup Operator - address operator = getOperatorAddress(0); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - cheats.prank(delegationFaucet.owner()); - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - assertTrue( - delegation.delegatedTo(stakerContract) == operator, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated address not set appropriately" - ); - assertTrue( - delegation.isDelegated(stakerContract), - "test_mintDepositAndDelegate_StrategyAndOperatorShares: delegated status not set appropriately" - ); - assertEq( - stakerSharesAfter, - stakerSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_StrategyAndOperatorShares: operator shares not updated correctly" - ); - } - - /** - * @param _operatorIndex is the index of the operator to use from the test-data/operators.json file - */ - function test_mintDepositAndDelegate_RevertsIf_UnregisteredOperator(uint8 _operatorIndex) public { - cheats.assume(_operatorIndex < 15); - address operator = getOperatorAddress(_operatorIndex); - // Unregistered operator should revert - cheats.expectRevert("DelegationFaucet: Operator not registered"); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - } - - function test_depositIntoStrategy_IncreaseShares(uint8 _operatorIndex, uint256 _depositAmount) public { - cheats.assume(_operatorIndex < 15 && _depositAmount < DEFAULT_AMOUNT); - if (_depositAmount == 0) { - _depositAmount = DEFAULT_AMOUNT; - } - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - assertTrue( - delegation.delegatedTo(stakerContract) == operator, - "test_mintDepositAndDelegate_IncreaseShares: delegated address not set appropriately" - ); - assertTrue( - delegation.isDelegated(stakerContract), - "test_mintDepositAndDelegate_IncreaseShares: delegated status not set appropriately" - ); - assertEq( - stakerSharesAfter, - stakerSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_IncreaseShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + DEFAULT_AMOUNT, - "test_mintDepositAndDelegate_IncreaseShares: operator shares not updated correctly" - ); - - // Deposit more into strategy - stakerSharesBefore = stakerSharesAfter; - operatorSharesBefore = operatorSharesAfter; - delegationFaucet.depositIntoStrategy(stakerContract, stakeTokenStrat, stakeToken, _depositAmount); - stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - - assertEq( - stakerSharesAfter, - stakerSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_IncreasesShares: staker shares not updated correctly" - ); - assertEq( - operatorSharesAfter, - operatorSharesBefore + _depositAmount, - "test_mintDepositAndDelegate_IncreasesShares: operator shares not updated correctly" - ); - } - - function test_queueWithdrawal_StakeTokenWithdraw(uint8 _operatorIndex, uint256 _withdrawAmount) public { - cheats.assume(_operatorIndex < 15 && 0 < _withdrawAmount && _withdrawAmount < DEFAULT_AMOUNT); - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - uint256 operatorSharesBefore = delegation.operatorShares(operator, stakeTokenStrat); - uint256 stakerSharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 nonceBefore = delegation.cumulativeWithdrawalsQueued(/*staker*/ stakerContract); - - // Queue withdrawal - ( - IDelegationManager.Withdrawal memory queuedWithdrawal, - , /*tokensArray is unused in this test*/ - /*withdrawalRoot is unused in this test*/ - ) = _setUpQueuedWithdrawalStructSingleStrat( - /*staker*/ stakerContract, - /*withdrawer*/ stakerContract, - stakeToken, - stakeTokenStrat, - _withdrawAmount - ); - IDelegationManager.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); - - params[0] = IDelegationManager.QueuedWithdrawalParams({ - strategies: queuedWithdrawal.strategies, - shares: queuedWithdrawal.shares, - withdrawer: stakerContract - }); - - delegationFaucet.queueWithdrawal( - stakerContract, - params - ); - uint256 operatorSharesAfter = delegation.operatorShares(operator, stakeTokenStrat); - uint256 stakerSharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 nonceAfter = delegation.cumulativeWithdrawalsQueued(/*staker*/ stakerContract); - - assertEq( - operatorSharesBefore, - operatorSharesAfter + _withdrawAmount, - "test_queueWithdrawal_WithdrawStakeToken: operator shares not updated correctly" - ); - // Withdrawal queued, but not withdrawn as of yet - assertEq( - stakerSharesBefore, - stakerSharesAfter + _withdrawAmount, - "test_queueWithdrawal_WithdrawStakeToken: staker shares not updated correctly" - ); - assertEq( - nonceBefore, - nonceAfter - 1, - "test_queueWithdrawal_WithdrawStakeToken: staker withdrawal nonce not updated" - ); - } - - function test_completeQueuedWithdrawal_ReceiveAsTokensMarkedFalse( - uint8 _operatorIndex, - uint256 _withdrawAmount - ) public { - test_queueWithdrawal_StakeTokenWithdraw(_operatorIndex, _withdrawAmount); - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - // assertion before values - uint256 sharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceBefore = stakeToken.balanceOf(address(stakerContract)); - - // Set completeQueuedWithdrawal params - IStrategy[] memory strategyArray = new IStrategy[](1); - IERC20[] memory tokensArray = new IERC20[](1); - uint256[] memory shareAmounts = new uint256[](1); - { - strategyArray[0] = stakeTokenStrat; - shareAmounts[0] = _withdrawAmount; - tokensArray[0] = stakeToken; - } - - IDelegationManager.Withdrawal memory queuedWithdrawal; - { - uint256 nonce = delegation.cumulativeWithdrawalsQueued(stakerContract); - - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: stakerContract, - withdrawer: stakerContract, - nonce: (nonce - 1), - startBlock: uint32(block.number), - delegatedTo: strategyManager.delegation().delegatedTo(stakerContract) - }); - } - cheats.expectEmit(true, true, true, true, address(delegation)); - emit WithdrawalCompleted(delegation.calculateWithdrawalRoot(queuedWithdrawal)); - uint256 middlewareTimesIndex = 0; - bool receiveAsTokens = false; - delegationFaucet.completeQueuedWithdrawal( - stakerContract, - queuedWithdrawal, - tokensArray, - middlewareTimesIndex, - receiveAsTokens - ); - // assertion after values - uint256 sharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceAfter = stakeToken.balanceOf(address(stakerContract)); - assertEq( - sharesBefore + _withdrawAmount, - sharesAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedFalse: staker shares not updated correctly" - ); - assertEq( - balanceBefore, - balanceAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedFalse: stakerContract balance not updated correctly" - ); - } - - function test_completeQueuedWithdrawal_ReceiveAsTokensMarkedTrue( - uint8 _operatorIndex, - uint256 _withdrawAmount - ) public { - test_queueWithdrawal_StakeTokenWithdraw(_operatorIndex, _withdrawAmount); - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - // assertion before values - uint256 sharesBefore = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceBefore = stakeToken.balanceOf(address(stakerContract)); - - // Set completeQueuedWithdrawal params - IStrategy[] memory strategyArray = new IStrategy[](1); - IERC20[] memory tokensArray = new IERC20[](1); - uint256[] memory shareAmounts = new uint256[](1); - { - strategyArray[0] = stakeTokenStrat; - shareAmounts[0] = _withdrawAmount; - tokensArray[0] = stakeToken; - } - - IDelegationManager.Withdrawal memory queuedWithdrawal; - { - uint256 nonce = delegation.cumulativeWithdrawalsQueued(stakerContract); - - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: stakerContract, - withdrawer: stakerContract, - nonce: (nonce - 1), - startBlock: uint32(block.number), - delegatedTo: strategyManager.delegation().delegatedTo(stakerContract) - }); - } - cheats.expectEmit(true, true, true, true, address(delegation)); - emit WithdrawalCompleted(delegation.calculateWithdrawalRoot(queuedWithdrawal)); - uint256 middlewareTimesIndex = 0; - bool receiveAsTokens = true; - delegationFaucet.completeQueuedWithdrawal( - stakerContract, - queuedWithdrawal, - tokensArray, - middlewareTimesIndex, - receiveAsTokens - ); - // assertion after values - uint256 sharesAfter = strategyManager.stakerStrategyShares(stakerContract, stakeTokenStrat); - uint256 balanceAfter = stakeToken.balanceOf(address(stakerContract)); - assertEq( - sharesBefore, - sharesAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedTrue: staker shares not updated correctly" - ); - assertEq( - balanceBefore + _withdrawAmount, - balanceAfter, - "test_completeQueuedWithdrawal_ReceiveAsTokensMarkedTrue: stakerContract balance not updated correctly" - ); - } - - function test_transfer_TransfersERC20(uint8 _operatorIndex, address _to, uint256 _transferAmount) public { - cheats.assume(_operatorIndex < 15); - // Setup Operator - address operator = getOperatorAddress(_operatorIndex); - address stakerContract = delegationFaucet.getStaker(operator); - _registerOperator(operator); - - // Mint token to Staker, deposit minted amount into strategy, and delegate to operator - IDelegationManager.SignatureWithExpiry memory signatureWithExpiry; - delegationFaucet.mintDepositAndDelegate(operator, signatureWithExpiry, bytes32(0), DEFAULT_AMOUNT); - - ERC20PresetMinterPauser mockToken = new ERC20PresetMinterPauser("MockToken", "MTK"); - mockToken.mint(stakerContract, _transferAmount); - - uint256 stakerBalanceBefore = mockToken.balanceOf(stakerContract); - uint256 toBalanceBefore = mockToken.balanceOf(_to); - delegationFaucet.transfer(stakerContract, address(mockToken), _to, _transferAmount); - uint256 stakerBalanceAfter = mockToken.balanceOf(stakerContract); - uint256 toBalanceAfter = mockToken.balanceOf(_to); - assertEq( - stakerBalanceBefore, - stakerBalanceAfter + _transferAmount, - "test_transfer_TransfersERC20: staker balance not updated correctly" - ); - assertEq( - toBalanceBefore + _transferAmount, - toBalanceAfter, - "test_transfer_TransfersERC20: to balance not updated correctly" - ); - } - - function _registerOperator(address _operator) internal { - IDelegationManager.OperatorDetails memory operatorDetails = IDelegationManager.OperatorDetails({ - __deprecated_earningsReceiver: _operator, - delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 - }); - _testRegisterAsOperator(_operator, operatorDetails); - } - - function _setUpQueuedWithdrawalStructSingleStrat( - address staker, - address withdrawer, - IERC20 token, - IStrategy strategy, - uint256 shareAmount - ) - internal - view - returns ( - IDelegationManager.Withdrawal memory queuedWithdrawal, - IERC20[] memory tokensArray, - bytes32 withdrawalRoot - ) - { - IStrategy[] memory strategyArray = new IStrategy[](1); - tokensArray = new IERC20[](1); - uint256[] memory shareAmounts = new uint256[](1); - strategyArray[0] = strategy; - tokensArray[0] = token; - shareAmounts[0] = shareAmount; - queuedWithdrawal = IDelegationManager.Withdrawal({ - strategies: strategyArray, - shares: shareAmounts, - staker: staker, - withdrawer: withdrawer, - nonce: delegation.cumulativeWithdrawalsQueued(staker), - startBlock: uint32(block.number), - delegatedTo: strategyManager.delegation().delegatedTo(staker) - }); - // calculate the withdrawal root - withdrawalRoot = delegation.calculateWithdrawalRoot(queuedWithdrawal); - return (queuedWithdrawal, tokensArray, withdrawalRoot); - } -}