datahaven/contracts/script/deploy/DeployLocal.s.sol
Tobi Demeco 80a0138f00
feat(contracts): add set up validator script and execute it when starting integration tests (#47)
This PR adds the `setup-validators` Typescript script that, given an
already started up network, sets up a new validator set and sends it
through Snowbridge's Gateway to the solochain. To accomplish that
purpose, this PR:
- Modifies the `DeployLocal` script to save in the `anvil.json` file not
only the deployed strategies' addresses but also the owner of each
strategy's underlying token. This owner is used as the source of funds
to transfer tokens to other validators so they can register under that
strategy.
- Adds an `OPERATOR_SOLOCHAIN_ADDRESS` to the `Accounts` utility script
contract. This address is the one used as the Solochain address when
registering a new Operator.
- Updates the `SignUpOperator` (which I believe is now deprecated since
we have multiple Operator Sets) and `SignUpOperatorBase` scripts to
adapt to both aforementioned changes.
- Updates the `ELScriptStorage` script to save the new extra information
of each deployed strategy (the creator of the underlying token) in
storage.
- Adds a `validator-set.json` file which contains the validators that
should be registered in the AVS and sent to the Solochain network
through the Snowbridge Gateway when starting any integration test. This
is currently hardcoded but could be generated in any other way, giving
us flexibility for testing.
- Adds both a Markdown file and a Excalidraw diagram showcasing both how
the setup of integration tests work and possible integration tests that
will be added in a future PR. This list is not exahustive as there are
many more scenarios we will want to test using integration tests.
- Updates the `e2e-cli.ts` script to execute the validator setup when
bootstrapping the network used for integration testing.

---------

Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
2025-04-22 16:49:51 -03:00

859 lines
36 KiB
Solidity

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.27;
// Testing imports
import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";
import {DeployParams} from "./DeployParams.s.sol";
import {Logging} from "../utils/Logging.sol";
import {Accounts} from "../utils/Accounts.sol";
// Snowbridge imports
import {Gateway} from "snowbridge/src/Gateway.sol";
import {IGatewayV2} from "snowbridge/src/v2/IGateway.sol";
import {GatewayProxy} from "snowbridge/src/GatewayProxy.sol";
import {AgentExecutor} from "snowbridge/src/AgentExecutor.sol";
import {Agent} from "snowbridge/src/Agent.sol";
import {Initializer} from "snowbridge/src/Initializer.sol";
import {OperatingMode} from "snowbridge/src/types/Common.sol";
import {ud60x18} from "snowbridge/lib/prb-math/src/UD60x18.sol";
import {BeefyClient} from "snowbridge/src/BeefyClient.sol";
// OpenZeppelin imports
import {ERC20PresetFixedSupply} from
"@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {ITransparentUpgradeableProxy} from
"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {TransparentUpgradeableProxy} from
"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
// EigenLayer imports
import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol";
import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol";
import {DelegationManager} from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol";
import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol";
import {StrategyManager} from "eigenlayer-contracts/src/contracts/core/StrategyManager.sol";
import {IAllocationManagerTypes} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IETHPOSDeposit} from "eigenlayer-contracts/src/contracts/interfaces/IETHPOSDeposit.sol";
import {
IRewardsCoordinator,
IRewardsCoordinatorTypes
} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {PermissionController} from
"eigenlayer-contracts/src/contracts/permissions/PermissionController.sol";
import {PauserRegistry} from "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol";
import {EigenPod} from "eigenlayer-contracts/src/contracts/pods/EigenPod.sol";
import {EigenPodManager} from "eigenlayer-contracts/src/contracts/pods/EigenPodManager.sol";
import {StrategyBaseTVLLimits} from
"eigenlayer-contracts/src/contracts/strategies/StrategyBaseTVLLimits.sol";
import {EmptyContract} from "eigenlayer-contracts/src/test/mocks/EmptyContract.sol";
// DataHaven imports
import {DataHavenServiceManager} from "../../src/DataHavenServiceManager.sol";
import {MerkleUtils} from "../../src/libraries/MerkleUtils.sol";
import {VetoableSlasher} from "../../src/middleware/VetoableSlasher.sol";
import {RewardsRegistry} from "../../src/middleware/RewardsRegistry.sol";
struct ServiceManagerInitParams {
address avsOwner;
address rewardsInitiator;
address[] validatorsStrategies;
address[] bspsStrategies;
address[] mspsStrategies;
address gateway;
}
// Struct to store more detailed strategy information
struct StrategyInfo {
address address_;
address underlyingToken;
address tokenCreator;
}
contract Deploy is Script, DeployParams, Accounts {
// Progress indicator
uint16 public deploymentStep = 0;
uint16 public totalSteps = 4; // Total major deployment steps
// EigenLayer Contract declarations
EmptyContract public emptyContract;
RewardsCoordinator public rewardsCoordinator;
RewardsCoordinator public rewardsCoordinatorImplementation;
PermissionController public permissionController;
PermissionController public permissionControllerImplementation;
AllocationManager public allocationManager;
AllocationManager public allocationManagerImplementation;
DelegationManager public delegation;
DelegationManager public delegationImplementation;
StrategyManager public strategyManager;
StrategyManager public strategyManagerImplementation;
AVSDirectory public avsDirectory;
AVSDirectory public avsDirectoryImplementation;
EigenPodManager public eigenPodManager;
EigenPodManager public eigenPodManagerImplementation;
UpgradeableBeacon public eigenPodBeacon;
EigenPod public eigenPodImplementation;
StrategyBaseTVLLimits public baseStrategyImplementation;
StrategyInfo[] public deployedStrategies;
IETHPOSDeposit public ethPOSDeposit;
// EigenLayer required semver
string public constant SEMVER = "v1.0.0";
function _logProgress() internal {
deploymentStep++;
Logging.logProgress(deploymentStep, totalSteps);
}
function run() public {
Logging.logHeader("DATAHAVEN DEPLOYMENT SCRIPT");
console.log("| Network: %s", vm.envOr("NETWORK", string("anvil")));
console.log("| Timestamp: %s", vm.toString(block.timestamp));
Logging.logFooter();
// Load configurations
SnowbridgeConfig memory snowbridgeConfig = getSnowbridgeConfig();
AVSConfig memory avsConfig = getAVSConfig();
EigenLayerConfig memory eigenLayerConfig = getEigenLayerConfig();
// Deploy EigenLayer core contracts
Logging.logHeader("EIGENLAYER CORE CONTRACTS DEPLOYMENT");
Logging.logInfo("Deploying core infrastructure contracts");
// Deploy proxy admin for ability to upgrade proxy contracts
vm.broadcast(_deployerPrivateKey);
ProxyAdmin proxyAdmin = new ProxyAdmin();
Logging.logContractDeployed("ProxyAdmin", address(proxyAdmin));
// Deploy pauser registry
PauserRegistry pauserRegistry = _deployPauserRegistry(eigenLayerConfig);
Logging.logContractDeployed("PauserRegistry", address(pauserRegistry));
// Deploy empty contract to use as initial implementation for proxies
vm.broadcast(_deployerPrivateKey);
emptyContract = new EmptyContract();
Logging.logContractDeployed("EmptyContract", address(emptyContract));
// Deploy proxies that will point to implementations
Logging.logSection("Deploying Proxy Contracts");
_deployProxies(proxyAdmin);
Logging.logStep("Initial proxies deployed successfully");
// Setup ETH2 deposit contract for EigenPod functionality
ethPOSDeposit = IETHPOSDeposit(getETHPOSDepositAddress());
Logging.logContractDeployed("ETHPOSDeposit", address(ethPOSDeposit));
// Deploy EigenPod implementation and beacon
vm.broadcast(_deployerPrivateKey);
eigenPodImplementation = new EigenPod(
ethPOSDeposit, eigenPodManager, eigenLayerConfig.beaconChainGenesisTimestamp, SEMVER
);
vm.broadcast(_deployerPrivateKey);
eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation));
Logging.logContractDeployed("EigenPod Implementation", address(eigenPodImplementation));
Logging.logContractDeployed("EigenPod Beacon", address(eigenPodBeacon));
// Deploy implementation contracts
Logging.logSection("Deploying Implementation Contracts");
_deployImplementations(eigenLayerConfig, pauserRegistry);
Logging.logStep("Implementation contracts deployed successfully");
// Upgrade proxies to point to implementations and initialise
Logging.logSection("Initializing Contracts");
_upgradeAndInitializeProxies(eigenLayerConfig, proxyAdmin);
Logging.logStep("Proxies upgraded and initialized successfully");
// Deploy strategy implementation and create strategy proxies
Logging.logSection("Deploying Strategy Contracts");
_deployStrategies(pauserRegistry, proxyAdmin);
Logging.logStep("Strategy contracts deployed successfully");
// Transfer ownership of core contracts
vm.broadcast(_deployerPrivateKey);
proxyAdmin.transferOwnership(eigenLayerConfig.executorMultisig);
vm.broadcast(_deployerPrivateKey);
eigenPodBeacon.transferOwnership(eigenLayerConfig.executorMultisig);
Logging.logStep("Ownership transferred to multisig");
Logging.logFooter();
_logProgress();
// Deploy Snowbridge and configure Agent
Logging.logHeader("SNOWBRIDGE DEPLOYMENT");
(
BeefyClient beefyClient,
AgentExecutor agentExecutor,
IGatewayV2 gateway,
address payable rewardsAgentAddress
) = _deploySnowbridge(snowbridgeConfig);
Logging.logFooter();
_logProgress();
// Deploy DataHaven custom contracts
(
DataHavenServiceManager serviceManager,
VetoableSlasher vetoableSlasher,
RewardsRegistry rewardsRegistry
) = _deployDataHavenContracts(avsConfig, proxyAdmin, gateway);
Logging.logFooter();
_logProgress();
// Set the Agent in the RewardsRegistry
Logging.logHeader("FINAL CONFIGURATION");
// This needs to be executed by the AVS owner
vm.broadcast(_avsOwnerPrivateKey);
serviceManager.setRewardsAgent(0, address(rewardsAgentAddress));
Logging.logStep("Agent set in RewardsRegistry");
Logging.logContractDeployed("Agent Address", rewardsAgentAddress);
Logging.logFooter();
_logProgress();
// Output all deployed contract addresses
_outputDeployedAddresses(
beefyClient,
agentExecutor,
gateway,
serviceManager,
vetoableSlasher,
rewardsRegistry,
rewardsAgentAddress
);
}
function _deploySnowbridge(
SnowbridgeConfig memory config
) internal returns (BeefyClient, AgentExecutor, IGatewayV2, address payable) {
Logging.logSection("Deploying Snowbridge Core Components");
BeefyClient beefyClient = _deployBeefyClient(config);
Logging.logContractDeployed("BeefyClient", address(beefyClient));
vm.broadcast(_deployerPrivateKey);
AgentExecutor agentExecutor = new AgentExecutor();
Logging.logContractDeployed("AgentExecutor", address(agentExecutor));
vm.broadcast(_deployerPrivateKey);
Gateway gatewayImplementation = new Gateway(address(beefyClient), address(agentExecutor));
Logging.logContractDeployed("Gateway Implementation", address(gatewayImplementation));
// Configure and deploy Gateway proxy
OperatingMode defaultOperatingMode = OperatingMode.Normal;
Initializer.Config memory gatewayConfig = Initializer.Config({
mode: defaultOperatingMode,
deliveryCost: 1,
registerTokenFee: 1,
assetHubCreateAssetFee: 1,
assetHubReserveTransferFee: 1,
exchangeRate: ud60x18(1),
multiplier: ud60x18(1),
foreignTokenDecimals: 18,
maxDestinationFee: 1
});
vm.broadcast(_deployerPrivateKey);
IGatewayV2 gateway = IGatewayV2(
address(new GatewayProxy(address(gatewayImplementation), abi.encode(gatewayConfig)))
);
Logging.logContractDeployed("Gateway Proxy", address(gateway));
// Create Agent
Logging.logSection("Creating Snowbridge Agent");
vm.broadcast(_deployerPrivateKey);
gateway.v2_createAgent(config.rewardsMessageOrigin);
address payable rewardsAgentAddress = payable(gateway.agentOf(config.rewardsMessageOrigin));
Logging.logContractDeployed("Rewards Agent", rewardsAgentAddress);
return (beefyClient, agentExecutor, gateway, rewardsAgentAddress);
}
function _deployProxies(
ProxyAdmin proxyAdmin
) internal {
// Deploy proxies with empty implementation initially
vm.broadcast(_deployerPrivateKey);
delegation = DelegationManager(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("DelegationManager Proxy", address(delegation));
vm.broadcast(_deployerPrivateKey);
strategyManager = StrategyManager(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("StrategyManager Proxy", address(strategyManager));
vm.broadcast(_deployerPrivateKey);
avsDirectory = AVSDirectory(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("AVSDirectory Proxy", address(avsDirectory));
vm.broadcast(_deployerPrivateKey);
eigenPodManager = EigenPodManager(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("EigenPodManager Proxy", address(eigenPodManager));
vm.broadcast(_deployerPrivateKey);
rewardsCoordinator = RewardsCoordinator(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("RewardsCoordinator Proxy", address(rewardsCoordinator));
vm.broadcast(_deployerPrivateKey);
allocationManager = AllocationManager(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("AllocationManager Proxy", address(allocationManager));
vm.broadcast(_deployerPrivateKey);
permissionController = PermissionController(
address(
new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")
)
);
Logging.logContractDeployed("PermissionController Proxy", address(permissionController));
}
function _deployImplementations(
EigenLayerConfig memory config,
PauserRegistry pauserRegistry
) internal {
// Deploy implementation contracts
vm.broadcast(_deployerPrivateKey);
delegationImplementation = new DelegationManager(
strategyManager,
eigenPodManager,
allocationManager,
pauserRegistry,
permissionController,
config.minWithdrawalDelayBlocks,
SEMVER
);
Logging.logContractDeployed(
"DelegationManager Implementation", address(delegationImplementation)
);
vm.broadcast(_deployerPrivateKey);
strategyManagerImplementation = new StrategyManager(delegation, pauserRegistry, SEMVER);
Logging.logContractDeployed(
"StrategyManager Implementation", address(strategyManagerImplementation)
);
vm.broadcast(_deployerPrivateKey);
avsDirectoryImplementation = new AVSDirectory(delegation, pauserRegistry, SEMVER);
Logging.logContractDeployed(
"AVSDirectory Implementation", address(avsDirectoryImplementation)
);
vm.broadcast(_deployerPrivateKey);
eigenPodManagerImplementation =
new EigenPodManager(ethPOSDeposit, eigenPodBeacon, delegation, pauserRegistry, SEMVER);
Logging.logContractDeployed(
"EigenPodManager Implementation", address(eigenPodManagerImplementation)
);
vm.broadcast(_deployerPrivateKey);
rewardsCoordinatorImplementation = new RewardsCoordinator(
IRewardsCoordinatorTypes.RewardsCoordinatorConstructorParams(
delegation,
strategyManager,
allocationManager,
pauserRegistry,
permissionController,
config.calculationIntervalSeconds,
config.maxRewardsDuration,
config.maxRetroactiveLength,
config.maxFutureLength,
config.genesisRewardsTimestamp,
SEMVER
)
);
Logging.logContractDeployed(
"RewardsCoordinator Implementation", address(rewardsCoordinatorImplementation)
);
vm.broadcast(_deployerPrivateKey);
allocationManagerImplementation = new AllocationManager(
delegation,
pauserRegistry,
permissionController,
config.deallocationDelay,
config.allocationConfigurationDelay,
SEMVER
);
Logging.logContractDeployed(
"AllocationManager Implementation", address(allocationManagerImplementation)
);
vm.broadcast(_deployerPrivateKey);
permissionControllerImplementation = new PermissionController(SEMVER);
Logging.logContractDeployed(
"PermissionController Implementation", address(permissionControllerImplementation)
);
}
function _upgradeAndInitializeProxies(
EigenLayerConfig memory config,
ProxyAdmin proxyAdmin
) internal {
// Initialize DelegationManager
{
IStrategy[] memory strategies;
uint256[] memory withdrawalDelayBlocks;
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgradeAndCall(
ITransparentUpgradeableProxy(payable(address(delegation))),
address(delegationImplementation),
abi.encodeWithSelector(
DelegationManager.initialize.selector,
config.executorMultisig,
config.delegationInitPausedStatus,
config.delegationWithdrawalDelayBlocks,
strategies,
withdrawalDelayBlocks
)
);
Logging.logStep("DelegationManager initialized");
}
// Initialize StrategyManager
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgradeAndCall(
ITransparentUpgradeableProxy(payable(address(strategyManager))),
address(strategyManagerImplementation),
abi.encodeWithSelector(
StrategyManager.initialize.selector,
config.executorMultisig,
config.operationsMultisig,
config.strategyManagerInitPausedStatus
)
);
Logging.logStep("StrategyManager initialized");
// Initialize AVSDirectory
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgradeAndCall(
ITransparentUpgradeableProxy(payable(address(avsDirectory))),
address(avsDirectoryImplementation),
abi.encodeWithSelector(
AVSDirectory.initialize.selector,
config.executorMultisig,
0 // Initial paused status
)
);
Logging.logStep("AVSDirectory initialized");
// Initialize EigenPodManager
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgradeAndCall(
ITransparentUpgradeableProxy(payable(address(eigenPodManager))),
address(eigenPodManagerImplementation),
abi.encodeWithSelector(
EigenPodManager.initialize.selector,
config.executorMultisig,
config.eigenPodManagerInitPausedStatus
)
);
Logging.logStep("EigenPodManager initialized");
// Initialize RewardsCoordinator
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgradeAndCall(
ITransparentUpgradeableProxy(payable(address(rewardsCoordinator))),
address(rewardsCoordinatorImplementation),
abi.encodeWithSelector(
RewardsCoordinator.initialize.selector,
config.executorMultisig,
config.rewardsCoordinatorInitPausedStatus,
config.rewardsUpdater,
config.activationDelay,
config.globalCommissionBips
)
);
Logging.logStep("RewardsCoordinator initialized");
// Initialize AllocationManager
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgradeAndCall(
ITransparentUpgradeableProxy(payable(address(allocationManager))),
address(allocationManagerImplementation),
abi.encodeWithSelector(
AllocationManager.initialize.selector,
config.executorMultisig,
config.allocationManagerInitPausedStatus
)
);
Logging.logStep("AllocationManager initialized");
// Initialize PermissionController (no initialization function)
vm.broadcast(_deployerPrivateKey);
proxyAdmin.upgrade(
ITransparentUpgradeableProxy(payable(address(permissionController))),
address(permissionControllerImplementation)
);
Logging.logStep("PermissionController upgraded");
}
function _deployStrategies(PauserRegistry pauserRegistry, ProxyAdmin proxyAdmin) internal {
// Deploy base strategy implementation
vm.broadcast(_deployerPrivateKey);
baseStrategyImplementation =
new StrategyBaseTVLLimits(strategyManager, pauserRegistry, SEMVER);
Logging.logContractDeployed("Strategy Implementation", address(baseStrategyImplementation));
// Create default test token and strategy if needed
// In a production environment, this would be replaced with actual token addresses.
if (block.chainid != 1) {
// We mint tokens to the operator account so that it then has a balance to deposit as stake.
vm.broadcast(_deployerPrivateKey);
address testToken =
address(new ERC20PresetFixedSupply("TestToken", "TEST", 1000000 ether, _operator));
Logging.logContractDeployed("TestToken", testToken);
// Create strategy for test token
vm.broadcast(_deployerPrivateKey);
StrategyBaseTVLLimits strategy = StrategyBaseTVLLimits(
address(
new TransparentUpgradeableProxy(
address(baseStrategyImplementation),
address(proxyAdmin),
abi.encodeWithSelector(
StrategyBaseTVLLimits.initialize.selector,
1000000 ether, // maxPerDeposit
10000000 ether, // maxDeposits
IERC20(testToken)
)
)
)
);
// Store the strategy with its token information
deployedStrategies.push(
StrategyInfo({
address_: address(strategy),
underlyingToken: testToken,
tokenCreator: _operator
})
);
Logging.logContractDeployed("Test Strategy", address(strategy));
}
// Whitelist strategies in the strategy manager
IStrategy[] memory strategies = new IStrategy[](deployedStrategies.length);
for (uint256 i = 0; i < deployedStrategies.length; i++) {
strategies[i] = IStrategy(deployedStrategies[i].address_);
}
vm.broadcast(_operationsMultisigPrivateKey);
strategyManager.addStrategiesToDepositWhitelist(strategies);
}
function _deployProxyAdmin() internal returns (ProxyAdmin) {
ProxyAdmin proxyAdmin = new ProxyAdmin();
return proxyAdmin;
}
function _deployPauserRegistry(
EigenLayerConfig memory config
) internal returns (PauserRegistry) {
// Use the array of pauser addresses directly from the config
vm.broadcast(_deployerPrivateKey);
return new PauserRegistry(config.pauserAddresses, config.unpauserAddress);
}
function _buildValidatorSet(
uint128 id,
bytes32[] memory validators
) internal pure returns (BeefyClient.ValidatorSet memory) {
// Calculate the merkle root from the validators array using the shared library
bytes32 merkleRoot = MerkleUtils.calculateMerkleRoot(validators);
// Create and return the validator set with the calculated merkle root
return
BeefyClient.ValidatorSet({id: id, length: uint128(validators.length), root: merkleRoot});
}
function _deployBeefyClient(
SnowbridgeConfig memory config
) internal returns (BeefyClient) {
// Create validator sets using the MerkleUtils library
BeefyClient.ValidatorSet memory validatorSet =
_buildValidatorSet(0, config.initialValidators);
BeefyClient.ValidatorSet memory nextValidatorSet =
_buildValidatorSet(1, config.nextValidators);
// Deploy BeefyClient
vm.broadcast(_deployerPrivateKey);
return new BeefyClient(
config.randaoCommitDelay,
config.randaoCommitExpiration,
config.minNumRequiredSignatures,
config.startBlock,
validatorSet,
nextValidatorSet
);
}
function _outputDeployedAddresses(
BeefyClient beefyClient,
AgentExecutor agentExecutor,
IGatewayV2 gateway,
DataHavenServiceManager serviceManager,
VetoableSlasher vetoableSlasher,
RewardsRegistry rewardsRegistry,
address agent
) internal {
Logging.logHeader("DEPLOYMENT SUMMARY");
Logging.logSection("Snowbridge Contracts");
Logging.logContractDeployed("BeefyClient", address(beefyClient));
Logging.logContractDeployed("AgentExecutor", address(agentExecutor));
Logging.logContractDeployed("Gateway", address(gateway));
Logging.logContractDeployed("Agent", agent);
Logging.logSection("DataHaven Contracts");
Logging.logContractDeployed("ServiceManager", address(serviceManager));
Logging.logContractDeployed("VetoableSlasher", address(vetoableSlasher));
Logging.logContractDeployed("RewardsRegistry", address(rewardsRegistry));
Logging.logSection("EigenLayer Core Contracts");
Logging.logContractDeployed("DelegationManager", address(delegation));
Logging.logContractDeployed("StrategyManager", address(strategyManager));
Logging.logContractDeployed("AVSDirectory", address(avsDirectory));
Logging.logContractDeployed("EigenPodManager", address(eigenPodManager));
Logging.logContractDeployed("EigenPodBeacon", address(eigenPodBeacon));
Logging.logContractDeployed("RewardsCoordinator", address(rewardsCoordinator));
Logging.logContractDeployed("AllocationManager", address(allocationManager));
Logging.logContractDeployed("PermissionController", address(permissionController));
Logging.logContractDeployed("ETHPOSDeposit", address(ethPOSDeposit));
Logging.logSection("Strategy Contracts");
Logging.logContractDeployed(
"BaseStrategyImplementation", address(baseStrategyImplementation)
);
for (uint256 i = 0; i < deployedStrategies.length; i++) {
Logging.logContractDeployed(
string.concat("DeployedStrategy", vm.toString(i)), deployedStrategies[i].address_
);
}
Logging.logFooter();
// Write to deployment file for future reference
string memory network = vm.envOr("NETWORK", string("anvil"));
string memory deploymentPath =
string.concat(vm.projectRoot(), "/deployments/", network, ".json");
// Create directory if it doesn't exist
vm.createDir(string.concat(vm.projectRoot(), "/deployments"), true);
// Create JSON with deployed addresses
string memory json = "{";
json = string.concat(json, '"network": "', network, '",');
// Snowbridge contracts
json = string.concat(json, '"BeefyClient": "', vm.toString(address(beefyClient)), '",');
json = string.concat(json, '"AgentExecutor": "', vm.toString(address(agentExecutor)), '",');
json = string.concat(json, '"Gateway": "', vm.toString(address(gateway)), '",');
json =
string.concat(json, '"ServiceManager": "', vm.toString(address(serviceManager)), '",');
json =
string.concat(json, '"VetoableSlasher": "', vm.toString(address(vetoableSlasher)), '",');
json =
string.concat(json, '"RewardsRegistry": "', vm.toString(address(rewardsRegistry)), '",');
json = string.concat(json, '"Agent": "', vm.toString(agent), '",');
// EigenLayer contracts
json = string.concat(json, '"DelegationManager": "', vm.toString(address(delegation)), '",');
json =
string.concat(json, '"StrategyManager": "', vm.toString(address(strategyManager)), '",');
json = string.concat(json, '"AVSDirectory": "', vm.toString(address(avsDirectory)), '",');
json =
string.concat(json, '"EigenPodManager": "', vm.toString(address(eigenPodManager)), '",');
json =
string.concat(json, '"EigenPodBeacon": "', vm.toString(address(eigenPodBeacon)), '",');
json = string.concat(
json, '"RewardsCoordinator": "', vm.toString(address(rewardsCoordinator)), '",'
);
json = string.concat(
json, '"AllocationManager": "', vm.toString(address(allocationManager)), '",'
);
json = string.concat(
json, '"PermissionController": "', vm.toString(address(permissionController)), '",'
);
json = string.concat(json, '"ETHPOSDeposit": "', vm.toString(address(ethPOSDeposit)), '",');
json = string.concat(
json,
'"BaseStrategyImplementation": "',
vm.toString(address(baseStrategyImplementation)),
'"'
);
// Add strategies with token information
if (deployedStrategies.length > 0) {
json = string.concat(json, ",");
json = string.concat(json, '"DeployedStrategies": [');
for (uint256 i = 0; i < deployedStrategies.length; i++) {
json = string.concat(json, "{");
json = string.concat(
json, '"address": "', vm.toString(deployedStrategies[i].address_), '",'
);
json = string.concat(
json,
'"underlyingToken": "',
vm.toString(deployedStrategies[i].underlyingToken),
'",'
);
json = string.concat(
json, '"tokenCreator": "', vm.toString(deployedStrategies[i].tokenCreator), '"'
);
json = string.concat(json, "}");
// Add comma if not the last element
if (i < deployedStrategies.length - 1) {
json = string.concat(json, ",");
}
}
json = string.concat(json, "]");
}
json = string.concat(json, "}");
// Write to file
vm.writeFile(deploymentPath, json);
Logging.logInfo(string.concat("Deployment info saved to: ", deploymentPath));
}
function _deployDataHavenContracts(
AVSConfig memory avsConfig,
ProxyAdmin proxyAdmin,
IGatewayV2 gateway
) internal returns (DataHavenServiceManager, VetoableSlasher, RewardsRegistry) {
Logging.logHeader("DATAHAVEN CUSTOM CONTRACTS DEPLOYMENT");
// Deploy the Service Manager
vm.broadcast(_deployerPrivateKey);
DataHavenServiceManager serviceManagerImplementation =
new DataHavenServiceManager(rewardsCoordinator, permissionController, allocationManager);
Logging.logContractDeployed(
"ServiceManager Implementation", address(serviceManagerImplementation)
);
// Extract strategies logic to a helper function to reduce local variables
_prepareStrategiesForServiceManager(avsConfig, deployedStrategies);
// Create service manager initialisation parameters struct to reduce stack variables
ServiceManagerInitParams memory initParams = ServiceManagerInitParams({
avsOwner: avsConfig.avsOwner,
rewardsInitiator: avsConfig.rewardsInitiator,
validatorsStrategies: avsConfig.validatorsStrategies,
bspsStrategies: avsConfig.bspsStrategies,
mspsStrategies: avsConfig.mspsStrategies,
gateway: address(gateway)
});
// Create the service manager proxy
DataHavenServiceManager serviceManager =
_createServiceManagerProxy(serviceManagerImplementation, proxyAdmin, initParams);
Logging.logContractDeployed("ServiceManager Proxy", address(serviceManager));
// Deploy VetoableSlasher
vm.broadcast(_deployerPrivateKey);
VetoableSlasher vetoableSlasher = new VetoableSlasher(
allocationManager,
serviceManager,
avsConfig.vetoCommitteeMember,
avsConfig.vetoWindowBlocks
);
Logging.logContractDeployed("VetoableSlasher", address(vetoableSlasher));
// Deploy RewardsRegistry
vm.broadcast(_deployerPrivateKey);
RewardsRegistry rewardsRegistry = new RewardsRegistry(
address(serviceManager),
address(0) // Will be set to the Agent address after creation
);
Logging.logContractDeployed("RewardsRegistry", address(rewardsRegistry));
Logging.logSection("Configuring Service Manager");
// Register the DataHaven service in the AllocationManager
vm.broadcast(_avsOwnerPrivateKey);
serviceManager.updateAVSMetadataURI("");
Logging.logStep("DataHaven service registered in AllocationManager");
// Set the slasher in the ServiceManager
vm.broadcast(_avsOwnerPrivateKey);
serviceManager.setSlasher(vetoableSlasher);
Logging.logStep("Slasher set in ServiceManager");
// Set the RewardsRegistry in the ServiceManager
uint32 validatorsSetId = serviceManager.VALIDATORS_SET_ID();
vm.broadcast(_avsOwnerPrivateKey);
serviceManager.setRewardsRegistry(validatorsSetId, rewardsRegistry);
Logging.logStep("RewardsRegistry set in ServiceManager");
return (serviceManager, vetoableSlasher, rewardsRegistry);
}
function _createServiceManagerProxy(
DataHavenServiceManager implementation,
ProxyAdmin proxyAdmin,
ServiceManagerInitParams memory params
) internal returns (DataHavenServiceManager) {
vm.broadcast(_deployerPrivateKey);
bytes memory initData = abi.encodeWithSelector(
DataHavenServiceManager.initialise.selector,
params.avsOwner,
params.rewardsInitiator,
params.validatorsStrategies,
params.bspsStrategies,
params.mspsStrategies,
params.gateway
);
TransparentUpgradeableProxy proxy =
new TransparentUpgradeableProxy(address(implementation), address(proxyAdmin), initData);
return DataHavenServiceManager(address(proxy));
}
function _prepareStrategiesForServiceManager(
AVSConfig memory config,
StrategyInfo[] memory strategies
) internal pure {
if (config.validatorsStrategies.length == 0) {
config.validatorsStrategies = new address[](strategies.length);
config.bspsStrategies = new address[](strategies.length);
config.mspsStrategies = new address[](strategies.length);
for (uint256 i = 0; i < strategies.length; i++) {
config.validatorsStrategies[i] = strategies[i].address_;
config.bspsStrategies[i] = strategies[i].address_;
config.mspsStrategies[i] = strategies[i].address_;
}
}
}
}