## Overview
Implements deterministic weighted-stake-based validator selection in
`DataHavenServiceManager`, building on the era-targeting submitter model
from PR #433. Previously, `buildNewValidatorSetMessage()` forwarded all
registered operators in arbitrary membership order with no stake-based
ranking, meaning high-stake operators could be displaced by lower-stake
ones when downstream caps applied. This PR fixes that by computing a
weighted stake score per operator and selecting the top-32 candidates
before bridging the set to DataHaven.
Spec: `specs/validator-set-selection/validator-set-selection.md`
## Contract Changes (`DataHavenServiceManager.sol`)
**New state:**
- `MAX_ACTIVE_VALIDATORS = 32` — cap on the outbound validator set
- `mapping(IStrategy => uint96) public strategiesAndMultipliers` —
per-strategy weight used in the selection formula
**Updated `buildNewValidatorSetMessage()`:**
1. Fetches allocated stake for all operators × strategies from
`AllocationManager`
2. Computes `weightedStake(op) = Σ(allocatedStake[op][j] ×
multiplier[j])` across all strategies
3. Filters operators with no solochain address mapping or zero weighted
stake
4. Runs a partial selection sort to pick the top `min(candidateCount,
32)` by descending weighted stake; ties broken by lower operator address
(deterministic)
5. Reverts with `EmptyValidatorSet()` if no eligible candidates remain
**Admin API changes:**
- `addStrategiesToValidatorsSupportedStrategies()` signature changed
from `IStrategy[]` to `IRewardsCoordinatorTypes.StrategyAndMultiplier[]`
— strategy and multiplier are stored atomically in one call, eliminating
the risk of a strategy being registered without a multiplier
- New `setStrategiesAndMultipliers(StrategyAndMultiplier[])` — updates
multiplier weights for existing strategies without touching the
EigenLayer strategy set
- New `getStrategiesAndMultipliers()` — returns all strategies with
their current multipliers
- `removeStrategiesFromValidatorsSupportedStrategies()` now cleans up
multiplier entries on removal
**New error / event:**
- `EmptyValidatorSet()` — reverts when no eligible candidates exist
- `StrategiesAndMultipliersSet(StrategyAndMultiplier[])` — emitted on
add or update of multipliers
## Tests (`ValidatorSetSelection.t.sol`)
New 552-line Foundry test suite covering all cases from the spec:
| Case |
|------|
| `addStrategies` stores multiplier atomically |
| `removeStrategies` deletes multiplier |
| `setStrategiesAndMultipliers` updates without touching the strategy
set |
| `getStrategiesAndMultipliers` returns correct pairs |
| Weighted stake computed correctly across multiple strategies |
| Operators with zero weighted stake are excluded |
| Unset multiplier treated as 0 |
| Top-32 selection when candidate count > 32 |
| All candidates included when count < 32 |
| Tie-breaking by lower operator address |
| `EmptyValidatorSet` revert when no eligible operators |
## Deploy Scripts
- **`DeployBase.s.sol`**: Sets a default multiplier of `1` for all
configured validator strategies after AVS registration via
`setStrategiesAndMultipliers`
- **New `AllocateOperatorStake.s.sol`**: Forge script that allocates
full magnitude (`1e18`) to the validator operator set for a given
operator. Must be run at least one block after `SignUpValidator` to
respect EigenLayer's allocation configuration delay.
## E2E Framework
- **`validators.ts` — `registerOperator()`**: Extended to deposit tokens
into each deployed strategy and allocate full magnitude to the DataHaven
operator set after registration. Previously operators registered without
staking, producing zero weighted stake and getting filtered out by the
new selection logic.
- **`setup-validators.ts`**: Added a stake allocation pass after the
registration loop, invoking `AllocateOperatorStake.s.sol` per validator.
- **`validator-set-update.test.ts`**: Added debug logging for
transaction receipts and the `OutboundMessageAccepted` /
`ExternalValidatorsSet` events.
- **`generated.ts`**: Regenerated contract bindings to include new
functions, events, and the `EmptyValidatorSet` error.
## ⚠️ Breaking Changes ⚠️
- `addStrategiesToValidatorsSupportedStrategies(IStrategy[])` →
`addStrategiesToValidatorsSupportedStrategies(StrategyAndMultiplier[])`:
callers must supply multipliers alongside strategies.
- Operators with zero weighted stake are no longer included in the
bridged validator set.
## Rollout Notes
1. PR #433 (era-targeting + submitter role) must be deployed first
2. Deploy this `ServiceManager` upgrade
3. Confirm `strategiesAndMultipliers` is set for all active strategies
(default multiplier `1` applied automatically by `DeployBase`)
4. Deploy the runtime cap-enforcement changes (spec section 10.2)
5. Submitter daemon requires no changes — continues submitting
`targetEra = ActiveEra + 1`
## Era-targeted validator set submission with dedicated submitter role
> **Note:** This PR includes a detailed specification at
[`specs/validator-set-submission/validator-set-submission.md`](https://github.com/datahaven-xyz/datahaven/blob/feat/validator-set-submitter/specs/validator-set-submission/validator-set-submission.md)
that covers the design rationale, submission lifecycle, era-targeting
rules, and failure modes. Reading the spec first will make the contract,
pallet, and daemon changes easier to follow.
### Summary
- Introduce a dedicated `validatorSetSubmitter` role on
`DataHavenServiceManager`, separating validator set submission authority
from the contract owner
- Replace the unscoped `sendNewValidatorSet` with
`sendNewValidatorSetForEra`, which encodes a `targetEra` into the
Snowbridge message payload
- Add server-side era validation in the `external-validators` pallet to
reject stale, duplicate, or out-of-range submissions
- Add a long-running TypeScript daemon that watches session changes and
automatically submits each era's validator set at the right time
### Contract changes (`contracts/`)
- **New `validatorSetSubmitter` storage slot** — set during `initialize`
and rotatable via `setValidatorSetSubmitter` (owner-only). The storage
gap is decremented accordingly.
- **`sendNewValidatorSet` → `sendNewValidatorSetForEra`** — accepts a
`uint64 targetEra` parameter and is restricted to
`onlyValidatorSetSubmitter` instead of `onlyOwner`.
- **`buildNewValidatorSetMessageForEra`** — the
`NewValidatorSetPayload.externalIndex` is now caller-supplied instead of
hardcoded to `0`.
- **New events** — `ValidatorSetSubmitterUpdated`,
`ValidatorSetMessageSubmitted`.
- **New error** — `OnlyValidatorSetSubmitter`.
- **New test suite** — `ValidatorSetSubmitter.t.sol` covering submitter
set/rotate, access control, era encoding, and legacy function removal.
### Pallet changes (`operator/`)
- **`validate_target_era`** in `external-validators` — enforces
`activeEra < targetEra <= activeEra + 1` and `targetEra > ExternalIndex`
(dedup guard).
- **New errors** — `TargetEraTooOld`, `TargetEraTooNew`,
`DuplicateOrStaleTargetEra`.
- **Tests** — five new test cases for era boundary conditions (next-era
acceptance, old-era rejection, too-new rejection, duplicate rejection,
genesis behavior). Existing `era_hooks_with_external_index` test updated
to use valid target eras.
- **Runtime test fixes** — `external_index: 0` → `1` in
mainnet/stagenet/testnet EigenLayer message processor tests to satisfy
the new validation.
### Validator set submitter daemon
(`test/tools/validator-set-submitter/`)
- Event-driven service that subscribes to finalized
`Session.CurrentIndex` via Polkadot-API `watchValue`.
- Submits once per era during the last session, targeting `ActiveEra +
1`.
- Tracks submitted eras to avoid duplicates; skips if `ExternalIndex`
already covers the target.
- Startup self-checks: Ethereum connectivity, DataHaven connectivity,
on-chain submitter authorization.
- Supports `--dry-run` mode and YAML configuration.
- Graceful shutdown on `SIGINT`/`SIGTERM`.
### Test & tooling updates
- **E2E test** (`validator-set-update.test.ts`) — calls
`sendNewValidatorSetForEra` with a computed `targetEra` and filters the
substrate event by `external_index`.
- **`update-validator-set.ts` script** — accepts `--target-era` flag;
defaults to era 1 for fresh networks.
- **CLI launch** — wires validator set update as an interactive step
after relayer launch.
- **`package.json`** — new `submitter` and `submitter:dry-run` scripts.
- Regenerated contract bindings, PAPI metadata, state-diff, and storage
layout snapshots.
### Test plan
- [x] `forge test` — passes, including new `ValidatorSetSubmitter.t.sol`
- [x] `cargo test` — passes, including new era-validation tests in
`external-validators`
- [x] `bun test:e2e` — validator-set-update suite passes with
era-targeted flow
- [x] Manual: run submitter daemon against local network (`bun
submitter`), verify it submits once per era at the correct session
## ⚠️ Breaking Changes ⚠️
- **`sendNewValidatorSet` removed** — replaced by
`sendNewValidatorSetForEra(uint64 targetEra, ...)`. Callers must now
supply a `targetEra` parameter.
- **Access control changed** — validator set submission is now
restricted to the `validatorSetSubmitter` role instead of the contract
`owner`. The submitter address is set during `initialize` and rotatable
via `setValidatorSetSubmitter` (owner-only).
- **`external-validators` pallet now validates `targetEra`** — messages
with a stale, duplicate, or out-of-range `external_index` are rejected
on-chain. Existing integrations sending `external_index: 0` will fail
validation.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary
- Adds an arithmetic invariant check (`slot + size == 151`) to
`check-storage-layout.sh` that catches cases where a new state variable
is added without shrinking `__GAP` accordingly
- The existing snapshot-diff check alone could pass with a wrong gap
size if the snapshot is updated to match — this new check prevents that
- Updates the negative test to also accept the new `__GAP invariant
violated!` error message
## Test plan
- [x] `check-storage-layout.sh` passes on the current correct layout
- [x] `check-storage-layout-negative.sh` passes — the bad layout
contract (slot 107 + size 45 = 152) correctly triggers the invariant
failure
## Summary
Slashing and rewards submissions were submitted through the bridge with
their **solochain address** , while EigenLayer expects the **ethereum
operator address**, the addresses were not being translated, so the
protocol was broken.
This PR adds a **reverse mapping** (Solochain address → Eth address) and
uses it in both the slashing and rewards paths so that:
- `slashValidatorsOperator` accepts requests where `operator` is a
Solochain address and translates it to the Eth operator before calling
EigenLayer.
- `submitRewards` translates each `operatorRewards[].operator` from
Solochain to Eth before calling the RewardsCoordinator.
- Unknown or unmapped solochain addresses cause a revert
(`UnknownSolochainAddress`) instead of silently failing.
## What's changed
### DataHavenServiceManager
- **Reverse mapping**: `mapping(address => address) public
validatorSolochainAddressToEthAddress` (Solochain → Eth), with `__GAP`
reduced by one slot for upgradeable layout.
- **Helper**: `_ethOperatorFromSolochain(address)` – returns Eth
operator for a Solochain address, reverts with
`UnknownSolochainAddress()` if unmapped.
- **Registration / lifecycle**:
- `registerOperator`: populates both forward and reverse mappings;
enforces uniqueness (one Solochain per operator) and clears old reverse
entry when an operator re-registers with a new Solochain.
- `deregisterOperator`: clears both forward and reverse entries.
- `updateSolochainAddressForValidator`: updates both mappings, enforces
uniqueness and clears the previous Solochain's reverse entry.
- **Slashing**: `slashValidatorsOperator` uses
`_ethOperatorFromSolochain(slashings[i].operator)` so requests keyed by
Solochain address are translated before calling EigenLayer.
- **Rewards**: `submitRewards` builds a translated copy of the
submission with each `operatorRewards[].operator` set via
`_ethOperatorFromSolochain(...)`; unmapped addresses revert.
### IDataHavenServiceManager
- New getter: `validatorSolochainAddressToEthAddress(address solochain)
external view returns (address)`.
- New errors: `UnknownSolochainAddress()`,
`SolochainAddressAlreadyAssigned()`.
### Storage and fixtures
- Storage snapshot updated for the new state variable.
- `DataHavenServiceManagerBadLayout.sol` updated (reverse mapping + gap)
for layout negative tests.
- Storage layout test extended to assert the reverse mapping is
preserved across proxy upgrade.
### Tests
- **Slashing.t.sol**: Slashing with Solochain address (translation and
emit of Eth operator); negative test for unmapped Solochain reverting
with `UnknownSolochainAddress()`.
- **RewardsSubmitter.t.sol**: Rewards submission with Solochain
addresses (translation to Eth in RewardsCoordinator calldata); negative
test for unmapped Solochain.
- **StorageLayout.t.sol**: Reverse mapping preserved after upgrade.
- **OperatorAddressMappings.t.sol** (new): Uniqueness (Solochain already
assigned to another operator), update/deregister clearing reverse
mapping, and getter behaviour.
## Testing
- **Unit tests**: `forge test` from `contracts/` (all existing and new
tests pass).
- **Storage**:
- `./scripts/check-storage-layout.sh`
- `./scripts/check-storage-layout-negative.sh`
- **Coverage**: Slashing path (Solochain → Eth translation + revert),
rewards path (translation + revert), registration/update/deregister
(reverse mapping and uniqueness), and storage layout upgrade
preservation.
---------
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <ahmadkaouk.93@gmail.com>
## 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>
## Summary
- Add multi-environment deployment support (stagenet, testnet, mainnet)
to CLI and contracts
- Configure stagenet and testnet runtimes with correct genesis hashes
and Snowbridge Agent IDs
- Add CLI commands for BEEFY checkpoint updates and rewards origin
computation
- Add ETH validator strategies (native beacon chain ETH + LSTs) to all
config files
## Changes
### Runtime Configuration
**Stagenet Runtime:**
- Set `StagenetGenesisHash` to DataHaven stagenet genesis hash
- Configure `RewardsAgentOrigin` with computed Snowbridge Agent ID
- Add tests verifying rewards account derivation and agent ID
computation
**Testnet Runtime:**
- Set `TestnetGenesisHash` to DataHaven testnet genesis hash
- Configure `RewardsAgentOrigin` with computed Snowbridge Agent ID
- Add tests verifying rewards account derivation and agent ID
computation
The Rewards Agent ID is computed following Snowbridge's location
description pattern:
```
blake2_256(SCALE_ENCODE("GlobalConsensus", ByGenesis(genesis), "AccountKey20", rewards_account))
```
### CLI Enhancements
- All contracts subcommands (`status`, `deploy`, `verify`,
`update-metadata`) now accept `--environment` option
- Config and deployment files use environment-prefixed naming (e.g.,
`stagenet-hoodi.json`, `testnet-hoodi.json`)
- New `update-beefy-checkpoint` command that:
- Connects to a live DataHaven chain via WebSocket RPC
- Fetches all BEEFY data at the same finalized block for consistency
- Uses parallel queries with `Promise.all` for better performance
- Computes authority hashes (keccak256 of Ethereum addresses derived
from BEEFY public keys)
- Uses Snowbridge's quorum formula `n - floor((n-1)/3)` for strictly >
2/3 majority
- New `update-rewards-origin` command that computes the Snowbridge Agent
ID for the rewards pallet
- Centralized validation via `contractsPreActionHook` for all contract
commands
- Environment validation against allowlist (`stagenet`, `testnet`,
`mainnet`)
### Contract Changes
- Network validation uses explicit allowlist instead of suffix matching
- Added `initialValidatorSetId` and `nextValidatorSetId` fields to
`SnowbridgeConfig` struct
- `DeployBase.s.sol` now uses config values for validator set IDs
instead of hardcoded 0/1
- `DeployParams.s.sol` loads validator set IDs from config with
backwards compatibility
### Validator Strategies
Added ETH-equivalent strategies to allow validators to stake using
native ETH or LSTs:
**All Networks:**
- `0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0` - Native beacon chain ETH
(virtual strategy)
**Hoodi Testnet:**
- `0xf8a1a66130d614c7360e868576d5e59203475fe0` - stETH
- `0x24579aD4fe83aC53546E5c2D3dF5F85D6383420d` - WETH
**Ethereum Mainnet:**
- `0x93c4b944D05dfe6df7645A86cd2206016c51564D` - stETH
- `0x1BeE69b7dFFfA4E2d53C2a2Df135C388AD25dCD2` - rETH
- `0x54945180dB7943c0ed0FEE7EdaB2Bd24620256bc` - cbETH
### Config Files
- `stagenet-hoodi.json` - Hoodi testnet with stagenet EigenLayer
addresses
- `testnet-hoodi.json` - Hoodi testnet with testnet EigenLayer addresses
- `mainnet-ethereum.json` - Ethereum mainnet with mainnet EigenLayer
addresses
- Removed `hoodi.json` (replaced by environment-prefixed files)
## Usage
```bash
# Deploy to stagenet on Hoodi
bun cli contracts deploy --chain hoodi --environment stagenet
# Update BEEFY checkpoint from live chain
bun cli contracts update-beefy-checkpoint \
--chain hoodi \
--environment stagenet \
--rpc-url wss://services.datahaven-dev.network/stagenet
# Compute rewards origin for a chain
bun cli contracts update-rewards-origin \
--chain hoodi \
--environment stagenet \
--rpc-url wss://services.datahaven-dev.network/stagenet
# Check deployment status
bun cli contracts status --chain hoodi --environment stagenet
```
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
### Summary
Optimizes `award_session_performance_points` by batching all validator
rewards into a single storage mutation instead of performing individual
mutations inside the loop.
### Problem
The `award_session_performance_points` function, called during session
rotation via `SessionManager::end_session`, was calling `reward_by_ids`
inside the validator loop for each validator individually:
```rust
for validator in validators.iter() {
// ... calculate points ...
Self::reward_by_ids([(validator.clone(), points)].into_iter());
}
```
Each call to `reward_by_ids` performs a `StorageMap::mutate` on
`RewardPointsForEra`, which reads and writes the entire
`EraRewardPoints` structure (a `BTreeMap` containing up to N validator
entries). With N validators, this results in N separate
read-modify-write cycles of an O(N)-sized structure, leading to O(N²)
total storage I/O.
### Solution
Collect all reward points first, then perform a single batched call to
`reward_by_ids`:
```rust
let mut rewards = Vec::new();
for validator in validators.iter() {
// ... calculate points ...
rewards.push((validator.clone(), points));
}
if !rewards.is_empty() {
Self::reward_by_ids(rewards.into_iter());
}
```
This reduces the complexity from O(N²) to O(N) by performing only one
storage mutation that processes all validators at once.
### Why This Matters
Session rotation hooks are mandatory—they execute regardless of block
weight limits. While `pallet_session::on_initialize` returns `max_block`
weight during rotation (preventing user transactions), the actual
execution time still matters. With a large validator set, O(N²) storage
operations could exceed the block time target, potentially causing block
production delays.
### Test Plan
- [x] Existing unit tests pass (`cargo test -p
pallet-external-validators-rewards`)
## Summary
### Configuration
- Remove deprecated `deny_warnings` config key from foundry.toml
- Add global `[lint]` config to suppress naming convention warnings for
AVS/EL/ERC patterns (`mixed-case-function`, `mixed-case-variable`)
### DataHavenServiceManager Refactoring
- Rename immutable variables to SCREAMING_SNAKE_CASE
(`_allocationManager` → `_ALLOCATION_MANAGER`, `_rewardsCoordinator` →
`_REWARDS_COORDINATOR`)
- Wrap modifier logic in internal functions (`_checkRewardsInitiator`,
`_checkValidator`, `_checkAllocationManager`) to reduce contract size
- Add `_toAddress` helper with assembly for safe bytes-to-address
conversion
### Safe Typecasting
- Replace direct typecasts with OpenZeppelin's SafeCast library in
deploy scripts and test utilities
- Use `.toUint32()`, `.toUint64()`, `.toUint160()` for
overflow-protected conversions
- Replace `bytes32("wrong origin")` string cast with hex literal in test
deployer
### Code Cleanup
- Remove 25+ unused imports across script and test files
- Convert plain imports to named imports for better clarity
- Use `SafeERC20.safeTransfer()` for token transfers in tests
- Change `view` to `pure` where appropriate
## Test plan
- [x] `forge build` completes with no warnings
- [x] `forge test` passes all 10 tests
## Summary
- Add zero address validation across all functions that accept address
parameters to prevent misconfiguration
- Fix race condition in `buildNewValidatorSetMessage()` that could cause
reverts during validator deregistration
- Refactor contract for improved readability and reduced code
duplication
- Update AVS metadata URL to point to the correct hosted JSON file
## Changes
### Security & Validation
- Add `ZeroAddress` error and validate all address inputs in
`initialize`, `setRewardsInitiator`, `setSnowbridgeGateway`,
`addValidatorToAllowlist`, `registerOperator`, and
`updateSolochainAddressForValidator`
- Fix race condition: filter out zero solochain addresses in
`buildNewValidatorSetMessage()` to prevent reverts when a validator is
mid-deregistration
### Refactoring
- Replace verbose `if/revert` patterns with `require` statements for
consistency
- Inline single-use internal functions (`_createDataHavenOperatorSets`,
`_setRewardsInitiator`)
- Consolidate duplicate error types into single `ZeroAddress` error
- Rename `initialise` → `initialize` to maintain consistency with the
transparent upgradability pattern
- Optimize validator set message encoding by removing redundant wrapper
function
### Observability
- Add `SolochainAddressUpdated` event for tracking validator address
changes
### Cleanup
- Remove unused remappings from `foundry.toml`
- Fix typo in metadata description
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## Summary
This PR integrate the slashing feature with EigenLayer. With this PR,
slashing can now be relayed to our Datahaven AVS and then executed
within EigenLayer. In addition some refactoring of the original slashing
pallet has been done.
## Motivation
To avoid misbehaving actor in the network, Datahaven has implemented a
slashing pallet in which offenses can be reported and then if adequate
can lead to a sanction on the misbehaving node. It incentive nodes to
only follow good behavior in addition to the reward incentive. The
rewards flow is managed directly into EigenLayer (see
https://github.com/datahaven-xyz/datahaven/pull/351).
## Slashing flow
<img width="2355" height="946" alt="Slashing Flow"
src="https://github.com/user-attachments/assets/c1ddc3dc-2a7e-429d-94e0-1e02a3f65246"
/>
## What changes
* Implemented `slashValidatorsOperator` in `DataHavenServiceManager`. It
received all the slashing requests batched (every new era the queued
slashing are being relayed from substrate to Ethereum). It handle the
slashing of the operators reported into the Validator set.
* Added a `slashes_adapter.rs` utility file to remove the duplication
for each runtime. In addition, we made use of the `sol!` macro from
alloy to encode the calldata for the Ethereum call. This avoid rewriting
encoding logic and allow to remove the hardcoded selector value used to
call the slashing function.
* Added some tests in solidity to test the registering and slashing of
an operator in Ethereum via Eigen Layer.
* Added e2e tests that test the injection of a slash request, it being
relayed via the snowbridge relayer and executed by our Datahaven AVS.
## What could be better
* We are only deploying one strategy for now so it is hardcoded in the
slashing flow. We should be able to update the pallet in case we are
adding a new strategy. So communication from Ethereum should be relayed.
* We don't have error being return in case the slashing fail. Which
could happen if we don't have the right number of strategy or the
validator is not registered... etc.
* More tests for the unhappy path
## Summary
This PR improve the generating state workflow. It will also check for
outdated state-diff.json and add a practical script to easily generate a
new one.
The way we generate state has also been changed to make it work with
macOS M1 system. We don't run the tool in the container anymore but
instead directly on the machine.
## What changes
* A check-generated-state.js script was added to quickly look for
outdated test
* The check was added in the CI
* A generate-contracts.ts script was added to easily generate the new
state with the new instructions to run on MacOS
---------
Co-authored-by: Gonza Montiel <gon.montiel@gmail.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
## Summary
This PR remove the middlewares contracts from eigen layer. Instead we
are planning to use the eigne layer contract directly. It also removes
the tests related to the middleware slasher code and the mock contract
used in it.
## Motivation
When slashing an operator in the Dathaven we are going through the
substrate slashing pallet already implemented. It already allow to
configure a slashing window and/or to cancel a slashing. In the future
it will also be compatible with a government pallet. This part of code
is therefore redundant. For the same reason we remove the tests because
we are not using the slashing middleware contracts.
## What changed
* Remove the slasher middleware files
* Remove the tests related to the middleware slasher file
This PR significantly refactors and improves the end-to-end testing
framework and infrastructure. The primary focus was on simplifying the
test suites, improving reliability through better resource management,
and hardening the relayer infrastructure.
All E2E tests are now passing on the CI and demonstrate consistent
reliability when run locally.
### Key Changes
#### 1. E2E Test Suite Refactor & Cleanup
* **Simplified Test Logic**: Heavily refactored the core test suites
(`native-token-transfer.test.ts`, `rewards-message.test.ts`, and
`validator-set-update.test.ts`). The new implementation is much cleaner,
utilizing shared helpers to reduce boilerplate.
* **Utility Consolidation**: Removed redundant utility files
(`storage.ts`, `rewards-helpers.ts`) and simplified `events.ts`. Event
waiting now uses `rxjs` for Substrate and native `viem` watchers for
Ethereum, which is more robust and easier to maintain.
* **Better Connector Management**: Unified the creation and cleanup of
test clients in `ConnectorFactory`. It now handles the lifecycle of
WebSocket connections more gracefully, including clearing the
`socketClientCache` to prevent reconnection noise during teardown.
#### 2. Infrastructure & Stability
* **Relayer Relaunch Policy**: Added a restart policy for Snowbridge
relayer containers. They are now configured with `--restart
on-failure:5`, ensuring that relayers automatically relaunch if they
crash during the sensitive initialization phase.
* **WebSocket Integration**:
* Updated the `ConnectorFactory` to prefer **WebSockets** for the
Ethereum public client, which is essential for efficient, event-heavy
E2E testing.
* Enhanced `launchKurtosisNetwork` to correctly identify and register
the Execution Layer's WebSocket endpoint from Kurtosis.
* **Disabled Contract Injection**: This PR temporarily disables the
automatic injection of contracts into the genesis state by default.
* *Reason*: I encountered issues generating a valid `state-diff.json`
for the latest contract versions. Even after applying several
workarounds, the injected state remained unstable. As a result, I've
reverted to manual contract deployment during the launch sequence for
better reliability for now.
#### 3. Documentation & Maintenance
* Removed obsolete documentation (`event-utilities-guide.md`) that no
longer reflects the simplified event-handling API.
* Cleaned up `test/launcher/validators.ts` and moved logic into more
appropriate helpers.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
### Context
The function `v2_sendMessage()` on Snowbridge Gateway contract is
**permissionless** (I'm shocked this is the design choice). Any
EOA/contract on Ethereum can build a message and send it through our DH
bridge. While we don't change our Snowbridge fork, then this will
continue to be the case.
### Problem
We use `v2_sendMessage()` to send **permissioned** operations to our
chain. For instance: update our validator set message (coming next,
_slashing-related_ messages). So we do need to restrict the processing
of the incoming messages on the Substrate side.
### Fix
- I've added a check to `EigenLayerMessageProcessor` that enforces
`message.origin` to be only a configured `AuthorisedOrigin`.
- I've added an `AuthorisedOrigin` to
`pallet_external_validators::Config`
- I've configured the `AuthorisedOrigin` to be
`DatahavenServiceManagerAddress` in all three runtimes
### Stages
- [x] Implementation
- [x] Runtime integration tests
- [x] Collect `DatahavenServiceManagerAddress` parameter for e2e tests
to work
Fixes https://github.com/datahaven-xyz/sr-datahaven/issues/12
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Remve the `DataHavenTest.sol` file which was a file generated as part of
the template.
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
# Enable AVS owner workflow
Until now, the deployer of the contracts and the owner of the deployed
contracts where the same account. Even if we allowed a different owner
to be specified, we were using the same. For this reason, a private key
was required, so after the deployment we could execute owned
transactions needed for the CLI.
In this PR we:
- Add a mechanism to the CLI to specify a different owner account other
than the deployer via `--avs-owner-address`
- Add CLI flags `--avs-owner-key` and`--execute-owner-transactions` so
account ownership vs. immediate execution is explicit and deferred. If
both previous parameters are provided, the CLI will execute the
transactions using the private key provided.
- Allow DataHaven AVS deploy scripts to toggle owner-call execution via
an env flag `TX_EXECUTION`
- Add documentation on how the new parameters work in `test/README.md`
and `test/docs/deployment.md`.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
## 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
Apparently, EigenLayer started including mock files inside
`test/mocks/*`, that weren't in our remappings. That's why the e2e
contract building was failing, both for e2e tests and CLI launch, while
trying to solve `src/test/mocks/AllocationManagerMock.sol` in our own
contracts source. I added the necessary remappings and the tests run
now.
In this PR, we introduce a way to save Ethereum state into a file. This
saved state can then be injected into Ethereum to speed up e2e initial
test setup.
This is a rewrite of the now closed PR
https://github.com/datahaven-xyz/datahaven/pull/90 .
It uses a an external tool written in rust to save state from the
Ethereum running container : https://github.com/undercover-cactus/Chaos
---------
Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## Summary
- sync `contracts/lib/eigenlayer-contracts` to tag
`v1.8.0-testnet-final` and refresh `EIGENLAYER.md` with the new commit
reference
- update local/test deployment flows to deploy the upstream
`EigenStrategy`, feed it into `AllocationManager`/`StrategyManager`, and
adopt the revised `EigenPod` constructor
- drop the obsolete `AllocationManagerMock` stub and replace its usage
with targeted `vm.mockCall` stubs that return `slashOperator` share data
- adjust slasher unit tests to match the new ABI so DataHaven stays
aligned with EigenLayer 1.8 semantics
## Testing
- forge build
- forge test
This PR remove the `cargo chef` step used to build the docker image used
in deployment. We noticed that `cargo chef` was adding more time to the
build and that removing it was saving us 40min.
Also in this PR, we removed the base image from parity which was really
heavy and was filling the rest of the disk space. This broke the build.
After some investigation it doesn't seem to add a lot to the build. It
has been replace with the official rust image as a base to build our
node.
The image used to run the image has been replaced with
`debian:trixie-slim`.
In the end those changed **should not** break any of the current
behavior and makes save a bit of CI time.
## Summary
Fixes the CI build failure in the `task-ts-build` workflow caused by
Foundry v1.4.2's Solar linter not being able to resolve Snowbridge's
context-specific import remappings.
## Problem
The Snowbridge submodule uses context-specific remappings (prefixed with
`:`) for its dependencies:
- `lib/snowbridge/contracts/:openzeppelin/` → OpenZeppelin contracts
- `lib/snowbridge/contracts/:prb/math/` → PRB Math library
Foundry v1.4.2's Solar linter doesn't understand these context-specific
remappings and fails with errors like:
```
error: file openzeppelin/utils/cryptography/MerkleProof.sol not found
error: file prb/math/src/UD60x18.sol not found
```
## Solution
Added global remappings that the linter can understand:
```toml
"openzeppelin/=lib/snowbridge/contracts/lib/openzeppelin-contracts/contracts/",
"prb/math/=lib/snowbridge/contracts/lib/prb-math/",
```
### Why This Works
- The linter can now resolve `openzeppelin/` and `prb/math/` imports
globally
- These global remappings take **lower precedence** than
context-specific ones during compilation
- The compiler still uses the context-specific remappings (with `:`)
when compiling Snowbridge contracts
- The linter uses the global remappings when checking all files
## Changes
### Commit 1: Add global remappings
- `contracts/foundry.toml`: Added 2 global remapping entries
### Commit 2: Apply forge fmt
- Applied automatic formatting via `forge fmt` to ensure code style
consistency
- Multi-line formatting for long import statements and function
signatures
- No functional changes - purely formatting updates
## Testing
✅ Local build succeeds with `forge build`
✅ No Snowbridge import resolution errors
✅ `forge fmt --check` passes with no formatting issues
✅ Only linting notes/warnings remain (not errors)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
### Summary
Removes the obsolete `operator/test` folder that was no longer being
used and contained outdated test scripts.
### Changes
- ✅ Deleted `operator/test/` directory and all contents
- ✅ Moved `test_message_encoding.sh` script to `operator/scripts/` for
proper organization
- ✅ Updated comment reference in `contracts/test/MessageEncoding.t.sol`
to point to new script location
### Impact
- **No breaking changes** - All legitimate test files remain properly
organized within their respective pallets
- **Cleaner codebase** - Removes unused/obsolete code
### PR Description
Add a comprehensive end-to-end test that validates rewards distribution
across the full system (chain → bridge → execution environment).
### Use cases covered
- Verify the rewards infrastructure is correctly deployed and reachable.
- Detect the end-of-era rewards emission and capture its essential data.
- Confirm the cross-chain delivery and execution of the rewards message.
- Ensure the rewards registry updates with the new root and can be
queried.
- Generate per-validator proofs for claiming rewards.
- Successfully claim rewards for a validator and validate the payout is
reflected.
- Prevent a second (double) claim for the same index with a proper
rejection.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## 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>
### Summary
- **Add** `test/suites/native-token-transfer.test.ts` focused on the
HAVE native token lifecycle via Snowbridge v2.
- **Validate** registration, DataHaven → Ethereum mints, Ethereum →
DataHaven unlocks, event emission, and 1:1 backing invariant.
### Tests added
- should register DataHaven native token on Ethereum
- should transfer tokens from DataHaven to Ethereum
- should maintain 1:1 backing ratio
- should emit transfer events
- should transfer tokens from Ethereum to DataHaven (Snowbridge v2)
### What the suite covers
- **Registration**: Sudo-registers the native token; confirms
`ForeignTokenRegistered` on the Gateway; verifies ERC-20 metadata
(`HAVE`/`wHAVE`, 18 decimals).
- **DataHaven → Ethereum**: Executes `transfer_to_ethereum`; asserts
Substrate events (`TokensLocked`, `TokensTransferredToEthereum`);
observes Ethereum `Transfer` mint (from zero address); validates sender
balance delta, sovereign account increase, and ERC-20 recipient credit.
- **Backing invariant**: Ensures sovereign account balance ≥ ERC-20
total supply.
- **Event emission**: Confirms key Substrate events without polling
delays.
- **Ethereum → DataHaven**: Approves and calls `Gateway.sendToken`; if
unsupported locally, the test skips; otherwise asserts burn on Ethereum
and unlock on DataHaven with corresponding balance deltas.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
## Summary
This PR introduces support for deploying Datahaven contracts to
different chains (hoodi, holesky, mainnet), as well as a new cli command
to manage this deployment separately from the regular deployment, while
maintaining compatibility with it.
#### New CLI command
- **`bun cli contracts deploy`** - Deploy contracts to supported chains
(Hoodi, Holesky, Mainnet)
- **`bun cli contracts status`** - Check deployment configuration and
status
- **`bun cli contracts verify`** - Verify contracts on block explorers
- Commands need the chain parameter: `--chain <hoodi | holesky |
mainnet>`
- Right now only `hoodi` and `holesky` are supported
### Deployment
#### Hoodi & Holesky Network Support
- Added **DeployBase.s.sol** as common ground for
**DeployTestnet.s.sol** (also new) and **DeployLocal.s.sol** (existing).
- **Hoodi configuration** (`contracts/config/hoodi.json`) with deployed
EigenLayer contract addresses to reference.
- **Holesky configuration** (`contracts/config/hoodi.json`) with
deployed EigenLayer contract addresses to reference.
#### Contracts being deployed
- **DataHaven**: ServiceManager, VetoableSlasher, RewardsRegistry
- **Snowbridge**: BeefyClient, AgentExecutor, Gateway, RewardsAgent
- **EigenLayer**: References existing deployed contracts (not
re-deployed)
#### Deployment files
When the deployment is done, a new file under `contracts/deployments` is
generated with the addresses of the deployed contracts, for each chain
(it will be overriden per chain if run multiple times). So we would have
one `anvil.json`, `hoodi.json`, `holesky.json`, etc, with the addresses
of the deployed contracts for reference and for later verification.
#### Todo
- [x] Test compatibility with existing `bun cli launch` and `bun cli
deploy` commands
#### For follow-up PRs
- Fix verification issue with `foundry verify-contracts` when specifying
the `chain` or `chain-id` parameter, needed for hoodi
(https://github.com/foundry-rs/foundry/issues/7466).
- Add `redeploy` feature to only override implementation contract and
leave the proxy address untouched
## Usage Examples
```bash
# Deploy to Hoodi network
bun cli contracts deploy --chain hoodi
# Check deployment status
bun cli contracts status --chain hoodi
# Verify contracts on block explorer
bun cli contracts verify --chain hoodi
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added deployment and configuration support for new networks "hoodi"
and "holesky", including new configuration and deployment files.
* Introduced a CLI tool for managing contract deployments, status
checks, and verification across supported chains.
* Added example environment configuration and comprehensive deployment
documentation.
* Enabled contract verification and status reporting via the CLI with
support for block explorer integration.
* **Improvements**
* Refactored deployment scripts for modularity, supporting both local
and testnet environments.
* Centralized and extended configuration loading to support additional
contract addresses and network parameters.
* Enhanced deployment utilities and typings to support multi-network
deployments.
* **Bug Fixes**
* Improved input validation and error handling in CLI commands and
deployment scripts.
* Added explicit handling for zero address in operator strategy
retrieval.
* **Chores**
* Updated documentation and configuration templates for easier
onboarding and deployment management.
* Improved logging and output formatting for deployment and verification
processes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
We remove `calculateMerkleRootUnsorted` and `buildMerkleProofUnsorted`
and instead introduce a new parameter `sorting`. This parameter
`sorting` will indicate if we need to sort the pair before hashing the
new node.
## Summary of changes
- We decided to remove the topics and nonce from the massage encoding
since we don't use them (original commit:
ee2a3f2fd4).
- Besides, we already have a nonce at the Snowbridge message level
f4ab5c2b2e/operator/primitives/snowbridge/inbound-queue/src/v2/message.rs (L105)
- I had to recreate the static test for _encoding_ (happens in
[DataHavenSnowbridgeMessages.sol](d12d40634f/contracts/src/libraries/DataHavenSnowbridgeMessages.sol)
) / _decoding_ (happens in
[operator/primitives/bridge/src/lib.rs)](f9f9cc65fe/operator/primitives/bridge/src/lib.rs).
Now it matches the current structure. The idea is that now we can test
that we don't break the decoding in followup refactoring.
- Fixes a problem with EigenLayer validator addresses. In all our
contracts we were using `bytes32` to refer to a Solochain validator
address. But on our Substrate change we actually expect AccountId20, so
only 20 bytes. This was causing the decoding to fail.
- I opted for the minimal change that would be to take the right-most 20
bytes to send that to our chain. But we might want aswell to limit our
EigenLayer contracts to be only 20 bytes long. @ahmadkaouk showcase this
[here](92a34c273c)
- Adds a bash script to run the static test. The test will compile the
contracts, run the encoding test, compile the operator, and run the
decoding test. This saves a huge amount of time since we don't need to
run the full e2e setup. The way of running it is the following:
```bash
cd operator/test/scripts
./test_message_encoding.sh
```
- As a consequence of this PR, the execution relayer now works properly.
EDIT:
> [!IMPORTANT]
**We decided to use 20-byte addresses in our contracts**. So what is
stated above is not valid anymore.
The change implies that the mapping from Ethereum addresses to bytes32
addresses now it's a mapping as follows:
dd3ba99ac0/contracts/src/DataHavenServiceManager.sol (L51-L52)
I've updated helper functions, tests, etc to be compliant with this
change. The execution relayer and beefy relayer look stable now.
---------
Co-authored-by: Ahmad Kaouk <ahmadkaouk.93@gmail.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
# Description
This PR implements a comprehensive overhaul of the `RewardsRegistry`
contract to maintain complete history of reward merkle roots while
providing index-based claim tracking for operators. The new architecture
enables operators to claim rewards from any historical merkle root
instead of only the latest one. To do so, it:
- Adds the `merkleRootHistory` storage array to the contract, in which
we keep all rewards roots that ever came from the DataHaven side.
- Adds the `operatorClaimedByIndex` storage map to the contract, in
which we keep track, for each validator and root index, if it has
claimed it or not.
- This works even for new validators, since theoretically with this
system you could argue they could claim older roots that they were not a
part of which would be catastrophic, but they could never draft a
correct proof for those to claim them.
- Keeps some of the interface from before the overhaul, to have quick
access to the latest rewards merkle root through `getLatestMerkleRoot()`
and to claim rewards for it with `claimRewards()`. This is because the
expected behaviour is for validators to claim their rewards every era.
- Adds a way to batch claim rewards with `claimRewardsBatch()`. This
function allows a validator to claim rewards for multiple root indices
in one call by providing multiple proofs, useful if the validator has
fallen behind claims and has to catch up, although special care will
have to be taken by it to avoid reaching the gas limit of a transaction.
## Storage Efficiency Analysis
One might think this solution is not as storage-efficient as other
solutions that we can think of (I even had two other alternatives in
mind as well), but a simple back-of-the-envelope calculation gives us
peace of mind that the impact of this solution on the overal state size
of the chain is negligible:
### Assumptions (Worst Case Scenario):
- 1,000 validators (actual estimate for DataHaven: ~50/100 validators)
- 6-hour eras (most-likely scenario, following what Polkadot does:
~24-hour eras)
- Which means 4 merkle root updates per day
### Annual Storage Requirements:
- Merkle Root History: **46,720 bytes/year**
- 4 roots/day × 32 bytes/root × 365 days/year = 46,720 bytes/year
- Operator Claim Tracking: **~1.46 MB/year**
- 1,000 operators × 1 boolean/(operator * root index) × 1 byte/boolean ×
4 root indices/day × 365 days/year = 1,460,000 bytes/year
- **Total: ~1.5 MB/year**
This represents negligible storage overhead compared to the significant
operational benefits gained.
## TODO
Since we want to allow the operators/validators to only have to interact
with the AVS contract (that's why the `claimRewards` functions have the
`onlyAVS` modifier), we still have to:
- [x] Add the required functions to the AVS to allow operators to claim
their rewards.
- [x] Adds comprehensive unit tests for them.
---------
Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com>
Co-authored-by: Ahmad Kaouk <ahmadkaouk.93@gmail.com>
This PR improves the CLI to get from the deployments the
`RewardsRegistryAddress` (address of the RewardsRegistry contract
deployed), `RewardsAgentOrigin` (origin used for the agent in charge of
updating the rewards merkle root in the RewardsRegistry contract) and
`RewardsUpdateSelector` (function selector of the function that the
agent must execute to do the aforementioned update) and then set these
values in the `parameters` pallet of the runtime.
After these changes the rewards merkle root is being updated on the
Ethereum side. 🎉
## This PR includes:
- Running the execution relayer on the CLI
- Modifying the Payload generation in the `DataHavenServiceManager.sol`
- Modified the `EigenLayerMessageProcessor` to work with the
ValidatorSet update message, but for this change we are loosing the
generic message type (it was the only way to make it work so far).
- Adds a `--no-wait` argument to the cli launch and stop commands to
bootstrap faster.
### Testing the Snowbridge message encoding / decoding
- Added`MessageEncoding.t.sol` is documented and explains how to
generate bin data to use in the rust test.
- Added a Rust unit test to `EigenLayerMessageProcessor` to compare the
message encoding/decoding taking the bytes from a file (previously
generated with some mock data).
Specifically, we want that:
3cbca0db6d/contracts/src/libraries/DataHavenSnowbridgeMessages.sol (L78-L85)
Generates the right bytes encoding for
0e2c9cd518/operator/primitives/bridge/src/lib.rs (L51)
If the test passes, it's very likely that the CLI will also pass, if
not, then we might wanna check something else is missing.
### Breaking change ⚠️
For compatibility reasons with Snowbridge contracts (they call specific
extrinsics of specific pallets), I had to rename:
- `InboundQueueV2` -> `EthereumInboundQueueV2`
- `OutboundQueueV2` -> `EthereumOutboundQueueV2`
## For follow up PRs:
- Add an automated way of generating the Solidity bytes fo testing, so
we don't need to maintain the MessageEncoding.t.sol and generate the
binary data manually.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added support for the "execution" relayer type in relay configuration,
parsing, and CLI launch utilities.
- Introduced a Solidity test contract for encoding and logging validator
set messages.
- Added a comprehensive "start:all" script to streamline launching and
setup processes.
- **Enhancements**
- Improved message encoding for validator set updates, aligning with new
struct field names and message formats.
- Updated relay configuration schema and validation to support execution
relayers and OFAC settings.
- Increased beacon datastore capacity and adjusted relay scheduling
parameters in configuration files.
- **Refactor**
- Renamed runtime type aliases for inbound/outbound queues to more
descriptive names across mainnet, stagenet, and testnet.
- Centralized and streamlined validator set update logic in CLI
utilities.
- Centralized message decoding logic and improved visibility of message
fields in Rust components.
- **Bug Fixes**
- Improved error handling and decoding logic for message processing in
Rust components.
- **Tests**
- Added Rust and Solidity tests for message encoding and processing
validation.
- **Chores**
- Updated dependencies and feature flags in Rust project configuration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
## Changes
- New option: `--kurtosis-enclave-name` to allow you to specify a new
ethereum network with a different enclave name. Neccesary step for
setting up local testing with multiple enclaves running at once
- Refactor: all single dash options (e.g. `-i`) have been renamed to
have double dashes `--` for consistency others
- sad times: CLI now must be invoked `bun cli launch` since we have
multiple fns now
- Package Update
- New Function: `stop` which allows you to kill all components (eth, dh,
relayers) or only a single part
- Gonza's mac target build fix
- Misc fixes to ci like caching and rate limits
## Additional Comment
The CLI needs multiple commands and this PR adds the first new one
`stop`.
This syntax is faily extensible so @ffarall 's k8 command can follow
suite.
Originally we were going to have an `exec` command to expose internal
fns to be callable by command line, i.e. generate beacon checkpoint -
however the need for it has since been superceded by the deploy to k8
command that's going to be added. I've left the code in place though so
when another usecase comes up we can just plug that in.
---------
Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
This PR:
- Adds a check to make sure the BEEFY RPC endpoint is ready before
spinning up the BEEFY relayer, otherwise it would just fail and crash.
- Adds the `--enable-offchain-indexing=true` flag to the Datahaven nodes
run when starting up the E2E infra. This is needed because otherwise
nodes can't be queried by the relayer to generate the required proofs
since they would not store the MMR leafs/nodes/root, so the relayer
would just crash.
- Updates the way we were generating the merkle root of the validator
set.
- The BEEFY pallet (and as such, the relayer) generate the validator set
merkle tree by getting the validator list and treating it as an already
ordered set of merkle leafs, hashing each pair in succession without
caring what each leaf value is.
- Meanwhile, the OpenZeppelin crypto library (and as such, the
EigenLayer contracts) also gets the merkle leafs list but hashes each
pair of leafs in value order.
- This means that, for example, if the list of leafs is: ["0x124",
"0x123"]
- BEEFY would do `hash("0x124123")` to get the value of the parent node.
- OZ and EigenLayer would do `hash("0x123124")` to get the value of the
parent node.
- This created a mismatch between what the BEEFY relayer was expecting
and what was actually calculated in our script. A way to obtain a merkle
tree using the BEEFY way was added to solve this.
- Updates the authority set to not be a hardcoded array of keys, now the
BEEFY keys are obtained by directly querying the runtime before
deploying the BEEFY contracts.
- Renames a few files from `flamingo` to `datahaven`.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added support for calculating and generating Merkle roots and proofs
without sorting, enabling new use cases for validator set management.
- Introduced dynamic fetching and configuration of Datahaven validator
authorities during network launch.
- Added readiness check for the BEEFY protocol before relayer startup,
improving reliability of relayer operations.
- **Bug Fixes**
- Fixed indentation issues in configuration files for improved
readability and consistency.
- **Chores**
- Updated validator lists and addresses in configuration files.
- Enhanced e2e test scripts and added new commands for relayer and
minimal test scenarios.
- Added new dependency to test package.
- Updated version strings in package metadata.
- **Refactor**
- Improved logging and configuration handling during network and relayer
launches.
- Simplified import statements and removed unused code.
- **Style**
- Reformatted configuration and TypeScript files for better readability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Tim B <79199034+timbrinded@users.noreply.github.com>
Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
Eventually our CI will be required to run two private blockchains
locally plus associated relayers.
This PR is to prepare for this fate by improving run times and
refactoring our existing CIs so they are a bit easier to reason about.
### Refactors
- **_We now run ALL CIs on every PR!_** This is so that we decomplexify
the logic around conditional builds and fetching built binaries from
another source. This reduces the surface area of code we have to
maintain at the cost of execution time
- This penalty is ameliorated by a layered caching system. At best, it
will be less than a minute to complete a build since everything will be
cached. On GH runners this is about 6 minutes sadly.
- We will no longer be at risk of important CIs being skipped
erroneously which hide true failures.
- Caching is a low-risk approach because at worst it has to build from
scratch. A bad cache hit will never imply the wrong thing gets build
since cargo is smart enough to just throw away any inappropriate build
artefacts.
- `setup-rust` action created so we have a unified way of setting up
runner and unifying our approach to caching
- Use a unique caching key for different activities and it will fallback
to shared cache if no matches
- we are using `mainnet` kurtosis config so that it works with relayer
assumptions
### Additions
- We can specify the ethereum block time via a new cli arg `--slot-time
<seconds>`
- We can specify arbitrary network_param args which get passed into the
generated yaml
- e.g. giving `bun cli --kurtosis-network-args="pet=cat food=fish" will
add:
```yml
network_params:
# existing params...
pet: cat
food: fish
```
- We now have the ability to programmatically modify the yaml
- This means we are back down to a single `minimal.yml` kurtosis config
so we dont have to maintain changes between them
- Flow is: `add new cli arg` -> `add if() block which mutates yaml` ->
`profit`
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
This PR adds the `setup-validators` Typescript script that, given an
already started up network, sets up a new validator set and sends it
through Snowbridge's Gateway to the solochain. To accomplish that
purpose, this PR:
- Modifies the `DeployLocal` script to save in the `anvil.json` file not
only the deployed strategies' addresses but also the owner of each
strategy's underlying token. This owner is used as the source of funds
to transfer tokens to other validators so they can register under that
strategy.
- Adds an `OPERATOR_SOLOCHAIN_ADDRESS` to the `Accounts` utility script
contract. This address is the one used as the Solochain address when
registering a new Operator.
- Updates the `SignUpOperator` (which I believe is now deprecated since
we have multiple Operator Sets) and `SignUpOperatorBase` scripts to
adapt to both aforementioned changes.
- Updates the `ELScriptStorage` script to save the new extra information
of each deployed strategy (the creator of the underlying token) in
storage.
- Adds a `validator-set.json` file which contains the validators that
should be registered in the AVS and sent to the Solochain network
through the Snowbridge Gateway when starting any integration test. This
is currently hardcoded but could be generated in any other way, giving
us flexibility for testing.
- Adds both a Markdown file and a Excalidraw diagram showcasing both how
the setup of integration tests work and possible integration tests that
will be added in a future PR. This list is not exahustive as there are
many more scenarios we will want to test using integration tests.
- Updates the `e2e-cli.ts` script to execute the validator setup when
bootstrapping the network used for integration testing.
---------
Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>