diff --git a/contracts/evm/script/SFFLDeployer.s.sol b/contracts/evm/script/deploy/devnet/SFFLDeployer.s.sol similarity index 85% rename from contracts/evm/script/SFFLDeployer.s.sol rename to contracts/evm/script/deploy/devnet/SFFLDeployer.s.sol index b5f7c685..7e6b4385 100644 --- a/contracts/evm/script/SFFLDeployer.s.sol +++ b/contracts/evm/script/deploy/devnet/SFFLDeployer.s.sol @@ -22,21 +22,20 @@ import {IndexRegistry} from "eigenlayer-middleware/src/IndexRegistry.sol"; import {StakeRegistry} from "eigenlayer-middleware/src/StakeRegistry.sol"; import {OperatorStateRetriever} from "eigenlayer-middleware/src/OperatorStateRetriever.sol"; -import {RegistryCoordinator} from "../src/external/RegistryCoordinator.sol"; -import {SFFLServiceManager} from "../src/eth/SFFLServiceManager.sol"; -import {SFFLTaskManager} from "../src/eth/SFFLTaskManager.sol"; -import {SFFLRegistryCoordinator} from "../src/eth/SFFLRegistryCoordinator.sol"; -import {SFFLOperatorSetUpdateRegistry} from "../src/eth/SFFLOperatorSetUpdateRegistry.sol"; -import {ERC20Mock, IERC20} from "../test/mock/ERC20Mock.sol"; +import {RegistryCoordinator} from "../../../src/external/RegistryCoordinator.sol"; +import {SFFLServiceManager} from "../../../src/eth/SFFLServiceManager.sol"; +import {SFFLTaskManager} from "../../../src/eth/SFFLTaskManager.sol"; +import {SFFLRegistryCoordinator} from "../../../src/eth/SFFLRegistryCoordinator.sol"; +import {SFFLOperatorSetUpdateRegistry} from "../../../src/eth/SFFLOperatorSetUpdateRegistry.sol"; +import {ERC20Mock, IERC20} from "../../../test/mock/ERC20Mock.sol"; -import {Utils} from "./utils/Utils.sol"; +import {Utils} from "../../utils/Utils.sol"; import "forge-std/Test.sol"; import "forge-std/Script.sol"; import "forge-std/StdJson.sol"; import "forge-std/console.sol"; -// forge script script/SFFLDeployer.s.sol:SFFLDeployer --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast -vvvv contract SFFLDeployer is Script, Utils { uint256 public constant QUORUM_THRESHOLD_PERCENTAGE = 100; uint32 public constant TASK_RESPONSE_WINDOW_BLOCK = 30; @@ -197,6 +196,7 @@ contract SFFLDeployer is Script, Utils { /** * @dev Deploys the SFFL contracts. * @param delegationManager The delegation manager. + * @param avsDirectory The AVS directory. * @param strat The deployed strategy. * @param sfflCommunityMultisig The community multisig. * @param sfflPauser The pauser. @@ -219,25 +219,25 @@ contract SFFLDeployer is Script, Utils { sfflPauserReg = new PauserRegistry(pausers, sfflCommunityMultisig); - sfflServiceManagerProxy = _deployEmptyProxy(sfflProxyAdmin); + sfflServiceManagerProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); sfflServiceManager = SFFLServiceManager(address(sfflServiceManagerProxy)); - sfflTaskManagerProxy = _deployEmptyProxy(sfflProxyAdmin); + sfflTaskManagerProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); sfflTaskManager = SFFLTaskManager(address(sfflTaskManagerProxy)); - registryCoordinatorProxy = _deployEmptyProxy(sfflProxyAdmin); + registryCoordinatorProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); registryCoordinator = SFFLRegistryCoordinator(address(registryCoordinatorProxy)); - blsApkRegistryProxy = _deployEmptyProxy(sfflProxyAdmin); + blsApkRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); blsApkRegistry = BLSApkRegistry(address(blsApkRegistryProxy)); - indexRegistryProxy = _deployEmptyProxy(sfflProxyAdmin); + indexRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); indexRegistry = IndexRegistry(address(indexRegistryProxy)); - operatorSetUpdateRegistryProxy = _deployEmptyProxy(sfflProxyAdmin); + operatorSetUpdateRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); operatorSetUpdateRegistry = SFFLOperatorSetUpdateRegistry(address(operatorSetUpdateRegistryProxy)); - stakeRegistryProxy = _deployEmptyProxy(sfflProxyAdmin); + stakeRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); stakeRegistry = StakeRegistry(address(stakeRegistryProxy)); operatorStateRetriever = new OperatorStateRetriever(); @@ -332,53 +332,6 @@ contract SFFLDeployer is Script, Utils { _serializeSFFLDeployedContracts(); } - /** - * @dev Deploys a new proxy contract using the given implementation and initialization data. - * @param _impl Address of the implementation contract. - * @param _admin Proxy admin. - * @param _initCode Initialization code. - */ - function _deployProxy(ProxyAdmin _admin, address _impl, bytes memory _initCode) - internal - returns (TransparentUpgradeableProxy) - { - return new TransparentUpgradeableProxy(_impl, address(_admin), _initCode); - } - - /** - * @dev Deploys an empty proxy - i.e. a zero implementation and with no init code - * @param _admin Proxy admin. - */ - function _deployEmptyProxy(ProxyAdmin _admin) internal returns (TransparentUpgradeableProxy) { - return new TransparentUpgradeableProxy(address(emptyContract), address(_admin), ""); - } - - /** - * @dev Upgrades a proxy to a new implementation. - * @param _admin Proxy admin. - * @param _proxy The proxy to upgrade. - * @param _impl The new implementation to upgrade to. - */ - function _upgradeProxy(ProxyAdmin _admin, TransparentUpgradeableProxy _proxy, address _impl) internal { - _admin.upgrade(_proxy, _impl); - } - - /** - * @dev Upgrades a proxy to a new impl and calls a function on the implementation. - * @param _admin Proxy admin. - * @param _proxy The proxy to upgrade. - * @param _impl The new impl to upgrade to. - * @param _data The encoded calldata to use in the call after upgrading. - */ - function _upgradeProxyAndCall( - ProxyAdmin _admin, - TransparentUpgradeableProxy _proxy, - address _impl, - bytes memory _data - ) internal { - _admin.upgradeAndCall(_proxy, _impl, _data); - } - /** * @dev Serializes the SFFL deployed contracts to the forge output. */ diff --git a/contracts/evm/script/deploy/devnet/SFFLDeployerRollup.s.sol b/contracts/evm/script/deploy/devnet/SFFLDeployerRollup.s.sol new file mode 100644 index 00000000..542224fc --- /dev/null +++ b/contracts/evm/script/deploy/devnet/SFFLDeployerRollup.s.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {ProxyAdmin, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +import {PauserRegistry} from "@eigenlayer/contracts/permissions/PauserRegistry.sol"; + +import {SFFLRegistryRollup} from "../../../src/rollup/SFFLRegistryRollup.sol"; + +import {Utils} from "../../utils/Utils.sol"; + +import "forge-std/Test.sol"; +import "forge-std/Script.sol"; +import "forge-std/StdJson.sol"; +import "forge-std/console.sol"; + +contract SFFLDeployerRollup is Script, Utils { + uint256 public constant QUORUM_THRESHOLD_PERCENTAGE = 66; + address public constant AGGREGATOR_ADDR = 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720; + + ProxyAdmin public sfflProxyAdmin; + PauserRegistry public sfflPauserReg; + + SFFLRegistryRollup public sfflRegistryRollup; + TransparentUpgradeableProxy public sfflRegistryRollupProxy; + address public sfflRegistryRollupImpl; + + string public constant SFFL_DEPLOYMENT_FILE = "sffl_rollup_deployment_output"; + + function run() external { + address sfflCommunityMultisig = msg.sender; + address sfflPauser = msg.sender; + + vm.startBroadcast(); + + sfflProxyAdmin = new ProxyAdmin(); + + address[] memory pausers = new address[](2); + pausers[0] = sfflPauser; + pausers[1] = sfflCommunityMultisig; + + sfflPauserReg = new PauserRegistry(pausers, sfflCommunityMultisig); + + sfflRegistryRollupImpl = address(new SFFLRegistryRollup()); + sfflRegistryRollupProxy = _deployProxy( + sfflProxyAdmin, + sfflRegistryRollupImpl, + abi.encodeWithSelector( + SFFLRegistryRollup.initialize.selector, + QUORUM_THRESHOLD_PERCENTAGE, + sfflCommunityMultisig, + AGGREGATOR_ADDR, + sfflPauserReg + ) + ); + sfflRegistryRollup = SFFLRegistryRollup(address(sfflRegistryRollupProxy)); + + _serializeSFFLDeployedContracts(); + + vm.stopBroadcast(); + } + + /** + * @dev Serializes the SFFL deployed contracts to the forge output. + */ + function _serializeSFFLDeployedContracts() internal { + string memory parent_object = "parent object"; + string memory addresses = "addresses"; + + string memory output; + + output = vm.serializeAddress(addresses, "deployer", address(msg.sender)); + output = vm.serializeAddress(addresses, "sfflProxyAdmin", address(sfflProxyAdmin)); + output = vm.serializeAddress(addresses, "sfflPauserReg", address(sfflPauserReg)); + output = vm.serializeAddress(addresses, "sfflRegistryRollup", address(sfflRegistryRollup)); + output = vm.serializeAddress(addresses, "sfflRegistryRollupImpl", address(sfflRegistryRollupImpl)); + + string memory finalJson = vm.serializeString(parent_object, addresses, output); + + writeOutput(finalJson, SFFL_DEPLOYMENT_FILE); + } +} diff --git a/contracts/evm/script/deploy/holesky/SFFLDeployer.s.sol b/contracts/evm/script/deploy/holesky/SFFLDeployer.s.sol new file mode 100644 index 00000000..b593ad11 --- /dev/null +++ b/contracts/evm/script/deploy/holesky/SFFLDeployer.s.sol @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {ProxyAdmin, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +import {PauserRegistry} from "@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 {EmptyContract} from "@eigenlayer/test/mocks/EmptyContract.sol"; + +import { + IBLSApkRegistry, + IIndexRegistry, + IStakeRegistry, + IRegistryCoordinator +} 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 {OperatorStateRetriever} from "eigenlayer-middleware/src/OperatorStateRetriever.sol"; + +import {RegistryCoordinator} from "../../../src/external/RegistryCoordinator.sol"; +import {SFFLServiceManager} from "../../../src/eth/SFFLServiceManager.sol"; +import {SFFLTaskManager} from "../../../src/eth/SFFLTaskManager.sol"; +import {SFFLRegistryCoordinator} from "../../../src/eth/SFFLRegistryCoordinator.sol"; +import {SFFLOperatorSetUpdateRegistry} from "../../../src/eth/SFFLOperatorSetUpdateRegistry.sol"; +import {ERC20Mock, IERC20} from "../../../test/mock/ERC20Mock.sol"; + +import {Utils} from "../../utils/Utils.sol"; + +import "forge-std/Test.sol"; +import "forge-std/Script.sol"; +import "forge-std/StdJson.sol"; +import "forge-std/console.sol"; + +contract SFFLDeployer is Script, Utils { + uint256 public constant QUORUM_THRESHOLD_PERCENTAGE = 66; + uint32 public constant TASK_RESPONSE_WINDOW_BLOCK = 100; + + uint32 public constant MAX_OPERATOR_COUNT = 10; + uint16 public constant KICK_BIPS_OF_OPERATOR_STAKE = 15000; + uint16 public constant KICK_BIPS_OF_TOTAL_STAKE = 100; + + uint96 public constant STRATEGY_MULTIPLIER = 1 ether; + uint256 public constant WEIGHTING_DIVISOR = 1 ether; + + uint256 public constant NUM_QUORUMS = 1; + uint256 public constant INITIAL_PAUSED_STATUS = 0; + + // TODO: right now hardcoding these + address public constant AGGREGATOR_ADDR = 0xEEa35C4E6F933fC04c853a371e170eDA1124c10d; + address public constant TASK_GENERATOR_ADDR = 0xEEa35C4E6F933fC04c853a371e170eDA1124c10d; + + string public constant EIGENLAYER_DEPLOYMENT_FILE = "eigenlayer_deployment_output"; + string public constant SFFL_DEPLOYMENT_FILE = "sffl_avs_deployment_output"; + + struct EigenlayerDeployedContracts { + IStrategyManager strategyManager; + IDelegationManager delegationManager; + IAVSDirectory avsDirectory; + ProxyAdmin eigenLayerProxyAdmin; + PauserRegistry eigenLayerPauserReg; + StrategyBaseTVLLimits baseStrategyImpl; + } + + EmptyContract public emptyContract; + IStrategy[] strategies; + + // SFFL contracts + ProxyAdmin public sfflProxyAdmin; + PauserRegistry public sfflPauserReg; + + SFFLRegistryCoordinator public registryCoordinator; + TransparentUpgradeableProxy public registryCoordinatorProxy; + address public registryCoordinatorImpl; + + IBLSApkRegistry public blsApkRegistry; + TransparentUpgradeableProxy public blsApkRegistryProxy; + address public blsApkRegistryImpl; + + IIndexRegistry public indexRegistry; + TransparentUpgradeableProxy public indexRegistryProxy; + address public indexRegistryImpl; + + IStakeRegistry public stakeRegistry; + TransparentUpgradeableProxy public stakeRegistryProxy; + address public stakeRegistryImpl; + + SFFLOperatorSetUpdateRegistry public operatorSetUpdateRegistry; + TransparentUpgradeableProxy public operatorSetUpdateRegistryProxy; + address public operatorSetUpdateRegistryImpl; + + SFFLServiceManager public sfflServiceManager; + TransparentUpgradeableProxy public sfflServiceManagerProxy; + address public sfflServiceManagerImpl; + + SFFLTaskManager public sfflTaskManager; + TransparentUpgradeableProxy public sfflTaskManagerProxy; + address public sfflTaskManagerImpl; + + OperatorStateRetriever public operatorStateRetriever; + + function run() external { + EigenlayerDeployedContracts memory eigenlayerContracts = _readEigenlayerDeployedContracts(); + + address sfflCommunityMultisig = msg.sender; + address sfflPauser = msg.sender; + + // from the table in https://github.com/Layr-Labs/eigenlayer-contracts/blob/7229f2b426b6f2a24c7795b1a4687a010eac8ef2/README.md + strategies.push(IStrategy(0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3)); + strategies.push(IStrategy(0x3A8fBdf9e77DFc25d09741f51d3E181b25d0c4E0)); + strategies.push(IStrategy(0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9)); + strategies.push(IStrategy(0x05037A81BD7B4C9E0F7B430f1F2A22c31a2FD943)); + strategies.push(IStrategy(0x9281ff96637710Cd9A5CAcce9c6FAD8C9F54631c)); + strategies.push(IStrategy(0x31B6F59e1627cEfC9fA174aD03859fC337666af7)); + strategies.push(IStrategy(0x46281E3B7fDcACdBa44CADf069a94a588Fd4C6Ef)); + strategies.push(IStrategy(0x70EB4D3c164a6B4A5f908D4FBb5a9cAfFb66bAB6)); + strategies.push(IStrategy(0xaccc5A86732BE85b5012e8614AF237801636F8e5)); + strategies.push(IStrategy(0x7673a47463F80c6a3553Db9E54c8cDcd5313d0ac)); + strategies.push(IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0)); + + vm.startBroadcast(); + + emptyContract = new EmptyContract(); + + _deploySFFLContracts( + eigenlayerContracts.delegationManager, eigenlayerContracts.avsDirectory, sfflCommunityMultisig, sfflPauser + ); + + _whitelistOperators(); + vm.stopBroadcast(); + } + + /** + * @dev Reads the output of the Eigenlayer deployment script from the forge output and returns the EL deployed contracts. + */ + function _readEigenlayerDeployedContracts() internal view returns (EigenlayerDeployedContracts memory) { + string memory json = readOutput(EIGENLAYER_DEPLOYMENT_FILE); + return EigenlayerDeployedContracts({ + strategyManager: IStrategyManager(stdJson.readAddress(json, ".addresses.strategyManager")), + delegationManager: IDelegationManager(stdJson.readAddress(json, ".addresses.delegationManager")), + avsDirectory: IAVSDirectory(stdJson.readAddress(json, ".addresses.avsDirectory")), + eigenLayerProxyAdmin: ProxyAdmin(stdJson.readAddress(json, ".addresses.eigenLayerProxyAdmin")), + eigenLayerPauserReg: PauserRegistry(stdJson.readAddress(json, ".addresses.eigenLayerPauserReg")), + baseStrategyImpl: StrategyBaseTVLLimits(stdJson.readAddress(json, ".addresses.baseStrategyImplementation")) + }); + } + + function _whitelistOperators() internal { + // from keys in tests/keys/ecdsa + operatorSetUpdateRegistry.setOperatorWhitelisting(0xBF1BC6C45051E4330c3Ad921C78DCb242a1C2be6, true); + operatorSetUpdateRegistry.setOperatorWhitelisting(0xE7444212A0d2394Ab25888F2371548837c410a5d, true); + } + + /** + * @dev Deploys the SFFL contracts. + * @param delegationManager The delegation manager. + * @param avsDirectory The AVS directory. + * @param sfflCommunityMultisig The community multisig. + * @param sfflPauser The pauser. + */ + function _deploySFFLContracts( + IDelegationManager delegationManager, + IAVSDirectory avsDirectory, + address sfflCommunityMultisig, + address sfflPauser + ) internal { + sfflProxyAdmin = new ProxyAdmin(); + + address[] memory pausers = new address[](2); + pausers[0] = sfflPauser; + pausers[1] = sfflCommunityMultisig; + + sfflPauserReg = new PauserRegistry(pausers, sfflCommunityMultisig); + + sfflServiceManagerProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + sfflServiceManager = SFFLServiceManager(address(sfflServiceManagerProxy)); + + sfflTaskManagerProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + sfflTaskManager = SFFLTaskManager(address(sfflTaskManagerProxy)); + + registryCoordinatorProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + registryCoordinator = SFFLRegistryCoordinator(address(registryCoordinatorProxy)); + + blsApkRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + blsApkRegistry = BLSApkRegistry(address(blsApkRegistryProxy)); + + indexRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + indexRegistry = IndexRegistry(address(indexRegistryProxy)); + + operatorSetUpdateRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + operatorSetUpdateRegistry = SFFLOperatorSetUpdateRegistry(address(operatorSetUpdateRegistryProxy)); + + stakeRegistryProxy = _deployEmptyProxy(sfflProxyAdmin, address(emptyContract)); + stakeRegistry = StakeRegistry(address(stakeRegistryProxy)); + + operatorStateRetriever = new OperatorStateRetriever(); + + stakeRegistryImpl = address(new StakeRegistry(registryCoordinator, delegationManager)); + _upgradeProxy(sfflProxyAdmin, stakeRegistryProxy, stakeRegistryImpl); + + blsApkRegistryImpl = address(new BLSApkRegistry(registryCoordinator)); + _upgradeProxy(sfflProxyAdmin, blsApkRegistryProxy, blsApkRegistryImpl); + + indexRegistryImpl = address(new IndexRegistry(registryCoordinator)); + _upgradeProxy(sfflProxyAdmin, indexRegistryProxy, indexRegistryImpl); + + operatorSetUpdateRegistryImpl = address(new SFFLOperatorSetUpdateRegistry(registryCoordinator)); + _upgradeProxy(sfflProxyAdmin, operatorSetUpdateRegistryProxy, operatorSetUpdateRegistryImpl); + + registryCoordinatorImpl = address( + new SFFLRegistryCoordinator( + sfflServiceManager, stakeRegistry, blsApkRegistry, indexRegistry, operatorSetUpdateRegistry + ) + ); + + IRegistryCoordinator.OperatorSetParam[] memory quorumsOperatorSetParams = + new IRegistryCoordinator.OperatorSetParam[](NUM_QUORUMS); + + for (uint256 i = 0; i < quorumsOperatorSetParams.length; i++) { + quorumsOperatorSetParams[i] = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: MAX_OPERATOR_COUNT, + kickBIPsOfOperatorStake: KICK_BIPS_OF_OPERATOR_STAKE, + kickBIPsOfTotalStake: KICK_BIPS_OF_TOTAL_STAKE + }); + } + + uint96[] memory quorumsMinimumStake = new uint96[](NUM_QUORUMS); + IStakeRegistry.StrategyParams[][] memory quorumsStrategyParams = + new IStakeRegistry.StrategyParams[][](NUM_QUORUMS); + + for (uint256 i = 0; i < quorumsStrategyParams.length; i++) { + quorumsStrategyParams[i] = new IStakeRegistry.StrategyParams[](strategies.length); + + for (uint256 j = 0; j < quorumsStrategyParams[i].length; j++) { + quorumsStrategyParams[i][j] = + IStakeRegistry.StrategyParams({strategy: strategies[j], multiplier: STRATEGY_MULTIPLIER}); + } + } + + _upgradeProxyAndCall( + sfflProxyAdmin, + registryCoordinatorProxy, + registryCoordinatorImpl, + abi.encodeWithSelector( + registryCoordinator.initialize.selector, + sfflCommunityMultisig, + sfflCommunityMultisig, + sfflCommunityMultisig, + sfflPauserReg, + INITIAL_PAUSED_STATUS, + quorumsOperatorSetParams, + quorumsMinimumStake, + quorumsStrategyParams + ) + ); + + sfflServiceManagerImpl = address( + new SFFLServiceManager( + avsDirectory, registryCoordinator, stakeRegistry, sfflTaskManager, operatorSetUpdateRegistry + ) + ); + + _upgradeProxyAndCall( + sfflProxyAdmin, + sfflServiceManagerProxy, + sfflServiceManagerImpl, + abi.encodeWithSignature("initialize(address,address)", sfflCommunityMultisig, sfflPauserReg) + ); + + sfflTaskManagerImpl = address(new SFFLTaskManager(registryCoordinator, TASK_RESPONSE_WINDOW_BLOCK)); + + _upgradeProxyAndCall( + sfflProxyAdmin, + sfflTaskManagerProxy, + sfflTaskManagerImpl, + abi.encodeWithSelector( + SFFLTaskManager.initialize.selector, + sfflPauserReg, + sfflCommunityMultisig, + AGGREGATOR_ADDR, + TASK_GENERATOR_ADDR + ) + ); + + _serializeSFFLDeployedContracts(); + } + + /** + * @dev Serializes the SFFL deployed contracts to the forge output. + */ + function _serializeSFFLDeployedContracts() internal { + string memory parent_object = "parent object"; + string memory addresses = "addresses"; + + string memory output; + + output = vm.serializeAddress(addresses, "deployer", address(msg.sender)); + output = vm.serializeAddress(addresses, "sfflProxyAdmin", address(sfflProxyAdmin)); + output = vm.serializeAddress(addresses, "sfflPauserReg", address(sfflPauserReg)); + output = vm.serializeAddress(addresses, "registryCoordinator", address(registryCoordinator)); + output = vm.serializeAddress(addresses, "registryCoordinatorImpl", address(registryCoordinatorImpl)); + output = vm.serializeAddress(addresses, "blsApkRegistry", address(blsApkRegistry)); + output = vm.serializeAddress(addresses, "blsApkRegistryImpl", address(blsApkRegistryImpl)); + output = vm.serializeAddress(addresses, "indexRegistry", address(indexRegistry)); + output = vm.serializeAddress(addresses, "indexRegistryImpl", address(indexRegistryImpl)); + output = vm.serializeAddress(addresses, "stakeRegistry", address(stakeRegistry)); + output = vm.serializeAddress(addresses, "stakeRegistryImpl", address(stakeRegistryImpl)); + output = vm.serializeAddress(addresses, "operatorSetUpdateRegistry", address(operatorSetUpdateRegistry)); + output = vm.serializeAddress(addresses, "operatorSetUpdateRegistryImpl", address(operatorSetUpdateRegistryImpl)); + output = vm.serializeAddress(addresses, "sfflServiceManager", address(sfflServiceManager)); + output = vm.serializeAddress(addresses, "sfflServiceManagerImpl", address(sfflServiceManagerImpl)); + output = vm.serializeAddress(addresses, "sfflTaskManager", address(sfflTaskManager)); + output = vm.serializeAddress(addresses, "sfflTaskManagerImpl", address(sfflTaskManagerImpl)); + output = vm.serializeAddress(addresses, "operatorStateRetriever", address(operatorStateRetriever)); + + string memory finalJson = vm.serializeString(parent_object, addresses, output); + + writeOutput(finalJson, SFFL_DEPLOYMENT_FILE); + } +} diff --git a/contracts/evm/script/deploy/holesky/SFFLDeployerRollup.s.sol b/contracts/evm/script/deploy/holesky/SFFLDeployerRollup.s.sol new file mode 100644 index 00000000..6abd5f8c --- /dev/null +++ b/contracts/evm/script/deploy/holesky/SFFLDeployerRollup.s.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {ProxyAdmin, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +import {PauserRegistry} from "@eigenlayer/contracts/permissions/PauserRegistry.sol"; + +import {SFFLRegistryRollup} from "../../../src/rollup/SFFLRegistryRollup.sol"; + +import {Utils} from "../../utils/Utils.sol"; + +import "forge-std/Test.sol"; +import "forge-std/Script.sol"; +import "forge-std/StdJson.sol"; +import "forge-std/console.sol"; + +contract SFFLDeployerRollup is Script, Utils { + uint256 public constant QUORUM_THRESHOLD_PERCENTAGE = 66; + address public constant AGGREGATOR_ADDR = 0xEEa35C4E6F933fC04c853a371e170eDA1124c10d; + + ProxyAdmin public sfflProxyAdmin; + PauserRegistry public sfflPauserReg; + + SFFLRegistryRollup public sfflRegistryRollup; + TransparentUpgradeableProxy public sfflRegistryRollupProxy; + address public sfflRegistryRollupImpl; + + string public constant SFFL_DEPLOYMENT_FILE = "sffl_rollup_deployment_output"; + + function run() external { + address sfflCommunityMultisig = msg.sender; + address sfflPauser = msg.sender; + + vm.startBroadcast(); + + sfflProxyAdmin = new ProxyAdmin(); + + address[] memory pausers = new address[](2); + pausers[0] = sfflPauser; + pausers[1] = sfflCommunityMultisig; + + sfflPauserReg = new PauserRegistry(pausers, sfflCommunityMultisig); + + sfflRegistryRollupImpl = address(new SFFLRegistryRollup()); + sfflRegistryRollupProxy = _deployProxy( + sfflProxyAdmin, + sfflRegistryRollupImpl, + abi.encodeWithSelector( + SFFLRegistryRollup.initialize.selector, + QUORUM_THRESHOLD_PERCENTAGE, + sfflCommunityMultisig, + AGGREGATOR_ADDR, + sfflPauserReg + ) + ); + sfflRegistryRollup = SFFLRegistryRollup(address(sfflRegistryRollupProxy)); + + _serializeSFFLDeployedContracts(); + + vm.stopBroadcast(); + } + + /** + * @dev Serializes the SFFL deployed contracts to the forge output. + */ + function _serializeSFFLDeployedContracts() internal { + string memory parent_object = "parent object"; + string memory addresses = "addresses"; + + string memory output; + + output = vm.serializeAddress(addresses, "deployer", address(msg.sender)); + output = vm.serializeAddress(addresses, "sfflProxyAdmin", address(sfflProxyAdmin)); + output = vm.serializeAddress(addresses, "sfflPauserReg", address(sfflPauserReg)); + output = vm.serializeAddress(addresses, "sfflRegistryRollup", address(sfflRegistryRollup)); + output = vm.serializeAddress(addresses, "sfflRegistryRollupImpl", address(sfflRegistryRollupImpl)); + + string memory finalJson = vm.serializeString(parent_object, addresses, output); + + writeOutput(finalJson, SFFL_DEPLOYMENT_FILE); + } +} diff --git a/contracts/evm/script/output/11155420/sffl_rollup_deployment_output.json b/contracts/evm/script/output/11155420/sffl_rollup_deployment_output.json new file mode 100644 index 00000000..91381782 --- /dev/null +++ b/contracts/evm/script/output/11155420/sffl_rollup_deployment_output.json @@ -0,0 +1,9 @@ +{ + "addresses": { + "deployer": "0x70d266e7089f15a963638Ec358D5975fc8dAfb6E", + "sfflPauserReg": "0x7E8c0D7f34A2a4FBC384105b32A5051ce46A3E3E", + "sfflProxyAdmin": "0x408dd5765DbE189929a4b2cfc40Ab2F52c310781", + "sfflRegistryRollup": "0x6eB9b1FAdCEE1a722B3bCf82c14b6C0067a7f123", + "sfflRegistryRollupImpl": "0xBB75932Dcf41cCC6C29B45b656d9e53DeCcb3A6E" + } +} \ No newline at end of file diff --git a/contracts/evm/script/output/17000/eigenlayer_deployment_output.json b/contracts/evm/script/output/17000/eigenlayer_deployment_output.json new file mode 100644 index 00000000..ab2c671c --- /dev/null +++ b/contracts/evm/script/output/17000/eigenlayer_deployment_output.json @@ -0,0 +1,55 @@ +{ + "addresses": { + "avsDirectory": "0x055733000064333CaDDbC92763c58BF0192fFeBf", + "avsDirectoryImplementation": "0xEF5BA995Bc7722fd1e163edF8Dc09375de3d3e3a", + "baseStrategyImplementation": "0xFb83e1D133D0157775eC4F19Ff81478Df1103305", + "beaconOracle": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25", + "delayedWithdrawalRouter": "0x642c646053eaf2254f088e9019ACD73d9AE0FA32", + "delayedWithdrawalRouterImplementation": "0xcE8b8D99773a718423F8040a6e52c06a4ce63407", + "delegationManager": "0xA44151489861Fe9e3055d95adC98FbD462B948e7", + "delegationManagerImplementation": "0x83f8F8f0BB125F7870F6bfCf76853f874C330D76", + "eigenLayerPauserReg": "0x85Ef7299F8311B25642679edBF02B62FA2212F06", + "eigenLayerProxyAdmin": "0xDB023566064246399b4AE851197a97729C93A6cf", + "eigenPodBeacon": "0x7261C2bd75a7ACE1762f6d7FAe8F63215581832D", + "eigenPodImplementation": "0xe98f9298344527608A1BCC23907B8145F9Cb641c", + "eigenPodManager": "0x30770d7E3e71112d7A6b7259542D1f680a70e315", + "eigenPodManagerImplementation": "0x5265C162f7d5F3fE3175a78828ab16bf5E324a7B", + "emptyContract": "0x9690d52B1Ce155DB2ec5eCbF5a262ccCc7B3A6D2", + "slasher": "0xcAe751b75833ef09627549868A04E32679386e7C", + "slasherImplementation": "0x99715D255E34a39bE9943b82F281CA734bcF345A", + "strategies": { + "WETH": "0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9", + "rETH": "0x3A8fBdf9e77DFc25d09741f51d3E181b25d0c4E0", + "stETH": "0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3", + "lsETH": "0x05037A81BD7B4C9E0F7B430f1F2A22c31a2FD943", + "frxETH": "0x15F70a41Afe34020B3B16079010D3e88c4A85daf", + "ETHx": "0x31B6F59e1627cEfC9fA174aD03859fC337666af7", + "osETH": "0x46281E3B7fDcACdBa44CADf069a94a588Fd4C6Ef", + "cbETH": "0x70EB4D3c164a6B4A5f908D4FBb5a9cAfFb66bAB6" + }, + "strategyAddresses": [ + "0x3A8fBdf9e77DFc25d09741f51d3E181b25d0c4E0", + "0x80528D6e9A2BAbFc766965E0E26d5aB08D9CFaF9", + "0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3", + "0x05037A81BD7B4C9E0F7B430f1F2A22c31a2FD943", + "0x15F70a41Afe34020B3B16079010D3e88c4A85daf", + "0x31B6F59e1627cEfC9fA174aD03859fC337666af7", + "0x46281E3B7fDcACdBa44CADf069a94a588Fd4C6Ef", + "0x70EB4D3c164a6B4A5f908D4FBb5a9cAfFb66bAB6" + ], + "strategyManager": "0xdfB5f6CE42aAA7830E94ECFCcAd411beF4d4D5b6", + "strategyManagerImplementation": "0x59f766A603C53f3AC8Be43bBe158c1519b193a18" + }, + "numStrategies": 8, + "chainInfo": { + "chainId": 17000, + "deploymentBlock": 1167041 + }, + "parameters": { + "communityMultisig": "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7", + "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", + "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", + "pauserMultisig": "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7", + "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" + } +} \ No newline at end of file diff --git a/contracts/evm/script/output/17000/sffl_avs_deployment_output.json b/contracts/evm/script/output/17000/sffl_avs_deployment_output.json new file mode 100644 index 00000000..975dda6d --- /dev/null +++ b/contracts/evm/script/output/17000/sffl_avs_deployment_output.json @@ -0,0 +1,22 @@ +{ + "addresses": { + "blsApkRegistry": "0xad79Cf487e89a9EFF4D9009941786fe199AC8Cc8", + "blsApkRegistryImpl": "0x7D8d41b1b983b720a3970cA5902c5381cB36b098", + "deployer": "0x70d266e7089f15a963638Ec358D5975fc8dAfb6E", + "indexRegistry": "0x8Fa979b662c7a881435b89DbAC18cd8054a13254", + "indexRegistryImpl": "0x08aA5922785793A90A472A0a581833e74db8939a", + "operatorSetUpdateRegistry": "0x33335e4Be434724cE003B63eAE499Ce7aaee5508", + "operatorSetUpdateRegistryImpl": "0x2C04749e1A69B8E30A345963E4219A4afc5427C6", + "operatorStateRetriever": "0x8fab2e26f88bF284fCc930fD97d3B820b90007D5", + "registryCoordinator": "0xCe0480ae3129f22427BC357Cf4CcC3ae8BcE7397", + "registryCoordinatorImpl": "0x4C5f683AAb3AFC289AfdBB55190c9fBdf083363a", + "sfflPauserReg": "0xBB75932Dcf41cCC6C29B45b656d9e53DeCcb3A6E", + "sfflProxyAdmin": "0x7E8c0D7f34A2a4FBC384105b32A5051ce46A3E3E", + "sfflServiceManager": "0x6eB9b1FAdCEE1a722B3bCf82c14b6C0067a7f123", + "sfflServiceManagerImpl": "0x369ABA1BEa573De5f61Ca6F9638De346709BDC8b", + "sfflTaskManager": "0x1D51F418e227c44eA6667f70DE6faac5244a62d0", + "sfflTaskManagerImpl": "0xad7E2A061E2eB8c73cF62E43f276d86d27678363", + "stakeRegistry": "0xd7AcBEBE84eE95C993CaB4F365CD862D1d278df4", + "stakeRegistryImpl": "0xB410Ce56e65aAbd9fa73eB78FA387716Ef7d0c88" + } +} \ No newline at end of file diff --git a/contracts/evm/script/output/421614/sffl_rollup_deployment_output.json b/contracts/evm/script/output/421614/sffl_rollup_deployment_output.json new file mode 100644 index 00000000..91381782 --- /dev/null +++ b/contracts/evm/script/output/421614/sffl_rollup_deployment_output.json @@ -0,0 +1,9 @@ +{ + "addresses": { + "deployer": "0x70d266e7089f15a963638Ec358D5975fc8dAfb6E", + "sfflPauserReg": "0x7E8c0D7f34A2a4FBC384105b32A5051ce46A3E3E", + "sfflProxyAdmin": "0x408dd5765DbE189929a4b2cfc40Ab2F52c310781", + "sfflRegistryRollup": "0x6eB9b1FAdCEE1a722B3bCf82c14b6C0067a7f123", + "sfflRegistryRollupImpl": "0xBB75932Dcf41cCC6C29B45b656d9e53DeCcb3A6E" + } +} \ No newline at end of file diff --git a/contracts/evm/script/utils/Utils.sol b/contracts/evm/script/utils/Utils.sol index 9a648451..adde5c14 100644 --- a/contracts/evm/script/utils/Utils.sol +++ b/contracts/evm/script/utils/Utils.sol @@ -1,59 +1,12 @@ -// SPDX-License-Identifier: BUSL-1.1 -// Utility contract from EigenLayer's Incredible Squaring AVS: -// https://github.com/Layr-Labs/incredible-squaring-avs/blob/2c21b017da9f7a0df7b2c8896fbabf05fc80137a/contracts/script/utils/Utils.sol - +// SPDX-License-Identifier: MIT pragma solidity =0.8.12; -import {IRegistryCoordinator} from "eigenlayer-middleware/src/interfaces/IRegistryCoordinator.sol"; -import {StrategyBase} from "@eigenlayer/contracts/strategies/StrategyBase.sol"; -import {ERC20Mock} from "../../test/mock/ERC20Mock.sol"; +import {ProxyAdmin, TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "forge-std/Script.sol"; import "forge-std/StdJson.sol"; contract Utils is Script { - // Note that this fct will only work for the ERC20Mock that has a public mint function - function _mintTokens(address strategyAddress, address[] memory tos, uint256[] memory amounts) internal { - for (uint256 i = 0; i < tos.length; i++) { - ERC20Mock underlyingToken = ERC20Mock(address(StrategyBase(strategyAddress).underlyingToken())); - underlyingToken.mint(tos[i], amounts[i]); - } - } - - // TODO: this doesn't actually advance by n blocks... maybe because broadcasting batches txs somehow..? - function advanceChainByNBlocks(uint256 n) public { - for (uint256 i = 0; i < n; i++) { - // we transfer eth to ourselves to advance the block - vm.broadcast(msg.sender); - payable(msg.sender).transfer(1 wei); - } - } - - function convertBoolToString(bool input) public pure returns (string memory) { - if (input) { - return "true"; - } else { - return "false"; - } - } - - function convertOperatorStatusToString(IRegistryCoordinator.OperatorStatus operatorStatus) - public - pure - returns (string memory) - { - if (operatorStatus == IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED) { - return "NEVER_REGISTERED"; - } else if (operatorStatus == IRegistryCoordinator.OperatorStatus.REGISTERED) { - return "REGISTERED"; - } else if (operatorStatus == IRegistryCoordinator.OperatorStatus.DEREGISTERED) { - return "DEREGISTERED"; - } else { - return "UNKNOWN"; - } - } - - // Forge scripts best practice: https://book.getfoundry.sh/tutorials/best-practices#scripts function readInput(string memory inputFileName) internal view returns (string memory) { string memory inputDir = string.concat(vm.projectRoot(), "/script/input/"); string memory chainDir = string.concat(vm.toString(block.chainid), "/"); @@ -74,4 +27,54 @@ contract Utils is Script { string memory outputFilePath = string.concat(outputDir, chainDir, outputFileName, ".json"); vm.writeJson(outputJson, outputFilePath); } + + /** + * @dev Deploys a new proxy contract using the given implementation and initialization data. + * @param _impl Address of the implementation contract. + * @param _admin Proxy admin. + * @param _initCode Initialization code. + */ + function _deployProxy(ProxyAdmin _admin, address _impl, bytes memory _initCode) + internal + returns (TransparentUpgradeableProxy) + { + return new TransparentUpgradeableProxy(_impl, address(_admin), _initCode); + } + + /** + * @dev Deploys an empty proxy - i.e. a zero implementation and with no init code + * @param _admin Proxy admin. + */ + function _deployEmptyProxy(ProxyAdmin _admin, address emptyContract) + internal + returns (TransparentUpgradeableProxy) + { + return new TransparentUpgradeableProxy(emptyContract, address(_admin), ""); + } + + /** + * @dev Upgrades a proxy to a new implementation. + * @param _admin Proxy admin. + * @param _proxy The proxy to upgrade. + * @param _impl The new implementation to upgrade to. + */ + function _upgradeProxy(ProxyAdmin _admin, TransparentUpgradeableProxy _proxy, address _impl) internal { + _admin.upgrade(_proxy, _impl); + } + + /** + * @dev Upgrades a proxy to a new impl and calls a function on the implementation. + * @param _admin Proxy admin. + * @param _proxy The proxy to upgrade. + * @param _impl The new impl to upgrade to. + * @param _data The encoded calldata to use in the call after upgrading. + */ + function _upgradeProxyAndCall( + ProxyAdmin _admin, + TransparentUpgradeableProxy _proxy, + address _impl, + bytes memory _data + ) internal { + _admin.upgradeAndCall(_proxy, _impl, _data); + } } diff --git a/docker-compose.yml b/docker-compose.yml index 98c0c748..ebffcefa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -86,14 +86,8 @@ services: command: - -c - | - apk add --no-cache jq - deployer='0xa0Ee7A142d267C1f36714E4a8F75612F20a79720' deployerpk='0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6' - pauserregistry='0x0000000000000000000000000000000000000001' - impladdr=$(forge create src/rollup/SFFLRegistryRollup.sol:SFFLRegistryRollup --private-key $$deployerpk --json | jq -r '.deployedTo') - initcall=$(cast calldata 'initialize(((uint256,uint256),uint128)[],uint128,uint64,address,address)' '[((643552363890320897587044283125191574906281609959531590546948318138132520777,7028377728703212953187883551402495866059211864756496641401904395458852281995),1000)]' 66 1 $$deployer $$pauserregistry) - - forge create lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy --constructor-args $$impladdr $$deployer $$initcall --private-key $$deployerpk + forge script script/deploy/holesky/SFFLDeployerRollup.s.sol --private-key $$deployerpk --broadcast environment: - ETH_RPC_URL=http://rollup0-anvil:8546 networks: @@ -149,14 +143,8 @@ services: command: - -c - | - apk add --no-cache jq - deployer='0xa0Ee7A142d267C1f36714E4a8F75612F20a79720' deployerpk='0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6' - pauserregistry='0x0000000000000000000000000000000000000001' - impladdr=$(forge create src/rollup/SFFLRegistryRollup.sol:SFFLRegistryRollup --private-key $$deployerpk --json | jq -r '.deployedTo') - initcall=$(cast calldata 'initialize(((uint256,uint256),uint128)[],uint128,uint64,address,address)' '[((643552363890320897587044283125191574906281609959531590546948318138132520777,7028377728703212953187883551402495866059211864756496641401904395458852281995),1000)]' 66 1 $$deployer $$pauserregistry) - - forge create lib/eigenlayer-middleware/lib/eigenlayer-contracts/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy --constructor-args $$impladdr $$deployer $$initcall --private-key $$deployerpk + forge script script/deploy/holesky/SFFLDeployerRollup.s.sol --private-key $$deployerpk --broadcast environment: - ETH_RPC_URL=http://rollup1-anvil:8547 networks: