Skip to content

Commit 1103809

Browse files
committed
feat: rewards v2.2 (#1659)
**Motivation:** We need to support Rewards v2.2 : - Rewards that are linear to allocated unique stake (Needs to be both retroactive and future-looking). - Rewards that are linear to total stake (Needs to be both retroactive and future-looking). TDD: https://www.notion.so/eigen-labs/PRD-Rewards-v2-2-Operator-Set-Rewards-with-Unique-Total-Stake-28513c11c3e080cbb856e41ddc6362f5 **Modifications:** Updates in `RewardsCoordinator`: - New `createUniqueStakeRewardsSubmission` function with `UniqueStakeRewardsSubmissionCreated` event emission - New `PAUSED_UNIQUE_STAKE_REWARDS_SUBMISSION` constant - New `isUniqueStakeRewardsSubmissionHash` mapping - New `createTotalStakeRewardsSubmission` function with `TotalStakeRewardsSubmissionCreated` event emission - New `PAUSED_TOTAL_STAKE_REWARDS_SUBMISSION` constant - New `isTotalStakeRewardsSubmissionHash` mapping - Updated storage gap to 33 slots (from 35 slots) Updated Bindings **Result:** Support for Rewards v2.2
1 parent 7a6f055 commit 1103809

File tree

7 files changed

+2581
-6
lines changed

7 files changed

+2581
-6
lines changed

pkg/bindings/IRewardsCoordinator/binding.go

Lines changed: 355 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/bindings/RewardsCoordinator/binding.go

Lines changed: 418 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/bindings/RewardsCoordinatorStorage/binding.go

Lines changed: 417 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/contracts/core/RewardsCoordinator.sol

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,52 @@ contract RewardsCoordinator is
200200
}
201201
}
202202

203+
/// @inheritdoc IRewardsCoordinator
204+
function createUniqueStakeRewardsSubmission(
205+
OperatorSet calldata operatorSet,
206+
RewardsSubmission[] calldata rewardsSubmissions
207+
) external onlyWhenNotPaused(PAUSED_UNIQUE_STAKE_REWARDS_SUBMISSION) checkCanCall(operatorSet.avs) nonReentrant {
208+
require(allocationManager.isOperatorSet(operatorSet), InvalidOperatorSet());
209+
for (uint256 i = 0; i < rewardsSubmissions.length; ++i) {
210+
RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i];
211+
uint256 nonce = submissionNonce[operatorSet.avs];
212+
bytes32 rewardsSubmissionHash = keccak256(abi.encode(operatorSet.avs, nonce, rewardsSubmission));
213+
214+
_validateRewardsSubmission(rewardsSubmission);
215+
216+
isUniqueStakeRewardsSubmissionHash[operatorSet.avs][rewardsSubmissionHash] = true;
217+
submissionNonce[operatorSet.avs] = nonce + 1;
218+
219+
emit UniqueStakeRewardsSubmissionCreated(
220+
msg.sender, rewardsSubmissionHash, operatorSet, nonce, rewardsSubmission
221+
);
222+
rewardsSubmission.token.safeTransferFrom(msg.sender, address(this), rewardsSubmission.amount);
223+
}
224+
}
225+
226+
/// @inheritdoc IRewardsCoordinator
227+
function createTotalStakeRewardsSubmission(
228+
OperatorSet calldata operatorSet,
229+
RewardsSubmission[] calldata rewardsSubmissions
230+
) external onlyWhenNotPaused(PAUSED_TOTAL_STAKE_REWARDS_SUBMISSION) checkCanCall(operatorSet.avs) nonReentrant {
231+
require(allocationManager.isOperatorSet(operatorSet), InvalidOperatorSet());
232+
for (uint256 i = 0; i < rewardsSubmissions.length; ++i) {
233+
RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i];
234+
uint256 nonce = submissionNonce[operatorSet.avs];
235+
bytes32 rewardsSubmissionHash = keccak256(abi.encode(operatorSet.avs, nonce, rewardsSubmission));
236+
237+
_validateRewardsSubmission(rewardsSubmission);
238+
239+
isTotalStakeRewardsSubmissionHash[operatorSet.avs][rewardsSubmissionHash] = true;
240+
submissionNonce[operatorSet.avs] = nonce + 1;
241+
242+
emit TotalStakeRewardsSubmissionCreated(
243+
msg.sender, rewardsSubmissionHash, operatorSet, nonce, rewardsSubmission
244+
);
245+
rewardsSubmission.token.safeTransferFrom(msg.sender, address(this), rewardsSubmission.amount);
246+
}
247+
}
248+
203249
/// @inheritdoc IRewardsCoordinator
204250
function processClaim(
205251
RewardsMerkleClaim calldata claim,

src/contracts/core/storage/RewardsCoordinatorStorage.sol

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator {
3232
uint8 internal constant PAUSED_OPERATOR_SET_SPLIT = 8;
3333
/// @dev Index for flag that pauses calling setOperatorSetPerformanceRewardsSubmission
3434
uint8 internal constant PAUSED_OPERATOR_DIRECTED_OPERATOR_SET_REWARDS_SUBMISSION = 9;
35+
/// @dev Index for flag that pauses calling createOperatorSetRewardsSubmission
36+
uint8 internal constant PAUSED_UNIQUE_STAKE_REWARDS_SUBMISSION = 10;
37+
/// @dev Index for flag that pauses calling createTotalStakeRewardsSubmission
38+
uint8 internal constant PAUSED_TOTAL_STAKE_REWARDS_SUBMISSION = 11;
3539

3640
/// @dev Salt for the earner leaf, meant to distinguish from tokenLeaf since they have the same sized data
3741
uint8 internal constant EARNER_LEAF_SALT = 0;
@@ -130,8 +134,13 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator {
130134
mapping(address avs => mapping(bytes32 hash => bool valid)) public
131135
isOperatorDirectedOperatorSetRewardsSubmissionHash;
132136

133-
// Construction
137+
/// @notice Returns whether a `hash` is a `valid` unique stake rewards submission hash for a given `avs`.
138+
mapping(address avs => mapping(bytes32 hash => bool valid)) public isUniqueStakeRewardsSubmissionHash;
139+
140+
/// @notice Returns whether a `hash` is a `valid` total stake rewards submission hash for a given `avs`.
141+
mapping(address avs => mapping(bytes32 hash => bool valid)) public isTotalStakeRewardsSubmissionHash;
134142

143+
// Construction
135144
constructor(
136145
IDelegationManager _delegationManager,
137146
IStrategyManager _strategyManager,
@@ -161,5 +170,5 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator {
161170
* variables without shifting down storage in the inheritance chain.
162171
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
163172
*/
164-
uint256[35] private __gap;
173+
uint256[33] private __gap;
165174
}

src/contracts/interfaces/IRewardsCoordinator.sol

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,38 @@ interface IRewardsCoordinatorEvents is IRewardsCoordinatorTypes {
331331
OperatorDirectedRewardsSubmission operatorDirectedRewardsSubmission
332332
);
333333

334+
/**
335+
* @notice Emitted when an AVS creates a valid `UniqueStakeRewardsSubmission` for an operator set.
336+
* @param caller The address calling `createUniqueStakeRewardsSubmission`.
337+
* @param rewardsSubmissionHash Keccak256 hash of (`avs`, `submissionNonce` and `rewardsSubmission`).
338+
* @param operatorSet The operatorSet on behalf of which the rewards are being submitted.
339+
* @param submissionNonce Current nonce of the avs. Used to generate a unique submission hash.
340+
* @param rewardsSubmission The Rewards Submission. Contains the token, start timestamp, duration, strategies and multipliers.
341+
*/
342+
event UniqueStakeRewardsSubmissionCreated(
343+
address indexed caller,
344+
bytes32 indexed rewardsSubmissionHash,
345+
OperatorSet operatorSet,
346+
uint256 submissionNonce,
347+
RewardsSubmission rewardsSubmission
348+
);
349+
350+
/**
351+
* @notice Emitted when an AVS creates a valid `TotalStakeRewardsSubmission` for an operator set.
352+
* @param caller The address calling `createTotalStakeRewardsSubmission`.
353+
* @param rewardsSubmissionHash Keccak256 hash of (`avs`, `submissionNonce` and `rewardsSubmission`).
354+
* @param operatorSet The operatorSet on behalf of which the rewards are being submitted.
355+
* @param submissionNonce Current nonce of the avs. Used to generate a unique submission hash.
356+
* @param rewardsSubmission The Rewards Submission. Contains the token, start timestamp, duration, strategies and multipliers.
357+
*/
358+
event TotalStakeRewardsSubmissionCreated(
359+
address indexed caller,
360+
bytes32 indexed rewardsSubmissionHash,
361+
OperatorSet operatorSet,
362+
uint256 submissionNonce,
363+
RewardsSubmission rewardsSubmission
364+
);
365+
334366
/// @notice rewardsUpdater is responsible for submitting DistributionRoots, only owner can set rewardsUpdater
335367
event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater);
336368

@@ -513,6 +545,40 @@ interface IRewardsCoordinator is IRewardsCoordinatorErrors, IRewardsCoordinatorE
513545
OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions
514546
) external;
515547

548+
/**
549+
* @notice Creates a new unique stake rewards submission for an operator set, to be split amongst the operators and
550+
* set of stakers delegated to operators. The operators have to both be registered and allocate unique slashable stake to the operator set to be rewarded.
551+
* @param operatorSet The operator set for which the rewards are being submitted
552+
* @param rewardsSubmissions The rewards submissions being created
553+
* @dev Expected to be called by the AVS that created the operator set
554+
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`
555+
* @dev The duration of the `rewardsSubmission` cannot be 0 and must be a multiple of `CALCULATION_INTERVAL_SECONDS`
556+
* @dev The tokens are sent to the `RewardsCoordinator` contract
557+
* @dev Strategies must be in ascending order of addresses to check for duplicates
558+
* @dev This function will revert if the `rewardsSubmissions` is malformed.
559+
*/
560+
function createUniqueStakeRewardsSubmission(
561+
OperatorSet calldata operatorSet,
562+
RewardsSubmission[] calldata rewardsSubmissions
563+
) external;
564+
565+
/**
566+
* @notice Creates a new total stake rewards submission for an operator set, to be split amongst the operators and
567+
* set of stakers delegated to operators. The operators have to just be registered to the operator set to be rewarded.
568+
* @param operatorSet The operator set for which the rewards are being submitted
569+
* @param rewardsSubmissions The rewards submissions being created
570+
* @dev Expected to be called by the AVS that created the operator set
571+
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`
572+
* @dev The duration of the `rewardsSubmission` cannot be 0 and must be a multiple of `CALCULATION_INTERVAL_SECONDS`
573+
* @dev The tokens are sent to the `RewardsCoordinator` contract
574+
* @dev Strategies must be in ascending order of addresses to check for duplicates
575+
* @dev This function will revert if the `rewardsSubmissions` is malformed.
576+
*/
577+
function createTotalStakeRewardsSubmission(
578+
OperatorSet calldata operatorSet,
579+
RewardsSubmission[] calldata rewardsSubmissions
580+
) external;
581+
516582
/**
517583
* @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]).
518584
* Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for,

0 commit comments

Comments
 (0)