Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions src/contracts/interfaces/IEmissionsController.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;

/// @title IEmissionsControllerErrors
/// @notice Errors for the IEmissionsController contract.
interface IEmissionsControllerErrors {
// TODO: Define with implementation.

}

/// @title IEmissionsControllerTypes
/// @notice Types for the IEmissionsController contract.
interface IEmissionsControllerTypes {
/// @notice Distribution types as defined in the ELIP.
/// @dev Ref: "Distribution Submission types may include: createRewardsForAllEarners, createOperatorSetTotalStakeRewardsSubmission, createOperatorSetUniqueStakeRewardsSubmission, EigenDA Distribution, Manual Distribution."
enum DistributionType {
RewardsForAllEarners,
OperatorSetTotalStake,
OperatorSetUniqueStake,
EigenDA,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't EigenDA just one of the old reward types? createAVSRewardsSubmission

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My interpretation is the intent of that ref is to give the possible types of rewards submissions that can be made? Could be wrong though

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discuss the approach here in this doc (reference)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. If this becomes too complex in the EmissionsController, it might be worth just adding another createAVSRewardsSubmission with the AVS parameter in the RewardsCoordinator. There would be no sidecar changes here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we'd use the exact same event/logic. Don't think it's unreasonable bloat

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well there would be a sidecar change in this case due to the additional parameter right?

Manual
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is manual? Just directed to anyone?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref: "Manual Distribution - Rewards that are sent directly to the Incentive Council multisig for manual distribution."

}

/// @notice A Distribution structure containing weight, type and strategies.
/// @dev Ref: "A Distribution consists of N fields: Weight, Distribution-type, Strategies and Multipliers."
struct Distribution {
/// The bips denominated weight of the distribution.
uint256 weight;
/// The type of distribution.
DistributionType distributionType;
/// The encoded rewards submission (either `RewardsSubmission` or `OperatorDirectedRewardsSubmission`).
bytes encodedRewardsSubmission;
}
}

/// @title IEmissionsControllerEvents
/// @notice Events for the IEmissionsController contract.
interface IEmissionsControllerEvents is IEmissionsControllerTypes {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need an event for pressButton().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add an event with the implementation.

/// @notice Emitted when a distribution is updated.
/// @param distributionId The id of the distribution.
/// @param distribution The distribution.
event DistributionUpdated(uint256 indexed distributionId, Distribution distribution);

/// @notice Emitted when a distribution is added.
/// @param distributionId The id of the distribution.
/// @param distribution The distribution.
event DistributionAdded(uint256 indexed distributionId, Distribution distribution);

/// @notice Emitted when a distribution is removed.
/// @param distributionId The id of the distribution.
event DistributionRemoved(uint256 indexed distributionId);

/// @notice Emitted when the Incentive Council address is updated.
/// @param incentiveCouncil The new Incentive Council address.
event IncentiveCouncilUpdated(address indexed incentiveCouncil);

/// @notice Emitted when the inflation rate is updated.
/// @param inflationRate The new inflation rate.
event InflationRateUpdated(uint256 indexed inflationRate);
}

/// @title IEmissionsController
/// @notice Interface for the EmissionsController contract, which acts as the upgraded ActionGenerator.
/// @dev Ref: "This proposal requires upgrades to the TokenHopper and Action Generator contracts."
interface IEmissionsController is IEmissionsControllerErrors, IEmissionsControllerEvents {
/// -----------------------------------------------------------------------
/// Constants
/// -----------------------------------------------------------------------
/// @notice The rate of inflation for emissions.
/// @dev Immutable/constant variable that requires an upgrade to modify.
function EMISSIONS_INFLATION_RATE() external view returns (uint256);

/// @notice The start time of the emissions.
/// @dev Immutable/constant variable that requires an upgrade to modify.
function EMISSIONS_START_TIME() external view returns (uint256);

/// @notice The cooldown seconds of the emissions.
/// @dev Immutable/constant variable that requires an upgrade to modify.
function EMISSIONS_COOLDOWN_SECONDS() external view returns (uint256);

/// -----------------------------------------------------------------------
/// Initialization Functions
/// -----------------------------------------------------------------------

/// @notice Initializes the contract.
/// @param incentiveCouncil The initial Incentive Council address.
function initialize(
address incentiveCouncil
) external;

/// -----------------------------------------------------------------------
/// Permissionless Trigger
/// -----------------------------------------------------------------------

/// @notice Triggers the weekly emissions.
/// @dev Try/catch is used to prevent a single reverting rewards submission from halting emissions.
/// @dev Pagination is used to prevent out-of-gas errors; multiple calls may be needed to process all submissions.
/// @dev Ref: "The ActionGenerator today is a contract ... that is triggered by the Hopper. When triggered, it mints new EIGEN tokens..."
/// @dev Permissionless function that can be called by anyone when `isButtonPressable()` returns true.
function pressButton() external;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might have to batch this if the size of the distribution array becomes too large... something to think about for implementation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good callout, yeah will need to ensure the button is always "pressable".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment noting we should use pagination to avoid DOS/OOG.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what happens if one of the many reward tx's fail?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a try-catch for that or do we ensure it doesn't fail at all? How does the current Hopper handle that?

Copy link
Collaborator

@non-fungible-nelson non-fungible-nelson Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MC1823315 calls this out... Try-Catch (or error handling) is necessary to ensure minting does not revert (push button succeeds).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make sure that wallets will properly estimate this. We've had a bunch of problems with slashing when it came to using a try-catch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this relevant for pressButton() though? Shouldn't this primarily be called by a cronjob that can set an arbitrarily large gas limit?


/// -----------------------------------------------------------------------
/// Protocol Council Functions
/// -----------------------------------------------------------------------

/// @notice Sets the Incentive Council address.
/// @dev Only the Protocol Council can call this function.
/// @dev Ref: "Protocol Council Functions: Set Incentive Council multisig address that can interface with the ActionGenerator..."
/// @param incentiveCouncil The new Incentive Council address.
function setIncentiveCouncil(
address incentiveCouncil
) external;

/// -----------------------------------------------------------------------
/// Incentive Council Functions
/// -----------------------------------------------------------------------

/// @notice Adds a new distribution.
/// @dev Only the Incentive Council can call this function.
/// @dev Ref: "Incentive Council Functions: addDistribution(weight{int}, distribution-type{see below}, strategiesAndMultipliers())"
/// @param distribution The distribution to add.
/// @return distributionId The id of the added distribution.
function addDistribution(
Distribution calldata distribution
) external returns (uint256 distributionId);

/// @notice Updates an existing distribution.
/// @dev Only the Incentive Council can call this function.
/// @dev Ref: "Incentive Council Functions: updateDistribution(distributionId)"
/// @param distributionId The id of the distribution to update.
/// @param distribution The new distribution.
function updateDistribution(
uint256 distributionId,
Distribution calldata distribution
) external;

/// @notice Cancels a distribution.
/// @dev The distribution remains in storage, but is marked as cancelled.
/// @dev Only the Incentive Council can call this function.
/// @dev Ref: Implied by "updateDistribution" and general management of distributions.
/// @param distributionId The id of the distribution to remove.
function removeDistribution(
uint256 distributionId
) external;

/// -----------------------------------------------------------------------
/// View
/// -----------------------------------------------------------------------

/// @notice Checks if the emissions can be triggered.
/// @return True if the cooldown has passed and the system is ready.
function isButtonPressable() external view returns (bool);

/// @notice Returns the next button press time.
/// @return The next button press time.
function nextButtonPressTime() external view returns (uint256);

/// @notice Returns the last button press time.
/// @return The last button press time.
function lastButtonPressTime() external view returns (uint256);

/// @notice Returns a distribution by index.
/// @param distributionId The id of the distribution.
/// @return The Distribution struct at the given index.
function getDistribution(
uint256 distributionId
) external view returns (Distribution memory);

/// @notice Returns all distributions.
/// @return An append-only array of Distribution structs.
function getDistributions() external view returns (Distribution[] memory);

/// @notice Returns the current Incentive Council address.
/// @return The Incentive Council address.
function getIncentiveCouncil() external view returns (address);
}
Loading