Merge branch 'main' into fix/verify-allowlist-tx-receipt-status

This commit is contained in:
Steve Degosserie 2026-03-02 12:51:16 +02:00 committed by GitHub
commit 90c1f320e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 139 additions and 35 deletions

View file

@ -625,10 +625,43 @@ pub mod pallet {
impl<T: Config> OnEraEnd for Pallet<T> {
fn on_era_end(era_index: EraIndex) {
// Calculate performance-scaled inflation based on blocks produced.
// This must be done first since we use it for both minting and the rewards message.
let base_inflation = T::EraInflationProvider::get();
let scaled_inflation = Self::calculate_scaled_inflation(era_index, base_inflation);
// Check that there are reward points before minting.
// This prevents minting inflation when no validators have earned rewards.
let era_reward_points = RewardPointsForEra::<T>::get(&era_index);
let total_points: u128 = era_reward_points
.individual
.values()
.map(|pts| *pts as u128)
.sum();
if total_points.is_zero() {
log::error!(
target: "ext_validators_rewards",
"No reward points in era {}, skipping inflation minting",
era_index
);
return;
}
let ethereum_sovereign_account = T::RewardsEthereumSovereignAccount::get();
// Mint scaled inflation tokens using the configurable handler.
// Returns an InflationMintResult with the rewards/treasury split.
let mint_result = match T::HandleInflation::mint_inflation(
&ethereum_sovereign_account,
scaled_inflation,
) {
Ok(result) => result,
Err(err) => {
log::error!(target: "ext_validators_rewards", "Failed to handle inflation: {err:?}");
log::error!(target: "ext_validators_rewards", "Not sending message since there are no rewards to distribute");
return;
}
};
// Get era start timestamp from the active era (still the ending era at this point).
// Convert from milliseconds to seconds for EigenLayer compatibility.
let era_start_timestamp = T::EraIndexProvider::active_era()
@ -636,11 +669,11 @@ pub mod pallet {
.map(|ms| (ms / 1000) as u32)
.unwrap_or(0);
// Generate era rewards utils with the scaled inflation amount.
// This ensures the message to EigenLayer matches the actual minted amount.
let utils = match RewardPointsForEra::<T>::get(&era_index).generate_era_rewards_utils(
// Generate era rewards utils with the actual rewards amount (post-treasury split).
// This ensures the message to EigenLayer matches the actual minted rewards.
let utils = match era_reward_points.generate_era_rewards_utils(
era_index,
scaled_inflation,
mint_result.rewards_amount,
era_start_timestamp,
) {
Some(utils) => utils,
@ -654,17 +687,6 @@ pub mod pallet {
}
};
let ethereum_sovereign_account = T::RewardsEthereumSovereignAccount::get();
// Mint scaled inflation tokens using the configurable handler
if let Err(err) =
T::HandleInflation::mint_inflation(&ethereum_sovereign_account, scaled_inflation)
{
log::error!(target: "ext_validators_rewards", "Failed to handle inflation: {err:?}");
log::error!(target: "ext_validators_rewards", "Not sending message since there are no rewards to distribute");
return;
}
frame_system::Pallet::<T>::register_extra_weight_unchecked(
T::WeightInfo::on_era_end(),
DispatchClass::Mandatory,
@ -675,7 +697,7 @@ pub mod pallet {
message_id,
era_index,
total_points: utils.total_points,
inflation_amount: scaled_inflation,
inflation_amount: mint_result.rewards_amount,
});
}
}

View file

@ -230,7 +230,10 @@ impl pallet_external_validators_rewards::Config for Test {
pub struct InflationMinter;
impl HandleInflation<H160> for InflationMinter {
fn mint_inflation(rewards_account: &H160, total_amount: u128) -> sp_runtime::DispatchResult {
fn mint_inflation(
rewards_account: &H160,
total_amount: u128,
) -> Result<crate::types::InflationMintResult, sp_runtime::DispatchError> {
use sp_runtime::traits::Zero;
if total_amount.is_zero() {
@ -266,7 +269,10 @@ impl HandleInflation<H160> for InflationMinter {
.map_err(|_| DispatchError::Other("Failed to mint treasury inflation"))?;
}
Ok(())
Ok(crate::types::InflationMintResult {
rewards_amount,
treasury_amount,
})
}
}

View file

@ -160,15 +160,19 @@ fn test_on_era_end() {
let era_rewards = pallet_external_validators_rewards::RewardPointsForEra::<Test>::get(1);
let inflation =
<Test as pallet_external_validators_rewards::Config>::EraInflationProvider::get();
// The event should contain the rewards amount (post-treasury split), not the full inflation.
// Treasury gets Perbill::from_percent(20).mul_floor(inflation), rewards gets the rest.
let treasury_amount = InflationTreasuryProportion::get().mul_floor(inflation);
let rewards_amount = inflation - treasury_amount;
// Use 0 for era_start_timestamp in tests
let rewards_utils = era_rewards.generate_era_rewards_utils(1, inflation, 0);
let rewards_utils = era_rewards.generate_era_rewards_utils(1, rewards_amount, 0);
assert!(rewards_utils.is_some());
System::assert_last_event(RuntimeEvent::ExternalValidatorsRewards(
crate::Event::RewardsMessageSent {
message_id: Default::default(),
era_index: 1,
total_points: total_points as u128,
inflation_amount: inflation,
inflation_amount: rewards_amount,
},
));
})

View file

@ -39,14 +39,34 @@ pub trait SendMessage {
fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
}
// Trait for handling inflation
/// Result of minting inflation tokens, detailing the split between rewards and treasury.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct InflationMintResult {
/// Amount minted to the rewards account (for distribution to validators via AVS).
pub rewards_amount: u128,
/// Amount minted to the treasury account.
pub treasury_amount: u128,
}
/// Trait for handling inflation minting with a rewards/treasury split.
pub trait HandleInflation<AccountId> {
fn mint_inflation(who: &AccountId, amount: u128) -> sp_runtime::DispatchResult;
/// Mint inflation tokens, splitting between rewards and treasury.
/// Returns an `InflationMintResult` detailing the amounts minted to each destination.
fn mint_inflation(
who: &AccountId,
amount: u128,
) -> Result<InflationMintResult, sp_runtime::DispatchError>;
}
impl<AccountId> HandleInflation<AccountId> for () {
fn mint_inflation(_: &AccountId, _: u128) -> sp_runtime::DispatchResult {
Ok(())
fn mint_inflation(
_: &AccountId,
_: u128,
) -> Result<InflationMintResult, sp_runtime::DispatchError> {
Ok(InflationMintResult {
rewards_amount: 0,
treasury_amount: 0,
})
}
}

View file

@ -165,11 +165,15 @@ where
TreasuryProportion: Get<Perbill>,
TreasuryAccount: Get<crate::AccountId>,
{
/// Mints inflation tokens and splits them between rewards and treasury accounts
/// Mints inflation tokens and splits them between rewards and treasury accounts.
/// Returns an `InflationMintResult` detailing the amounts minted to each destination.
pub fn mint_inflation(
rewards_account: &crate::AccountId,
total_amount: u128,
) -> sp_runtime::DispatchResult {
) -> Result<
pallet_external_validators_rewards::types::InflationMintResult,
sp_runtime::DispatchError,
> {
use sp_runtime::traits::Zero;
if total_amount.is_zero() {
@ -236,7 +240,12 @@ where
treasury_amount
);
Ok(())
Ok(
pallet_external_validators_rewards::types::InflationMintResult {
rewards_amount,
treasury_amount,
},
)
}
}
@ -247,6 +256,7 @@ mod tests {
parameter_types,
traits::fungible::{Inspect, Mutate, Unbalanced},
};
use pallet_external_validators_rewards::types::InflationMintResult;
use sp_runtime::Perbill;
use std::cell::RefCell;
@ -561,7 +571,13 @@ mod tests {
let total_inflation = 1_000_000u128;
let result = TestHandler::mint_inflation(&rewards_account, total_inflation);
assert!(result.is_ok());
assert_eq!(
result,
Ok(InflationMintResult {
rewards_amount: 800_000,
treasury_amount: 200_000,
})
);
let rewards_balance = get_balance(&rewards_account);
let treasury_balance = get_balance(&TreasuryAccountId::get());
@ -579,7 +595,13 @@ mod tests {
let total_inflation = 1_000_000u128;
let result = TestHandler50Pct::mint_inflation(&rewards_account, total_inflation);
assert!(result.is_ok());
assert_eq!(
result,
Ok(InflationMintResult {
rewards_amount: 500_000,
treasury_amount: 500_000,
})
);
let rewards_balance = get_balance(&rewards_account);
let treasury_balance = get_balance(&TreasuryAccountId::get());
@ -596,7 +618,13 @@ mod tests {
let total_inflation = 1_000_000u128;
let result = TestHandler0Pct::mint_inflation(&rewards_account, total_inflation);
assert!(result.is_ok());
assert_eq!(
result,
Ok(InflationMintResult {
rewards_amount: total_inflation,
treasury_amount: 0,
})
);
let rewards_balance = get_balance(&rewards_account);
let treasury_balance = get_balance(&TreasuryAccountId::get());
@ -613,7 +641,13 @@ mod tests {
let total_inflation = 1_000_000u128;
let result = TestHandler100Pct::mint_inflation(&rewards_account, total_inflation);
assert!(result.is_ok());
assert_eq!(
result,
Ok(InflationMintResult {
rewards_amount: 0,
treasury_amount: total_inflation,
})
);
let rewards_balance = get_balance(&rewards_account);
let treasury_balance = get_balance(&TreasuryAccountId::get());

View file

@ -1460,7 +1460,13 @@ pub struct ExternalRewardsInflationHandler;
impl pallet_external_validators_rewards::types::HandleInflation<AccountId>
for ExternalRewardsInflationHandler
{
fn mint_inflation(who: &AccountId, amount: u128) -> sp_runtime::DispatchResult {
fn mint_inflation(
who: &AccountId,
amount: u128,
) -> Result<
pallet_external_validators_rewards::types::InflationMintResult,
sp_runtime::DispatchError,
> {
datahaven_runtime_common::inflation::ExternalRewardsInflationHandler::<
Balances,
runtime_params::dynamic_params::runtime_config::InflationTreasuryProportion,

View file

@ -1456,7 +1456,13 @@ pub struct ExternalRewardsInflationHandler;
impl pallet_external_validators_rewards::types::HandleInflation<AccountId>
for ExternalRewardsInflationHandler
{
fn mint_inflation(who: &AccountId, amount: u128) -> sp_runtime::DispatchResult {
fn mint_inflation(
who: &AccountId,
amount: u128,
) -> Result<
pallet_external_validators_rewards::types::InflationMintResult,
sp_runtime::DispatchError,
> {
datahaven_runtime_common::inflation::ExternalRewardsInflationHandler::<
Balances,
runtime_params::dynamic_params::runtime_config::InflationTreasuryProportion,

View file

@ -1460,7 +1460,13 @@ pub struct ExternalRewardsInflationHandler;
impl pallet_external_validators_rewards::types::HandleInflation<AccountId>
for ExternalRewardsInflationHandler
{
fn mint_inflation(who: &AccountId, amount: u128) -> sp_runtime::DispatchResult {
fn mint_inflation(
who: &AccountId,
amount: u128,
) -> Result<
pallet_external_validators_rewards::types::InflationMintResult,
sp_runtime::DispatchError,
> {
datahaven_runtime_common::inflation::ExternalRewardsInflationHandler::<
Balances,
runtime_params::dynamic_params::runtime_config::InflationTreasuryProportion,