Skip to content

Commit

Permalink
feat: AVS Creator
Browse files Browse the repository at this point in the history
  • Loading branch information
neutiyoo committed Jul 18, 2024
1 parent 8bab509 commit 5e39acb
Show file tree
Hide file tree
Showing 3 changed files with 423 additions and 0 deletions.
106 changes: 106 additions & 0 deletions contracts/script/AVSCreatorDeployer.s.sol
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();
}
}
182 changes: 182 additions & 0 deletions contracts/src/core/AVSCreator.sol
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;
}
}
Loading

0 comments on commit 5e39acb

Please sign in to comment.