mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 09:50:01 +00:00
## Summary - Add stagenet-hoodi deployment artifacts (contract addresses, rewards info) and update Snowbridge config with latest validator set - Fix the `bun cli contracts verify` command to correctly verify all deployed contracts, including proxy contracts and Snowbridge dependencies - Fix the `bun cli contracts update-metadata` command to use the correct config file when `--environment` is specified ## Contract verification fixes The verification CLI hardcoded all contract source paths as `src/<Name>.sol`, which failed for: - **Snowbridge contracts** (Gateway, BeefyClient, AgentExecutor) — these live in `lib/snowbridge/contracts/src/` - **Gateway proxy** — the `Gateway` deployment address is actually a `GatewayProxy`, not the Gateway implementation. The implementation address needs to be resolved from the ERC1967 storage slot - **ServiceManager proxy** — was not being verified at all Changes: - Added `contractPath` field to `ContractToVerify` so each contract specifies its source location relative to the contracts directory - Added `guessConstructorArgs` option for proxy contracts with complex encoded init data (uses forge's `--guess-constructor-args`) - Gateway is now verified as two separate contracts: Gateway Implementation (address resolved from ERC1967 proxy slot) and GatewayProxy - ServiceManager proxy is now verified as `TransparentUpgradeableProxy` ## Update-metadata fix The `update-metadata` command was ignoring the `--environment` flag when selecting the deployments file: 1. The handler received a pre-built networkId (`"stagenet-hoodi"`) as the chain parameter, which `getChainDeploymentParams` couldn't resolve (falling back to anvil). Now chain and environment are passed separately. 2. Commander.js routed `--environment` to the parent contracts command, leaving `options.environment` undefined on the subcommand. Added the same parent-fallback logic already used for `--chain`. ## Test plan - [x] `bun typecheck` passes - [x] Ran `bun cli contracts verify --chain hoodi --environment stagenet` — all contracts verified successfully on Etherscan - [x] `bun cli contracts update-metadata --chain hoodi --environment stagenet` now reads the correct `stagenet-hoodi.json` deployments file --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
111 lines
3.8 KiB
TypeScript
111 lines
3.8 KiB
TypeScript
import { logger, parseDeploymentsFile, printDivider } from "utils";
|
|
import { createPublicClient, createWalletClient, encodeFunctionData, http } from "viem";
|
|
import { privateKeyToAccount } from "viem/accounts";
|
|
import { buildNetworkId, 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,
|
|
opts: { execute?: boolean; avsOwnerKey?: string; environment?: string } = {}
|
|
) => {
|
|
try {
|
|
const execute = opts.execute ?? false;
|
|
const avsOwnerPrivateKey = normalizePrivateKey(
|
|
opts.avsOwnerKey || process.env.AVS_OWNER_PRIVATE_KEY
|
|
);
|
|
|
|
if (execute && !avsOwnerPrivateKey) {
|
|
throw new Error("AVS owner private key is required to execute this transaction");
|
|
}
|
|
|
|
// Get chain configuration using base chain name, and build networkId for deployment file lookup
|
|
const networkId = buildNetworkId(chain, opts.environment);
|
|
const deploymentParams = getChainDeploymentParams(chain);
|
|
logger.info(`🫎 Updating AVS metadata URI on ${networkId}`);
|
|
logger.info(`Network: ${deploymentParams.network} (Chain ID: ${deploymentParams.chainId})`);
|
|
logger.info(`RPC URL: ${deploymentParams.rpcUrl}`);
|
|
logger.info(`New URI: ${uri}`);
|
|
|
|
const deployments = await parseDeploymentsFile(networkId);
|
|
const serviceManagerAddress = deployments.ServiceManager;
|
|
|
|
if (!serviceManagerAddress) {
|
|
throw new Error("ServiceManager address not found in deployments file");
|
|
}
|
|
|
|
const calldata = encodeFunctionData({
|
|
abi: dataHavenServiceManagerAbi,
|
|
functionName: "updateAVSMetadataURI",
|
|
args: [uri]
|
|
});
|
|
|
|
if (!execute) {
|
|
logger.info("🔐 Tx execution disabled: submit the following transaction via your multisig");
|
|
const payload = {
|
|
to: serviceManagerAddress,
|
|
value: "0",
|
|
data: calldata
|
|
};
|
|
logger.info(JSON.stringify(payload, null, 2));
|
|
printDivider();
|
|
return payload;
|
|
}
|
|
|
|
// 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}`);
|
|
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;
|
|
}
|
|
};
|
|
|
|
const normalizePrivateKey = (key?: string): `0x${string}` | undefined => {
|
|
if (!key) {
|
|
return undefined;
|
|
}
|
|
return (key.startsWith("0x") ? key : `0x${key}`) as `0x${string}`;
|
|
};
|