mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-23 17:28:23 +00:00
Fix: command cli deploy contracts (#319)
## Summary This PR fixes several issues with the CLI deploy-contracts command to properly support local Anvil deployments and improves the overall contract deployment workflow. ### Key fixes: - Add support for anvil chain in the CLI deploy contracts command - Rename PRIVATE_KEY to DEPLOYER_PRIVATE_KEY for consistency and clarity across the deployment flow - Fix EigenLayer contract status display for local/anvil chains by reading addresses from the deployments file instead of config - Fix runShellCommandWithLogger to properly throw errors on command failure - Correct totalSteps in DeployTestnet.s.sol from 2 to 4 ### Housekeeping: - Update .gitignore to ignore the entire broadcast/ folder (autogenerated Foundry artifacts) - Streamline contracts/README.md with clearer structure and deployment instructions
This commit is contained in:
parent
0618e84268
commit
ffd01d8f1d
11 changed files with 143 additions and 152 deletions
6
contracts/.gitignore
vendored
6
contracts/.gitignore
vendored
|
|
@ -2,10 +2,8 @@
|
|||
cache/
|
||||
out/
|
||||
|
||||
# Ignores development broadcast logs
|
||||
!/broadcast
|
||||
/broadcast/*/3*/
|
||||
/broadcast/**/dry-run/
|
||||
# Ignores development broadcast logs (autogenerated by forge script --broadcast)
|
||||
broadcast/
|
||||
|
||||
# Docs
|
||||
docs/
|
||||
|
|
|
|||
|
|
@ -1,145 +1,71 @@
|
|||
# DataHaven AVS Smart Contracts 📜
|
||||
# DataHaven AVS Smart Contracts
|
||||
|
||||
This directory contains the smart contracts for the DataHaven Actively Validated Service (AVS) built on EigenLayer.
|
||||
|
||||
## Overview
|
||||
|
||||
DataHaven is an EVM-compatible Substrate blockchain secured by EigenLayer. These contracts implement the AVS Service Manager, middleware, and associated utilities that integrate with EigenLayer's operator registration, slashing, and rewards infrastructure.
|
||||
Implements the Actively Validated Service (AVS) logic for DataHaven, secured by EigenLayer. These contracts manage operator registration, handle cross-chain rewards via Snowbridge, and enforce slashing with a veto period.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
contracts/
|
||||
├── src/ # Smart contract source code
|
||||
├── src/
|
||||
│ ├── DataHavenServiceManager.sol # Core AVS service manager
|
||||
│ ├── RewardsRegistry.sol # Validator performance & rewards tracking
|
||||
│ ├── VetoableSlasher.sol # Slashing with veto period
|
||||
│ ├── middleware/ # RewardsRegistry, VetoableSlasher, Snowbridge helpers
|
||||
│ ├── interfaces/ # Contract interfaces
|
||||
│ ├── libraries/ # Utility libraries
|
||||
│ └── middleware/ # EigenLayer middleware integration
|
||||
├── script/ # Deployment & setup scripts
|
||||
│ └── deploy/ # Environment-specific deployment
|
||||
├── test/ # Foundry test suites
|
||||
└── foundry.toml # Foundry configuration
|
||||
│ └── libraries/ # Utility libraries
|
||||
├── script/ # Deployment & setup scripts
|
||||
├── lib/ # External dependencies (EigenLayer, Snowbridge, OpenZeppelin)
|
||||
└── test/ # Foundry test suites
|
||||
```
|
||||
|
||||
### Key Contracts
|
||||
## Key Components
|
||||
|
||||
- **DataHavenServiceManager**: Manages operator lifecycle, registration, and deregistration with EigenLayer
|
||||
- **RewardsRegistry**: Tracks validator performance metrics and handles reward distribution via Snowbridge
|
||||
- **VetoableSlasher**: Implements slashing mechanism with dispute resolution veto period
|
||||
- **Middleware**: Integration layer with EigenLayer's core contracts (based on [eigenlayer-middleware](https://github.com/Layr-Labs/eigenlayer-middleware))
|
||||
- **DataHavenServiceManager** (`src/DataHavenServiceManager.sol`): Core contract for operator lifecycle; inherits `ServiceManagerBase`.
|
||||
- **RewardsRegistry** (`src/middleware/RewardsRegistry.sol`): Tracks validator performance and distributes rewards via Snowbridge.
|
||||
- **VetoableSlasher** (`src/middleware/VetoableSlasher.sol`): Handles slashing requests with a dispute resolution veto window.
|
||||
|
||||
## Prerequisites
|
||||
## Development
|
||||
|
||||
- [Foundry](https://book.getfoundry.sh/getting-started/installation)
|
||||
|
||||
## Build
|
||||
|
||||
To build the contracts:
|
||||
Requires [Foundry](https://book.getfoundry.sh).
|
||||
|
||||
```bash
|
||||
cd contracts
|
||||
# Build and Test
|
||||
forge build
|
||||
```
|
||||
|
||||
This will compile all contracts and generate artifacts in the `out` directory.
|
||||
|
||||
## Test
|
||||
|
||||
Run the test suite with:
|
||||
|
||||
```bash
|
||||
forge test
|
||||
```
|
||||
|
||||
For more verbose output including logs:
|
||||
|
||||
```bash
|
||||
forge test -vv
|
||||
```
|
||||
|
||||
For maximum verbosity including stack traces:
|
||||
|
||||
```bash
|
||||
forge test -vvvv
|
||||
```
|
||||
|
||||
Run specific test contracts:
|
||||
|
||||
```bash
|
||||
forge test --match-contract RewardsRegistry
|
||||
```
|
||||
|
||||
Run specific test functions:
|
||||
|
||||
```bash
|
||||
forge test --match-test test_newRewardsMessage
|
||||
```
|
||||
|
||||
Exclude specific tests:
|
||||
|
||||
```bash
|
||||
forge test --no-match-test test_newRewardsMessage_OnlyRewardsAgent
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
### Local Deployment
|
||||
|
||||
1. In a separate terminal, start a local Anvil instance:
|
||||
|
||||
```bash
|
||||
anvil
|
||||
```
|
||||
|
||||
2. Deploy to local Anvil:
|
||||
|
||||
```bash
|
||||
forge script script/deploy/DeployLocal.s.sol --rpc-url anvil --broadcast
|
||||
```
|
||||
|
||||
### Network Deployment
|
||||
|
||||
To deploy to a network configured in `foundry.toml`:
|
||||
|
||||
```bash
|
||||
forge script script/deploy/DeployLocal.s.sol --rpc-url $NETWORK_RPC_URL --private-key $PRIVATE_KEY --broadcast
|
||||
```
|
||||
|
||||
Replace `$NETWORK_RPC_URL` with the RPC endpoint and `$PRIVATE_KEY` with your deployer's private key.
|
||||
|
||||
Or using a network from `foundry.toml`:
|
||||
|
||||
```bash
|
||||
forge script script/deploy/DeployLocal.s.sol --rpc-url mainnet --private-key $PRIVATE_KEY --broadcast
|
||||
# Regenerate TS bindings (after contract changes)
|
||||
cd ../test && bun generate:wagmi
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The deployment configuration can be modified in:
|
||||
Deployment parameters (EigenLayer addresses, initial validators, owners) are defined in `contracts/config/<network>.json`.
|
||||
- **Do not edit** `Config.sol` or `DeployParams.s.sol` directly; they only load the JSON.
|
||||
- Ensure `contracts/config/hoodi.json` (or `holesky.json`) matches your target environment before deploying.
|
||||
|
||||
- `script/deploy/Config.sol`: Environment-specific configuration
|
||||
- `script/deploy/DeployParams.s.sol`: Deployment parameters
|
||||
## Deployment
|
||||
|
||||
## Code Generation
|
||||
|
||||
After making changes to contracts, regenerate TypeScript bindings for the test framework:
|
||||
Two deployment paths exist: **Local** (Anvil) and **Testnet** (Hoodi/Holesky). Both install the **DataHaven AVS contracts** (ServiceManager, RewardsRegistry, VetoableSlasher) and **Snowbridge** (BeefyClient, Gateway, Agent). They differ in EigenLayer setup:
|
||||
|
||||
### Local (Anvil)
|
||||
**`DeployLocal.s.sol`** bootstraps a full EigenLayer core deployment (DelegationManager, StrategyManager, AVSDirectory, etc.) alongside DataHaven AVS and Snowbridge.
|
||||
```bash
|
||||
cd ../test
|
||||
bun generate:wagmi
|
||||
anvil
|
||||
forge script script/deploy/DeployLocal.s.sol --rpc-url anvil --broadcast
|
||||
```
|
||||
|
||||
This generates type-safe contract interfaces used by the E2E test suite.
|
||||
### Testnet (Hoodi / Holesky)
|
||||
**`DeployTestnet.s.sol`** references existing EigenLayer contracts (addresses from `contracts/config/<network>.json`) and only deploys DataHaven AVS + Snowbridge.
|
||||
```bash
|
||||
NETWORK=hoodi forge script script/deploy/DeployTestnet.s.sol \
|
||||
--rpc-url hoodi \
|
||||
--private-key $PRIVATE_KEY \
|
||||
--broadcast
|
||||
```
|
||||
Supported networks: `hoodi`, `holesky` (no mainnet config yet). Artifacts → `contracts/deployments/<network>.json`.
|
||||
|
||||
## Integration with DataHaven
|
||||
## How It Works
|
||||
1. **Registration**: Validators register with EigenLayer via `DataHavenServiceManager`.
|
||||
2. **Performance Tracking**: DataHaven computes reward points and sends a Merkle root to `RewardsRegistry` on Ethereum via Snowbridge.
|
||||
3. **Rewards Claims**: Validators claim rewards on Ethereum from `RewardsRegistry` using Merkle proofs.
|
||||
4. **Slashing**: Misbehavior triggers `VetoableSlasher` (subject to veto period).
|
||||
|
||||
These contracts integrate with the DataHaven Substrate node through:
|
||||
|
||||
1. **Operator Registration**: Validators register on-chain via `DataHavenServiceManager`
|
||||
2. **Performance Tracking**: Node submits validator metrics to `RewardsRegistry`
|
||||
3. **Cross-chain Rewards**: Rewards distributed from Ethereum to DataHaven via Snowbridge
|
||||
4. **Slashing**: Misbehavior triggers slashing through `VetoableSlasher` with veto period
|
||||
|
||||
For full network integration testing, see the [test directory](../test/README.md).
|
||||
See `test/README.md` for full network integration tests.
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
|
|||
_logProgress();
|
||||
|
||||
// Deploy Snowbridge (same for both modes)
|
||||
Logging.logHeader("SNOWBRIDGE DEPLOYMENT");
|
||||
(
|
||||
BeefyClient beefyClient,
|
||||
AgentExecutor agentExecutor,
|
||||
|
|
@ -170,6 +169,8 @@ abstract contract DeployBase is Script, DeployParams, Accounts {
|
|||
function _deploySnowbridge(
|
||||
SnowbridgeConfig memory config
|
||||
) internal returns (BeefyClient, AgentExecutor, IGatewayV2, address payable) {
|
||||
Logging.logHeader("SNOWBRIDGE DEPLOYMENT");
|
||||
|
||||
Logging.logSection("Deploying Snowbridge Core Components");
|
||||
|
||||
BeefyClient beefyClient = _deployBeefyClient(config);
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ contract DeployTestnet is DeployBase {
|
|||
);
|
||||
|
||||
currentTestnet = _detectAndValidateNetwork(networkName);
|
||||
totalSteps = 2; // Reduced steps since we're not deploying EigenLayer
|
||||
totalSteps = 4;
|
||||
|
||||
_executeSharedDeployment();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Copy this file to .env and fill in your values
|
||||
|
||||
# Private key for contract deployment (REQUIRED)
|
||||
PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000000
|
||||
DEPLOYER_PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
# AVS Owner private key (for post-deployment configuration)
|
||||
AVS_OWNER_PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000000
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ cd test && cp cli/handlers/contracts/.env.example .env
|
|||
Edit `.env` with your values:
|
||||
```bash
|
||||
# Required: Private key with deployment funds
|
||||
PRIVATE_KEY=0x...
|
||||
DEPLOYER_PRIVATE_KEY=0x...
|
||||
|
||||
# Required: AVS owner private key (can be same as PRIVATE_KEY)
|
||||
# Required: AVS owner private key (can be same as DEPLOYER_PRIVATE_KEY)
|
||||
AVS_OWNER_PRIVATE_KEY=0x...
|
||||
|
||||
# Optional: For contract verification
|
||||
|
|
|
|||
|
|
@ -91,17 +91,19 @@ export const contractsPreActionHook = async (thisCommand: any) => {
|
|||
const privateKey = thisCommand.getOptionValue("privateKey");
|
||||
|
||||
if (!chain) {
|
||||
logger.error("❌ Chain is required. Use --chain option (hoodi, holesky, mainnet)");
|
||||
logger.error("❌ Chain is required. Use --chain option (hoodi, holesky, mainnet, anvil)");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const supportedChains = ["hoodi", "holesky", "mainnet"];
|
||||
const supportedChains = ["hoodi", "holesky", "mainnet", "anvil"];
|
||||
if (!supportedChains.includes(chain)) {
|
||||
logger.error(`❌ Unsupported chain: ${chain}. Supported chains: ${supportedChains.join(", ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!privateKey) {
|
||||
logger.warn("⚠️ Private key not provided. Will use PRIVATE_KEY environment variable");
|
||||
if (!privateKey && !process.env.DEPLOYER_PRIVATE_KEY) {
|
||||
logger.warn(
|
||||
"⚠️ Private key not provided. Will use DEPLOYER_PRIVATE_KEY environment variable if set, or default Anvil key."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ export const showDeploymentPlanAndStatus = async (chain: string) => {
|
|||
await showEigenLayerContractStatus(
|
||||
config,
|
||||
deploymentParams.chainId.toString(),
|
||||
deploymentParams.rpcUrl
|
||||
deploymentParams.rpcUrl,
|
||||
chain
|
||||
);
|
||||
|
||||
printDivider();
|
||||
|
|
@ -109,27 +110,69 @@ const showDatahavenContractStatus = async (chain: string, rpcUrl: string) => {
|
|||
/**
|
||||
* Shows the status of EigenLayer contracts (verification only)
|
||||
*/
|
||||
const showEigenLayerContractStatus = async (config: any, chainId: string, rpcUrl: string) => {
|
||||
const showEigenLayerContractStatus = async (
|
||||
config: any,
|
||||
chainId: string,
|
||||
rpcUrl: string,
|
||||
chain: string
|
||||
) => {
|
||||
try {
|
||||
// For local/anvil deployments, read addresses from deployments file
|
||||
// For testnet/mainnet, use addresses from config file
|
||||
let eigenLayerAddresses: Record<string, string> = {};
|
||||
const isLocal = chain === "anvil" || chain === "local";
|
||||
|
||||
if (isLocal) {
|
||||
try {
|
||||
const deploymentsPath = `../contracts/deployments/${chain === "local" ? "anvil" : chain}.json`;
|
||||
const deploymentsFile = Bun.file(deploymentsPath);
|
||||
if (await deploymentsFile.exists()) {
|
||||
const deployments = await deploymentsFile.json();
|
||||
eigenLayerAddresses = {
|
||||
DelegationManager: deployments.DelegationManager,
|
||||
StrategyManager: deployments.StrategyManager,
|
||||
EigenPodManager: deployments.EigenPodManager,
|
||||
AVSDirectory: deployments.AVSDirectory,
|
||||
RewardsCoordinator: deployments.RewardsCoordinator,
|
||||
AllocationManager: deployments.AllocationManager,
|
||||
PermissionController: deployments.PermissionController
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug(`Could not read deployments file for EigenLayer contracts: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
const contracts = [
|
||||
{
|
||||
name: "DelegationManager",
|
||||
address: config.eigenLayer.delegationManager
|
||||
address: eigenLayerAddresses.DelegationManager || config.eigenLayer?.delegationManager || ""
|
||||
},
|
||||
{
|
||||
name: "StrategyManager",
|
||||
address: eigenLayerAddresses.StrategyManager || config.eigenLayer?.strategyManager || ""
|
||||
},
|
||||
{
|
||||
name: "EigenPodManager",
|
||||
address: eigenLayerAddresses.EigenPodManager || config.eigenLayer?.eigenPodManager || ""
|
||||
},
|
||||
{
|
||||
name: "AVSDirectory",
|
||||
address: eigenLayerAddresses.AVSDirectory || config.eigenLayer?.avsDirectory || ""
|
||||
},
|
||||
{ name: "StrategyManager", address: config.eigenLayer.strategyManager },
|
||||
{ name: "EigenPodManager", address: config.eigenLayer.eigenPodManager },
|
||||
{ name: "AVSDirectory", address: config.eigenLayer.avsDirectory },
|
||||
{
|
||||
name: "RewardsCoordinator",
|
||||
address: config.eigenLayer.rewardsCoordinator
|
||||
address:
|
||||
eigenLayerAddresses.RewardsCoordinator || config.eigenLayer?.rewardsCoordinator || ""
|
||||
},
|
||||
{
|
||||
name: "AllocationManager",
|
||||
address: config.eigenLayer.allocationManager
|
||||
address: eigenLayerAddresses.AllocationManager || config.eigenLayer?.allocationManager || ""
|
||||
},
|
||||
{
|
||||
name: "PermissionController",
|
||||
address: config.eigenLayer.permissionController
|
||||
address:
|
||||
eigenLayerAddresses.PermissionController || config.eigenLayer?.permissionController || ""
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ const contractsCommand = program
|
|||
- update-metadata: Update the metadata URI of an existing AVS contract
|
||||
|
||||
Common options:
|
||||
--chain: Target chain (required: hoodi, holesky, mainnet)
|
||||
--chain: Target chain (required: hoodi, holesky, mainnet, anvil)
|
||||
--rpc-url: Chain RPC URL (optional, defaults based on chain)
|
||||
--private-key: Private key for deployment
|
||||
--skip-verification: Skip contract verification
|
||||
|
|
@ -210,9 +210,13 @@ const contractsCommand = program
|
|||
contractsCommand
|
||||
.command("status")
|
||||
.description("Show deployment plan, configuration, and status")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet)")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet, anvil)")
|
||||
.option("--rpc-url <value>", "Chain RPC URL (optional, defaults based on chain)")
|
||||
.option("--private-key <value>", "Private key for deployment", process.env.PRIVATE_KEY || "")
|
||||
.option(
|
||||
"--private-key <value>",
|
||||
"Private key for deployment",
|
||||
process.env.DEPLOYER_PRIVATE_KEY || ""
|
||||
)
|
||||
.option("--skip-verification", "Skip contract verification", false)
|
||||
.hook("preAction", contractsPreActionHook)
|
||||
.action(contractsCheck);
|
||||
|
|
@ -221,9 +225,13 @@ contractsCommand
|
|||
contractsCommand
|
||||
.command("deploy")
|
||||
.description("Deploy DataHaven AVS contracts to specified chain")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet)")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet, anvil)")
|
||||
.option("--rpc-url <value>", "Chain RPC URL (optional, defaults based on chain)")
|
||||
.option("--private-key <value>", "Private key for deployment", process.env.PRIVATE_KEY || "")
|
||||
.option(
|
||||
"--private-key <value>",
|
||||
"Private key for deployment",
|
||||
process.env.DEPLOYER_PRIVATE_KEY || ""
|
||||
)
|
||||
.option("--skip-verification", "Skip contract verification", false)
|
||||
.hook("preAction", contractsPreActionHook)
|
||||
.action(contractsDeploy);
|
||||
|
|
@ -232,7 +240,7 @@ contractsCommand
|
|||
contractsCommand
|
||||
.command("verify")
|
||||
.description("Verify deployed contracts on block explorer")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet)")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet, anvil)")
|
||||
.option("--rpc-url <value>", "Chain RPC URL (optional, defaults based on chain)")
|
||||
.option("--skip-verification", "Skip contract verification", false)
|
||||
.hook("preAction", contractsPreActionHook)
|
||||
|
|
@ -242,7 +250,7 @@ contractsCommand
|
|||
contractsCommand
|
||||
.command("update-metadata")
|
||||
.description("Update AVS metadata URI for the DataHaven Service Manager")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet)")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet, anvil)")
|
||||
.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)")
|
||||
|
|
@ -270,9 +278,13 @@ contractsCommand
|
|||
// Default Contracts command (runs check)
|
||||
contractsCommand
|
||||
.description("Show deployment plan, configuration, and status")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet)")
|
||||
.option("--chain <value>", "Target chain (hoodi, holesky, mainnet, anvil)")
|
||||
.option("--rpc-url <value>", "Chain RPC URL (optional, defaults based on chain)")
|
||||
.option("--private-key <value>", "Private key for deployment", process.env.PRIVATE_KEY || "")
|
||||
.option(
|
||||
"--private-key <value>",
|
||||
"Private key for deployment",
|
||||
process.env.DEPLOYER_PRIVATE_KEY || ""
|
||||
)
|
||||
.option("--skip-verification", "Skip contract verification", false)
|
||||
.hook("preAction", contractsPreActionHook)
|
||||
.action(contractsCheck);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const constructDeployCommand = (options: ContractDeploymentOptions): stri
|
|||
const { chain, rpcUrl, verified, blockscoutBackendUrl } = options;
|
||||
|
||||
const deploymentScript =
|
||||
!chain || chain === "anvil" || chain === "local"
|
||||
!chain || chain === "anvil"
|
||||
? "script/deploy/DeployLocal.s.sol"
|
||||
: "script/deploy/DeployTestnet.s.sol";
|
||||
|
||||
|
|
@ -83,12 +83,16 @@ export const constructDeployCommand = (options: ContractDeploymentOptions): stri
|
|||
export const executeDeployment = async (
|
||||
deployCommand: string,
|
||||
parameterCollection?: ParameterCollection,
|
||||
chain?: string
|
||||
chain?: string,
|
||||
privateKey?: string
|
||||
) => {
|
||||
logger.info("⌛️ Deploying contracts (this might take a few minutes)...");
|
||||
|
||||
// Using custom shell command to improve logging with forge's stdoutput
|
||||
await runShellCommandWithLogger(deployCommand, { cwd: "../contracts" });
|
||||
await runShellCommandWithLogger(deployCommand, {
|
||||
cwd: "../contracts",
|
||||
env: privateKey ? { DEPLOYER_PRIVATE_KEY: privateKey } : undefined
|
||||
});
|
||||
|
||||
// After deployment, read the:
|
||||
// - Gateway address
|
||||
|
|
@ -198,7 +202,7 @@ export const deployContracts = async (options: {
|
|||
|
||||
// Construct and execute deployment
|
||||
const deployCommand = constructDeployCommand(deploymentOptions);
|
||||
await executeDeployment(deployCommand);
|
||||
await executeDeployment(deployCommand, undefined, options.chain, options.privateKey);
|
||||
|
||||
logger.success(`DataHaven contracts deployed successfully to ${options.chain}`);
|
||||
};
|
||||
|
|
@ -251,5 +255,5 @@ if (import.meta.main) {
|
|||
await buildContracts();
|
||||
|
||||
const deployCommand = constructDeployCommand(options);
|
||||
await executeDeployment(deployCommand);
|
||||
await executeDeployment(deployCommand, undefined, undefined, options.privateKey);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@ export const runShellCommandWithLogger = async (
|
|||
env?: object;
|
||||
logLevel?: LogLevel;
|
||||
waitFor?: (...args: unknown[]) => Promise<void>;
|
||||
throwOnError?: boolean;
|
||||
}
|
||||
) => {
|
||||
const { cwd = ".", env = {}, logLevel = "info" as LogLevel } = options || {};
|
||||
const { cwd = ".", env = {}, logLevel = "info" as LogLevel, throwOnError = true } = options || {};
|
||||
|
||||
try {
|
||||
if (!existsSync(cwd)) {
|
||||
|
|
@ -92,6 +93,10 @@ export const runShellCommandWithLogger = async (
|
|||
trimmedStderr.includes("\n") ? `>_ \n${trimmedStderr}` : `>_ ${trimmedStderr}`
|
||||
);
|
||||
}
|
||||
|
||||
if (throwOnError) {
|
||||
throw new Error(`Command failed with exit code ${exitCode}`);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error("❌ Error running shell command:", command, "in", cwd);
|
||||
|
|
|
|||
Loading…
Reference in a new issue