mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 01:38:32 +00:00
### Summary
This PR implements the EigenLayer Rewards Distribution V2 model for
DataHaven, replacing the previous merkle-root-based rewards registry
approach with EigenLayer's native `OperatorDirectedRewardsSubmission`
API. This enables direct integration with EigenLayer's
RewardsCoordinator for validator rewards distribution.
### Motivation
EigenLayer's V2 rewards model provides several advantages:
- **Direct integration**: Uses EigenLayer's native
`createOperatorDirectedOperatorSetRewardsSubmission` API
- **Per-operator rewards**: Distributes rewards proportionally to
individual operators based on their earned points
- **Simplified architecture**: Removes the need for a separate
RewardsRegistry contract
- **Better UX**: Operators receive rewards directly through EigenLayer's
established claiming mechanism
### Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ DataHaven Substrate │
├─────────────────────────────────────────────────────────────────┤
│ Era End │
│ │ │
│ ▼ │
│ external-validators-rewards pallet │
│ │ generate_era_rewards_utils() │
│ │ • Calculate individual points per validator │
│ │ • Compute total inflation amount │
│ │ │
│ ▼ │
│ RewardsSubmissionAdapter (runtime_common) │
│ │ build() → points_to_rewards() → encode_rewards_calldata() │
│ │ │
│ ▼ │
│ Snowbridge Outbound Queue │
│ │ CallContract(ServiceManager.submitRewards(...)) │
└────│────────────────────────────────────────────────────────────┘
│
▼ Cross-chain message via Snowbridge
┌─────────────────────────────────────────────────────────────────┐
│ Ethereum │
├─────────────────────────────────────────────────────────────────┤
│ DataHavenServiceManager │
│ │ submitRewards(OperatorDirectedRewardsSubmission) │
│ │ • Approve wHAVE tokens to RewardsCoordinator │
│ │ │
│ ▼ │
│ EigenLayer RewardsCoordinator │
│ │ createOperatorDirectedOperatorSetRewardsSubmission() │
│ │ │
│ ▼ │
│ Operators claim rewards via EigenLayer │
└─────────────────────────────────────────────────────────────────┘
```
### Changes Overview
#### Smart Contracts (`contracts/`)
**DataHavenServiceManager.sol**
- Added `submitRewards(OperatorDirectedRewardsSubmission)` function to
submit rewards to EigenLayer's RewardsCoordinator
- Implements `SafeERC20` for secure token approvals
- Uses `onlyRewardsInitiator` modifier for access control (Snowbridge
Agent)
- Emits `RewardsSubmitted` and `RewardsInitiatorSet` events for tracking
**IDataHavenServiceManager.sol**
- Added `submitRewards()` interface for EigenLayer rewards submission
- Added `setRewardsInitiator()` interface for configuring the authorized
caller
- Added new events: `RewardsSubmitted`, `RewardsInitiatorSet`
**New Test: RewardsSubmitter.t.sol**
- Comprehensive test suite covering:
- Access control (only rewards initiator can submit)
- Single and multiple operator rewards
- Multiple consecutive submissions
- Custom descriptions and different tokens
#### Substrate Runtime (`operator/`)
**New: `runtime/common/src/rewards_adapter.rs` (934 lines)**
A generic, configurable adapter for building EigenLayer rewards
messages:
- **`RewardsSubmissionConfig` trait**: Runtime-agnostic configuration
interface
- `OutboundQueue`: Snowbridge outbound queue type
- `rewards_duration()`: Reward period duration (typically 86400s)
- `whave_token_address()`: wHAVE ERC20 token on Ethereum
- `service_manager_address()`: ServiceManager contract address
- `rewards_agent_origin()`: Snowbridge agent origin
- **`RewardsSubmissionAdapter<C>`**: Generic implementation of
`SendMessage` trait
- **`points_to_rewards()`**: Converts validator points to token amounts
- Proportional distribution based on total points
- Returns remainder (dust) from integer division
- Arithmetic overflow/underflow protection
- **`encode_rewards_calldata()`**: ABI-encodes the `submitRewards` call
- Uses `alloy-core` for type-safe Solidity ABI encoding
- Validates `uint96` multiplier bounds
- **Comprehensive test suite** covering:
- Basic and edge-case reward calculations
- Remainder/dust handling
- Overflow/underflow protection
- ABI encoding round-trip verification
- Message building with various configurations
**Modified: `pallets/external-validators-rewards/`**
- **`types.rs`**: Extended `EraRewardsUtils` struct:
```rust
pub struct EraRewardsUtils {
pub era_index: u32, // NEW
pub rewards_merkle_root: H256,
pub leaves: Vec<H256>,
pub leaf_index: Option<u64>,
pub total_points: u128,
pub individual_points: Vec<(H160, u32)>, // NEW
pub inflation_amount: u128, // NEW
pub era_start_timestamp: u32 // NEW
}
```
- **`lib.rs`**: Updated `generate_era_rewards_utils()`:
- Now accepts `inflation_amount` parameter
- Extracts `individual_points` as `(H160, u32)` tuples for EigenLayer
- Returns `None` when `total_points` is zero (prevents inflation with no
distribution)
- **`mock.rs`**: Updated test mock to use `H160` as `AccountId`
(matching DataHaven's EVM-compatible account model)
**Modified: Runtime Configurations**
All three runtimes (mainnet, stagenet, testnet) updated:
1. **New runtime parameters** (`runtime_params.rs`):
- `ServiceManagerAddress`: DataHaven ServiceManager contract on Ethereum
- `WHAVETokenAddress`: wHAVE ERC20 token address
- `RewardsGenesisTimestamp`: EigenLayer-aligned genesis timestamp
- `RewardsDuration`: Rewards period (default: 86400 = 1 day)
2. **Refactored `RewardsSendAdapter`**:
- Replaced inline implementation with `RewardsSubmissionAdapter<Config>`
- Each runtime implements `RewardsSubmissionConfig` trait
- Cleaner, DRY configuration
## ⚠️ Breaking Changes ⚠️
- **Runtime Parameters**: New parameters must be configured via
governance before rewards submission will work:
- `ServiceManagerAddress` (replaces `RewardsRegistryAddress`)
- `WHAVETokenAddress`
- `RewardsGenesisTimestamp`
- **Contract Interface**: `submitRewards()` now accepts a full
`OperatorDirectedRewardsSubmission` struct instead of a merkle root
---------
Co-authored-by: Gonza Montiel <gonzamontiel@users.noreply.github.com>
18 lines
266 B
JSON
18 lines
266 B
JSON
[
|
|
{
|
|
"name": "EthereumGatewayAddress",
|
|
"value": null
|
|
},
|
|
{
|
|
"name": "RewardsUpdateSelector",
|
|
"value": null
|
|
},
|
|
{
|
|
"name": "RewardsAgentOrigin",
|
|
"value": null
|
|
},
|
|
{
|
|
"name": "DatahavenServiceManagerAddress",
|
|
"value": null
|
|
}
|
|
]
|