mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
## Contracts upgrade command with simple version tracking This PR aims to take the most minimal changes from #438 to make the upgrade command available. So it adds the `bun cli contracts upgrade` command for deploying a new `DataHavenServiceManager` implementation and upgrading the proxy, and includes a simple version tracking via a `contracts/VERSION` file. ### Contracts **`DataHavenServiceManager.sol`** - Added `_version` storage variable - Added `DATAHAVEN_VERSION()` view function, - Added `updateVersion(string)` function gated by `onlyProxyAdmin` - Added `VersionUpdated` event - The version is set at initialization and updated atomically with proxy upgrades via `upgradeAndCall`. ### CLI **`bun cli contracts upgrade`** works in two modes: _dry-run_ or _execute_. **Dry-run (default)** Deploys the new implementation on-chain (signed by the deployer key), then prints a ready-to-submit JSON payload for the multisig to execute the proxy upgrade. No AVS owner key required. ```bash # Uses version from contracts/VERSION (standard workflow) bun cli contracts upgrade --chain hoodi # Override version for this upgrade only (warns if it differs from contracts/VERSION) bun cli contracts upgrade --chain hoodi --target x.y.z ``` Example output: ```json { "to": "0xProxyAdmin...", "value": "0", "data": "0x...", "description": "Upgrade ServiceManager proxy to 0xNewImpl... and set version to 1.1.0" } ``` **Execute mode (`--execute`)** Deploys the implementation and broadcasts the proxy upgrade + version update in a single atomic `upgradeAndCall` transaction. Requires `AVS_OWNER_PRIVATE_KEY`. Used mostly for testing. ```bash bun cli contracts upgrade --chain anvil --execute ``` --- ### Expected flow - Bump mannually contracts/VERSION (e.g., 1.1.0) - Run bun cli contracts upgrade --chain anvil|hoodi|mainnet
89 lines
4 KiB
Solidity
89 lines
4 KiB
Solidity
// SPDX-License-Identifier: UNLICENSED
|
|
pragma solidity ^0.8.27;
|
|
|
|
import {Script} from "forge-std/Script.sol";
|
|
import {console} from "forge-std/console.sol";
|
|
|
|
// DataHaven imports
|
|
import {DataHavenServiceManager} from "../../src/DataHavenServiceManager.sol";
|
|
|
|
// EigenLayer imports
|
|
import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol";
|
|
import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol";
|
|
|
|
// OpenZeppelin imports
|
|
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
|
|
import {
|
|
ITransparentUpgradeableProxy
|
|
} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
|
|
|
|
/**
|
|
* @title DeployImplementation
|
|
* @notice Script for deploying implementation contracts and upgrading proxies
|
|
*/
|
|
contract DeployImplementation is Script {
|
|
function run() public {
|
|
// This script is designed to be called with specific function selectors
|
|
// Use forge script with --sig "functionName()" to call specific functions
|
|
}
|
|
|
|
/**
|
|
* @notice Deploy new ServiceManager implementation
|
|
*/
|
|
function deployServiceManagerImpl() public {
|
|
console.log("Deploying ServiceManager Implementation...");
|
|
|
|
// Get constructor parameters from environment variables
|
|
address rewardsCoordinator = vm.envAddress("REWARDS_COORDINATOR");
|
|
address allocationManager = vm.envAddress("ALLOCATION_MANAGER");
|
|
|
|
require(rewardsCoordinator != address(0), "REWARDS_COORDINATOR not set");
|
|
require(allocationManager != address(0), "ALLOCATION_MANAGER not set");
|
|
|
|
uint256 deployerPrivateKey = uint256(vm.envBytes32("PRIVATE_KEY"));
|
|
vm.broadcast(deployerPrivateKey);
|
|
DataHavenServiceManager serviceManagerImpl = new DataHavenServiceManager(
|
|
RewardsCoordinator(rewardsCoordinator), AllocationManager(allocationManager)
|
|
);
|
|
|
|
console.log("ServiceManager Implementation deployed at:", address(serviceManagerImpl));
|
|
}
|
|
|
|
/**
|
|
* @notice Update ServiceManager proxy and set version in one transaction.
|
|
* @dev Uses upgradeAndCall so the version update is atomically bundled with the upgrade.
|
|
* updateVersion is gated by onlyProxyAdmin, and upgradeAndCall executes the calldata
|
|
* with msg.sender = ProxyAdmin — satisfying that check.
|
|
* The AVS owner owns the ProxyAdmin, so the trust chain is: AVS owner → ProxyAdmin → updateVersion.
|
|
*/
|
|
function updateServiceManagerProxyWithVersion() public {
|
|
console.log("Updating ServiceManager proxy with version...");
|
|
|
|
// Get addresses and version from environment variables
|
|
address serviceManager = vm.envAddress("SERVICE_MANAGER");
|
|
address newImplementation = vm.envAddress("SERVICE_MANAGER_IMPL");
|
|
address proxyAdmin = vm.envAddress("PROXY_ADMIN");
|
|
string memory newVersion = vm.envString("NEW_VERSION");
|
|
|
|
require(serviceManager != address(0), "SERVICE_MANAGER not set");
|
|
require(newImplementation != address(0), "SERVICE_MANAGER_IMPL not set");
|
|
require(newImplementation.code.length > 0, "SERVICE_MANAGER_IMPL is not a contract");
|
|
require(proxyAdmin != address(0), "PROXY_ADMIN not set");
|
|
require(bytes(newVersion).length > 0, "NEW_VERSION not set");
|
|
|
|
// Encode the updateVersion call — gated by onlyProxyAdmin, satisfied since
|
|
// upgradeAndCall executes this calldata with msg.sender = ProxyAdmin
|
|
bytes memory data = abi.encodeWithSignature("updateVersion(string)", newVersion);
|
|
|
|
// AVS owner owns the ProxyAdmin (transferred during deployment)
|
|
uint256 avsOwnerPrivateKey = uint256(vm.envBytes32("AVS_OWNER_PRIVATE_KEY"));
|
|
vm.broadcast(avsOwnerPrivateKey);
|
|
ProxyAdmin(proxyAdmin)
|
|
.upgradeAndCall(
|
|
ITransparentUpgradeableProxy(payable(serviceManager)), newImplementation, data
|
|
);
|
|
|
|
console.log("ServiceManager proxy updated to:", newImplementation);
|
|
console.log("Version updated to:", newVersion);
|
|
}
|
|
}
|