feat: support updating the AVS dashboard metadata (#136)

## Key changes
- Add CLI command to update AVS metadata URI on-chain via
`updateAVSMetadataURI` function. Use:
  - `bun cli contracts update-metadata --chain <...> --uri <...>`
- Support for multiple chains (tipicaly holesky, hoodi, or a mainnet)
- Tx confirmation and gas usage reporting

---------

Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
This commit is contained in:
Gonza Montiel 2025-09-02 15:54:47 +02:00 committed by GitHub
parent c661a94014
commit 9f6614770c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 117 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View file

@ -0,0 +1,7 @@
{
"name": "DataHaven",
"website": "https://datahaven.xyz/",
"description": "DataHaven is a decentralized, EigenLayer-secured AVS for distributed storage. By leveraging restaking, it ensures tamper-proof, censorship-resistant, and verifiable data persistence. Designed with AI and Web3 ecosystems in mind, DataHaven integrates seamlessly with smart contracts, offering developers reliable storage infrastructure for models, logs, and digital assets at scale..",
"logo": "https://raw.githubusercontent.com/datahaven-xyz/datahaven-files/refs/heads/main/files/datahaven-logo.png",
"twitter": "https://x.com/datahaven_xyz"
}

View file

@ -9,5 +9,5 @@ AVS_OWNER_PRIVATE_KEY=0x00000000000000000000000000000000000000000000000000000000
# Etherscan API key for contract verification (optional)
# Get your API key from: https://etherscan.io/apis
# This is used for automatic contract verification on Hoodi block explorer
# ETHERSCAN_API_KEY=your_etherscan_api_key_here
# This is used for contract verification on Etherscan
ETHERSCAN_API_KEY=your_etherscan_api_key_here

View file

@ -1,3 +1,4 @@
export * from "./deploy";
export * from "./status";
export * from "./update-metadata";
export * from "./verify";

View file

@ -0,0 +1,75 @@
import { logger, parseDeploymentsFile, printDivider } from "utils";
import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { getChainDeploymentParams } from "../../../configs/contracts/config";
import { dataHavenServiceManagerAbi } from "../../../contract-bindings/generated";
/**
* Updates the AVS metadata URI for the DataHaven Service Manager
*/
export const updateAVSMetadataURI = async (chain: string, uri: string) => {
try {
// Load environment variables
const avsOwnerPrivateKey = process.env.AVS_OWNER_PRIVATE_KEY;
if (!avsOwnerPrivateKey) {
throw new Error("AVS_OWNER_PRIVATE_KEY environment variable is required");
}
// Get chain configuration
const deploymentParams = getChainDeploymentParams(chain);
logger.info(`🫎 Updating AVS metadata URI on ${chain} chain`);
logger.info(`Network: ${deploymentParams.network} (Chain ID: ${deploymentParams.chainId})`);
logger.info(`RPC URL: ${deploymentParams.rpcUrl}`);
logger.info(`New URI: ${uri}`);
// Create wallet client for the AVS owner
const account = privateKeyToAccount(avsOwnerPrivateKey as `0x${string}`);
const walletClient = createWalletClient({
account,
transport: http(deploymentParams.rpcUrl)
});
// Create public client for reading transaction receipts
const publicClient = createPublicClient({
transport: http(deploymentParams.rpcUrl)
});
logger.info(`Using account: ${account.address}`);
const deployments = await parseDeploymentsFile(chain);
const serviceManagerAddress = deployments.ServiceManager;
logger.info(`ServiceManager contract address: ${serviceManagerAddress}`);
// Call the updateAVSMetadataURI function
logger.info("📝 Calling updateAVSMetadataURI...");
const hash = await walletClient.writeContract({
address: serviceManagerAddress,
abi: dataHavenServiceManagerAbi,
functionName: "updateAVSMetadataURI",
args: [uri],
chain: null
});
logger.info("✅ Transaction submitted successfully!");
logger.info(`Transaction hash: ${hash}`);
// Wait for transaction confirmation
logger.info("⏳ Waiting for transaction confirmation...");
const receipt = await publicClient.waitForTransactionReceipt({ hash });
if (receipt.status === "success") {
logger.info(`✅ Transaction confirmed in block ${receipt.blockNumber}`);
logger.info(`Gas used: ${receipt.gasUsed}`);
} else {
logger.error("❌ Transaction failed");
}
printDivider();
return hash;
} catch (error) {
logger.error(`❌ Failed to update AVS metadata URI: ${error}`);
throw error;
}
};

View file

@ -11,7 +11,8 @@ import {
launch,
launchPreActionHook,
stop,
stopPreActionHook
stopPreActionHook,
updateAVSMetadataURI
} from "./handlers";
// Function to parse integer
@ -187,6 +188,7 @@ const contractsCommand = program
- status: Show deployment plan, configuration, and status (default)
- deploy: Deploy contracts to specified chain
- verify: Verify deployed contracts on block explorer
- update-metadata: Update the metadata URI of an existing AVS contract
Common options:
--chain: Target chain (required: hoodi, holesky, mainnet)
@ -229,6 +231,35 @@ contractsCommand
.hook("preAction", contractsPreActionHook)
.action(contractsVerify);
// Contracts Update Metadata
contractsCommand
.command("update-metadata")
.description("Update AVS metadata URI for the DataHaven Service Manager")
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet)")
.option("--uri <value>", "New metadata URI (required)")
.option("--reset", "Use if you want to reset the metadata URI")
.option("--rpc-url <value>", "Chain RPC URL (optional, defaults based on chain)")
.action(async (options: any, command: any) => {
// Try to get chain from options or command
let chain = options.chain;
if (!chain && command.parent) {
chain = command.parent.getOptionValue("chain");
}
if (!chain) {
chain = command.getOptionValue("chain");
}
if (!options.uri && !options.reset) {
throw new Error("--uri parameter is required");
}
if (options.reset) {
options.uri = "";
}
if (!chain) {
throw new Error("--chain parameter is required");
}
await updateAVSMetadataURI(chain, options.uri);
});
// Default Contracts command (runs check)
contractsCommand
.description("Show deployment plan, configuration, and status")