mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
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>
859 lines
36 KiB
Solidity
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_;
|
|
}
|
|
}
|
|
}
|
|
}
|