-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
423 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.12; | ||
|
||
import "forge-std/Script.sol"; | ||
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; | ||
|
||
import "../src/core/AVSCreator.sol"; | ||
import {IndexRegistry} from "eigenlayer-middleware/IndexRegistry.sol"; | ||
import {StakeRegistry} from "eigenlayer-middleware/StakeRegistry.sol"; | ||
import {BLSApkRegistry} from "eigenlayer-middleware/BLSApkRegistry.sol"; | ||
import {RegistryCoordinator} from "eigenlayer-middleware/RegistryCoordinator.sol"; | ||
import {MachServiceManager} from "../src/core/MachServiceManager.sol"; | ||
import {StakeRegistry, IStrategy} from "eigenlayer-middleware/StakeRegistry.sol"; | ||
|
||
// DELEGATION_MANAGER=$DELEGATION_MANAGER AVS_DIRECTORY=$AVS_DIRECTORY INITIAL_OWNER=$INITIAL_OWNER forge script ./script/AVSCreatorDeployer.s.sol \ | ||
// --private-key $PK \ | ||
// --rpc-url $URL \ | ||
// --etherscan-api-key $API_KEY \ | ||
// --broadcast -vvvv --slow --verify | ||
|
||
struct TokenAndWeight { | ||
address token; | ||
uint96 weight; | ||
} | ||
|
||
contract AVSCreatorDeployer is Script { | ||
function run() external { | ||
vm.startBroadcast(); | ||
|
||
address initialOwner = vm.envAddress("INITIAL_OWNER"); | ||
address delegationManager = vm.envAddress("DELEGATION_MANAGER"); | ||
address avsDirectory = vm.envAddress("AVS_DIRECTORY"); | ||
|
||
AVSCreator creator = new AVSCreator(delegationManager, avsDirectory); | ||
|
||
// Set the bytecodes | ||
creator.setIndexRegistryBytecode(type(IndexRegistry).creationCode); | ||
creator.setStakeRegistryBytecode(type(StakeRegistry).creationCode); | ||
creator.setApkRegistryBytecode(type(BLSApkRegistry).creationCode); | ||
creator.setRegistryCoordinatorBytecode(type(RegistryCoordinator).creationCode); | ||
creator.setServiceManagerBytecode(type(MachServiceManager).creationCode); | ||
|
||
uint256 numQuorums = 1; | ||
uint256 numStrategies = 3; | ||
uint96 minimumStake = 0; | ||
uint32 maxOperatorCount = 50; | ||
{ | ||
// strategies deployed | ||
TokenAndWeight[] memory deployedStrategyArray = new TokenAndWeight[](numStrategies); | ||
|
||
{ | ||
// need manually step in | ||
deployedStrategyArray[0].token = 0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0; | ||
deployedStrategyArray[1].token = 0x7D704507b76571a51d9caE8AdDAbBFd0ba0e63d3; | ||
deployedStrategyArray[2].token = 0x3A8fBdf9e77DFc25d09741f51d3E181b25d0c4E0; | ||
} | ||
|
||
{ | ||
// need manually step in | ||
deployedStrategyArray[0].weight = 1000000000000000000; | ||
deployedStrategyArray[1].weight = 997992210000000000; | ||
deployedStrategyArray[2].weight = 1104234999999999999; | ||
} | ||
|
||
IRegistryCoordinator.OperatorSetParam[] memory operatorSetParams = | ||
new IRegistryCoordinator.OperatorSetParam[](numQuorums); | ||
|
||
// prepare _operatorSetParams | ||
for (uint256 i = 0; i < numQuorums; i++) { | ||
// hard code these for now | ||
operatorSetParams[i] = IRegistryCoordinator.OperatorSetParam({ | ||
maxOperatorCount: maxOperatorCount, | ||
kickBIPsOfOperatorStake: 11000, // an operator needs to have kickBIPsOfOperatorStake / 10000 times the stake of the operator with the least stake to kick them out | ||
kickBIPsOfTotalStake: 1001 // an operator needs to have less than kickBIPsOfTotalStake / 10000 of the total stake to be kicked out | ||
}); | ||
} | ||
|
||
// prepare _minimumStakes | ||
uint96[] memory minimumStakeForQuourm = new uint96[](numQuorums); | ||
for (uint256 i = 0; i < numQuorums; i++) { | ||
minimumStakeForQuourm[i] = minimumStake; | ||
} | ||
|
||
// prepare _strategyParams | ||
IStakeRegistry.StrategyParams[][] memory strategyParams = new IStakeRegistry.StrategyParams[][](numQuorums); | ||
for (uint256 i = 0; i < numQuorums; i++) { | ||
IStakeRegistry.StrategyParams[] memory params = new IStakeRegistry.StrategyParams[](numStrategies); | ||
for (uint256 j = 0; j < numStrategies; j++) { | ||
params[j] = IStakeRegistry.StrategyParams({ | ||
strategy: IStrategy(deployedStrategyArray[j].token), | ||
multiplier: deployedStrategyArray[j].weight | ||
}); | ||
} | ||
strategyParams[i] = params; | ||
} | ||
|
||
creator.createAVS( | ||
initialOwner, initialOwner, initialOwner, operatorSetParams, minimumStakeForQuourm, strategyParams | ||
); | ||
} | ||
|
||
// Stop broadcasting transactions | ||
vm.stopBroadcast(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.12; | ||
|
||
import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; | ||
|
||
import {IRegistryCoordinator} from "eigenlayer-middleware/interfaces/IRegistryCoordinator.sol"; | ||
import {OperatorStateRetriever} from "eigenlayer-middleware/OperatorStateRetriever.sol"; | ||
import {PauserRegistry, IPauserRegistry} from "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol"; | ||
import {IStakeRegistry} from "eigenlayer-middleware/interfaces/IStakeRegistry.sol"; | ||
import {RegistryCoordinator} from "eigenlayer-middleware/RegistryCoordinator.sol"; | ||
|
||
contract EmptyContract {} | ||
|
||
contract AVSCreatorStorage { | ||
address public immutable emptyContract; | ||
address public immutable delegationManager; | ||
address public immutable avsDirectory; | ||
OperatorStateRetriever public immutable operatorStateRetriever; | ||
|
||
bytes public indexRegistryBytecode; | ||
bytes public stakeRegistryBytecode; | ||
bytes public apkRegistryBytecode; | ||
bytes public registryCoordinatorBytecode; | ||
bytes public serviceManagerBytecode; | ||
|
||
constructor(address delegationManager_, address avsDirectory_) { | ||
delegationManager = delegationManager_; | ||
avsDirectory = avsDirectory_; | ||
emptyContract = address(new EmptyContract()); | ||
operatorStateRetriever = new OperatorStateRetriever(); | ||
} | ||
} | ||
|
||
contract AVSCreator is AVSCreatorStorage { | ||
error AlreadySet(); | ||
|
||
event Created( | ||
ProxyAdmin ProxyAdmin, | ||
PauserRegistry pauserRegistry, | ||
address indexRegistryProxy, | ||
address stakeRegistryProxy, | ||
address apkRegistryProxy, | ||
address registryCoordinatorProxy, | ||
address serviceManagerProxy | ||
); | ||
|
||
modifier setOnce(bytes memory bytecode) { | ||
if (bytecode.length != 0) { | ||
revert AlreadySet(); | ||
} | ||
_; | ||
} | ||
|
||
constructor(address delegationManager_, address avsDirectory_) | ||
AVSCreatorStorage(delegationManager_, avsDirectory_) | ||
{} | ||
|
||
function setIndexRegistryBytecode(bytes calldata bytecode) external setOnce(indexRegistryBytecode) { | ||
indexRegistryBytecode = bytecode; | ||
} | ||
|
||
function setStakeRegistryBytecode(bytes calldata bytecode) external setOnce(stakeRegistryBytecode) { | ||
stakeRegistryBytecode = bytecode; | ||
} | ||
|
||
function setApkRegistryBytecode(bytes calldata bytecode) external setOnce(apkRegistryBytecode) { | ||
apkRegistryBytecode = bytecode; | ||
} | ||
|
||
function setRegistryCoordinatorBytecode(bytes calldata bytecode) external setOnce(registryCoordinatorBytecode) { | ||
registryCoordinatorBytecode = bytecode; | ||
} | ||
|
||
function setServiceManagerBytecode(bytes calldata bytecode) external setOnce(serviceManagerBytecode) { | ||
serviceManagerBytecode = bytecode; | ||
} | ||
|
||
function createAVS( | ||
address initialOwner_, | ||
address churnApprover_, | ||
address ejector_, | ||
IRegistryCoordinator.OperatorSetParam[] memory operatorSetParams_, | ||
uint96[] memory minimumStakes_, | ||
IStakeRegistry.StrategyParams[][] memory strategyParams_ | ||
) external { | ||
bytes memory registryCoordinatorInit; | ||
PauserRegistry pauserRegistry; | ||
{ | ||
{ | ||
address[] memory pausers = new address[](1); | ||
pausers[0] = initialOwner_; | ||
pauserRegistry = new PauserRegistry(pausers, initialOwner_); | ||
} | ||
|
||
registryCoordinatorInit = abi.encodeWithSelector( | ||
RegistryCoordinator.initialize.selector, | ||
initialOwner_, | ||
churnApprover_, | ||
ejector_, | ||
pauserRegistry, | ||
0, /*initialPausedStatus*/ | ||
operatorSetParams_, | ||
minimumStakes_, | ||
strategyParams_ | ||
); | ||
} | ||
|
||
ProxyAdmin proxyAdmin = new ProxyAdmin(); | ||
|
||
// Deploy proxies for each contract | ||
address indexRegistryProxy = address(new TransparentUpgradeableProxy(emptyContract, address(proxyAdmin), "")); | ||
address stakeRegistryProxy = address(new TransparentUpgradeableProxy(emptyContract, address(proxyAdmin), "")); | ||
address apkRegistryProxy = address(new TransparentUpgradeableProxy(emptyContract, address(proxyAdmin), "")); | ||
address registryCoordinatorProxy = | ||
address(new TransparentUpgradeableProxy(emptyContract, address(proxyAdmin), "")); | ||
address serviceManagerProxy = address(new TransparentUpgradeableProxy(emptyContract, address(proxyAdmin), "")); | ||
|
||
emit Created( | ||
proxyAdmin, | ||
pauserRegistry, | ||
indexRegistryProxy, | ||
stakeRegistryProxy, | ||
apkRegistryProxy, | ||
registryCoordinatorProxy, | ||
serviceManagerProxy | ||
); | ||
|
||
// Deploy the actual implementation contracts | ||
|
||
{ | ||
address indexRegistryImpl = | ||
_createImplementation(abi.encodePacked(indexRegistryBytecode, abi.encode(registryCoordinatorProxy))); | ||
|
||
address stakeRegistryImpl = _createImplementation( | ||
abi.encodePacked(stakeRegistryBytecode, abi.encode(registryCoordinatorProxy, delegationManager)) | ||
); | ||
|
||
address apkRegistryImpl = | ||
_createImplementation(abi.encodePacked(apkRegistryBytecode, abi.encode(registryCoordinatorProxy))); | ||
|
||
address registryCoordinatorImpl = _createImplementation( | ||
abi.encodePacked( | ||
registryCoordinatorBytecode, | ||
abi.encode(serviceManagerProxy, stakeRegistryProxy, apkRegistryProxy, indexRegistryProxy) | ||
) | ||
); | ||
|
||
proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(indexRegistryProxy)), indexRegistryImpl); | ||
proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(stakeRegistryProxy)), stakeRegistryImpl); | ||
proxyAdmin.upgrade(TransparentUpgradeableProxy(payable(apkRegistryProxy)), apkRegistryImpl); | ||
proxyAdmin.upgradeAndCall( | ||
TransparentUpgradeableProxy(payable(address(registryCoordinatorProxy))), | ||
address(registryCoordinatorImpl), | ||
registryCoordinatorInit | ||
); | ||
} | ||
|
||
proxyAdmin.transferOwnership(initialOwner_); | ||
} | ||
|
||
function createServiceManagerImplementation(address registryCoordinatorProxy_, address stakeRegistryProxy_) | ||
external | ||
returns (address) | ||
{ | ||
address impl = _createImplementation( | ||
abi.encodePacked( | ||
serviceManagerBytecode, abi.encode(avsDirectory, registryCoordinatorProxy_, stakeRegistryProxy_) | ||
) | ||
); | ||
return impl; | ||
} | ||
|
||
function _createImplementation(bytes memory bytecodeWithConstructor) internal returns (address) { | ||
address addr; | ||
assembly { | ||
addr := create(0, add(bytecodeWithConstructor, 0x20), mload(bytecodeWithConstructor)) | ||
if iszero(extcodesize(addr)) { revert(0, 0) } | ||
} | ||
return addr; | ||
} | ||
} |
Oops, something went wrong.