datahaven/test/utils/anvil.ts
Gonza Montiel 7097767021
feat: contracts upgrade command (#463)
## 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
2026-03-02 21:50:10 +01:00

48 lines
1.8 KiB
TypeScript

import { getPortFromKurtosis } from "./kurtosis";
import { logger } from "./logger";
/**
* Gets the RPC URL for the Anvil (local Ethereum) node running in Kurtosis
* @param enclaveName - The name of the Kurtosis enclave (default: "datahaven-ethereum")
* @returns The HTTP RPC URL for the Ethereum node
*/
export const getAnvilRpcUrl = async (enclaveName = "datahaven-ethereum"): Promise<string> => {
try {
logger.debug("Getting Anvil RPC URL from Kurtosis...");
// Get the RPC port from the EL (Execution Layer) service
const rpcPort = await getPortFromKurtosis("el-1-reth-lodestar", "rpc", enclaveName);
const rpcUrl = `http://127.0.0.1:${rpcPort}`;
logger.debug(`Anvil RPC URL: ${rpcUrl}`);
return rpcUrl;
} catch (error) {
logger.warn(`⚠️ Failed to get Anvil RPC URL from Kurtosis: ${error}`);
logger.warn(" Falling back to default http://localhost:8545");
return "http://localhost:8545";
}
};
/**
* Gets the WebSocket URL for the Anvil (local Ethereum) node running in Kurtosis
* @param enclaveName - The name of the Kurtosis enclave (default: "datahaven-ethereum")
* @returns The WebSocket URL for the Ethereum node
*/
export const getAnvilWsUrl = async (enclaveName = "datahaven-ethereum"): Promise<string> => {
try {
logger.debug("Getting Anvil WebSocket URL from Kurtosis...");
// Get the WS port from the EL (Execution Layer) service
const wsPort = await getPortFromKurtosis("el-1-reth-lodestar", "ws", enclaveName);
const wsUrl = `ws://127.0.0.1:${wsPort}`;
logger.debug(`Anvil WebSocket URL: ${wsUrl}`);
return wsUrl;
} catch (error) {
logger.warn(`⚠️ Failed to get Anvil WebSocket URL from Kurtosis: ${error}`);
logger.warn(" Falling back to default ws://localhost:8546");
return "ws://localhost:8546";
}
};