-
Notifications
You must be signed in to change notification settings - Fork 330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Rewards v2 #837
base: dev
Are you sure you want to change the base?
feat: Rewards v2 #837
Changes from 5 commits
95da83f
72d118b
9fa7737
de66c70
72cf05e
3975548
179aa1f
d4db04d
acd51b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file was touched since |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,6 +45,8 @@ contract RewardsCoordinator is | |
uint8 internal constant PAUSED_SUBMIT_DISABLE_ROOTS = 3; | ||
/// @dev Index for flag that pauses calling rewardAllStakersAndOperators | ||
uint8 internal constant PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS = 4; | ||
/// @dev Index for flag that pauses calling createAVSPerformanceRewardsSubmission | ||
uint8 internal constant PAUSED_AVS_PERFORMANCE_REWARDS_SUBMISSION = 5; | ||
|
||
/// @dev Salt for the earner leaf, meant to distinguish from tokenLeaf since they have the same sized data | ||
uint8 internal constant EARNER_LEAF_SALT = 0; | ||
|
@@ -118,11 +120,9 @@ contract RewardsCoordinator is | |
*/ | ||
|
||
/// @inheritdoc IRewardsCoordinator | ||
function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) | ||
external | ||
onlyWhenNotPaused(PAUSED_AVS_REWARDS_SUBMISSION) | ||
nonReentrant | ||
{ | ||
function createAVSRewardsSubmission( | ||
RewardsSubmission[] calldata rewardsSubmissions | ||
) external onlyWhenNotPaused(PAUSED_AVS_REWARDS_SUBMISSION) nonReentrant { | ||
Comment on lines
+123
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was changed due to auto linting. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Multiple other auto-linting instances in this PR. |
||
for (uint256 i = 0; i < rewardsSubmissions.length; i++) { | ||
RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i]; | ||
uint256 nonce = submissionNonce[msg.sender]; | ||
|
@@ -139,12 +139,9 @@ contract RewardsCoordinator is | |
} | ||
|
||
/// @inheritdoc IRewardsCoordinator | ||
function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmissions) | ||
external | ||
onlyWhenNotPaused(PAUSED_REWARDS_FOR_ALL_SUBMISSION) | ||
onlyRewardsForAllSubmitter | ||
nonReentrant | ||
{ | ||
function createRewardsForAllSubmission( | ||
RewardsSubmission[] calldata rewardsSubmissions | ||
) external onlyWhenNotPaused(PAUSED_REWARDS_FOR_ALL_SUBMISSION) onlyRewardsForAllSubmitter nonReentrant { | ||
for (uint256 i = 0; i < rewardsSubmissions.length; i++) { | ||
RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i]; | ||
uint256 nonce = submissionNonce[msg.sender]; | ||
|
@@ -161,12 +158,9 @@ contract RewardsCoordinator is | |
} | ||
|
||
/// @inheritdoc IRewardsCoordinator | ||
function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) | ||
external | ||
onlyWhenNotPaused(PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS) | ||
onlyRewardsForAllSubmitter | ||
nonReentrant | ||
{ | ||
function createRewardsForAllEarners( | ||
RewardsSubmission[] calldata rewardsSubmissions | ||
) external onlyWhenNotPaused(PAUSED_REWARD_ALL_STAKERS_AND_OPERATORS) onlyRewardsForAllSubmitter nonReentrant { | ||
for (uint256 i = 0; i < rewardsSubmissions.length; i++) { | ||
RewardsSubmission calldata rewardsSubmission = rewardsSubmissions[i]; | ||
uint256 nonce = submissionNonce[msg.sender]; | ||
|
@@ -178,12 +172,41 @@ contract RewardsCoordinator is | |
submissionNonce[msg.sender] = nonce + 1; | ||
|
||
emit RewardsSubmissionForAllEarnersCreated( | ||
msg.sender, nonce, rewardsSubmissionForAllEarnersHash, rewardsSubmission | ||
msg.sender, | ||
nonce, | ||
rewardsSubmissionForAllEarnersHash, | ||
rewardsSubmission | ||
); | ||
rewardsSubmission.token.safeTransferFrom(msg.sender, address(this), rewardsSubmission.amount); | ||
} | ||
} | ||
|
||
/// @inheritdoc IRewardsCoordinator | ||
function createAVSPerformanceRewardsSubmission( | ||
PerformanceRewardsSubmission[] calldata performanceRewardsSubmissions | ||
) external onlyWhenNotPaused(PAUSED_AVS_PERFORMANCE_REWARDS_SUBMISSION) nonReentrant { | ||
for (uint256 i = 0; i < performanceRewardsSubmissions.length; i++) { | ||
PerformanceRewardsSubmission calldata performanceRewardsSubmission = performanceRewardsSubmissions[i]; | ||
uint256 nonce = submissionNonce[msg.sender]; | ||
bytes32 performanceRewardsSubmissionHash = keccak256( | ||
abi.encode(msg.sender, nonce, performanceRewardsSubmission) | ||
); | ||
|
||
uint256 totalAmount = _validatePerformanceRewardsSubmission(performanceRewardsSubmission); | ||
|
||
isAVSPerformanceRewardsSubmissionHash[msg.sender][performanceRewardsSubmissionHash] = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need to check that it already exists There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The nonce keeps monotonically increasing. So it can theoretically never exist already. That was the point of the nonce here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, sounds good |
||
submissionNonce[msg.sender] = nonce + 1; | ||
|
||
emit AVSPerformanceRewardsSubmissionCreated( | ||
msg.sender, | ||
nonce, | ||
performanceRewardsSubmissionHash, | ||
performanceRewardsSubmission | ||
); | ||
performanceRewardsSubmission.token.safeTransferFrom(msg.sender, address(this), totalAmount); | ||
} | ||
} | ||
|
||
/// @inheritdoc IRewardsCoordinator | ||
function processClaim( | ||
RewardsMerkleClaim calldata claim, | ||
|
@@ -315,8 +338,8 @@ contract RewardsCoordinator is | |
"RewardsCoordinator._validateRewardsSubmission: startTimestamp must be a multiple of CALCULATION_INTERVAL_SECONDS" | ||
); | ||
require( | ||
block.timestamp - MAX_RETROACTIVE_LENGTH <= rewardsSubmission.startTimestamp | ||
&& GENESIS_REWARDS_TIMESTAMP <= rewardsSubmission.startTimestamp, | ||
block.timestamp - MAX_RETROACTIVE_LENGTH <= rewardsSubmission.startTimestamp && | ||
GENESIS_REWARDS_TIMESTAMP <= rewardsSubmission.startTimestamp, | ||
"RewardsCoordinator._validateRewardsSubmission: startTimestamp too far in the past" | ||
); | ||
require( | ||
|
@@ -340,6 +363,83 @@ contract RewardsCoordinator is | |
} | ||
} | ||
|
||
/** | ||
* @notice Validate a PerformanceRewardsSubmission. Called from `createAVSPerformanceRewardsSubmission`. | ||
* @param performanceRewardsSubmission PerformanceRewardsSubmission to validate. | ||
* @return total amount to be transferred from the avs to the contract. | ||
*/ | ||
function _validatePerformanceRewardsSubmission( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not checking for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could u add this in code comments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 179aa1f as a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thoughts on using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's do that with slashing like we are on #727 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright holding off on custom errors for now. |
||
PerformanceRewardsSubmission calldata performanceRewardsSubmission | ||
) internal view returns (uint256) { | ||
require( | ||
performanceRewardsSubmission.strategiesAndMultipliers.length > 0, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: no strategies set" | ||
); | ||
require( | ||
performanceRewardsSubmission.operatorRewards.length > 0, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: no operators rewarded" | ||
); | ||
|
||
uint256 totalAmount = 0; | ||
address currOperatorAddress = address(0); | ||
for (uint256 i = 0; i < performanceRewardsSubmission.operatorRewards.length; ++i) { | ||
OperatorReward calldata operatorReward = performanceRewardsSubmission.operatorRewards[i]; | ||
require( | ||
operatorReward.operator != address(0), | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: operator cannot be 0 address" | ||
); | ||
require( | ||
currOperatorAddress < operatorReward.operator, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: operators must be in ascending order to handle duplicates" | ||
Comment on lines
+396
to
+397
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a more gas efficient way of not having a temporary storage slot? Seems rather restrictive on the client but not seemingly impossible I suppose. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, who cares if there are duplicates? Is it up to us to infer their intention? Are there any side effects of allowing duplicates? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is your question: why are we doing this check? If that's the case we're doing it so that the AVS can't pass in duplicate operator addresses into the reward submission, and this is the cheapest way we can check that without doing any searching of the array. The cli/sdk can easily sort it into this order and warn if there are duplicates before the transaction is submitted onchain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do this duplicate check for the Rewards v1 submission. So I'm assuming it's some constraint on the pipeline and to make some calculation easier (I'm just speculating, but I could be wrong - Need to check this assumption). But besides that why would an AVS need to pay the same operator 2 different amounts in the same reward submission? This seems like a nice constraint to have. |
||
); | ||
currOperatorAddress = operatorReward.operator; | ||
require( | ||
operatorReward.amount > 0, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: operator reward amount cannot be 0" | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are the gas costs for 200,500,1000 operators? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is that question wrt to this check or in general how much it would cost if 200,500,1000 operators were passed in calldata? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The latter |
||
totalAmount += operatorReward.amount; | ||
} | ||
|
||
require( | ||
performanceRewardsSubmission.duration <= MAX_REWARDS_DURATION, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: duration exceeds MAX_REWARDS_DURATION" | ||
); | ||
require( | ||
performanceRewardsSubmission.duration % CALCULATION_INTERVAL_SECONDS == 0, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: duration must be a multiple of CALCULATION_INTERVAL_SECONDS" | ||
); | ||
require( | ||
performanceRewardsSubmission.startTimestamp % CALCULATION_INTERVAL_SECONDS == 0, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: startTimestamp must be a multiple of CALCULATION_INTERVAL_SECONDS" | ||
); | ||
require( | ||
block.timestamp - MAX_RETROACTIVE_LENGTH <= performanceRewardsSubmission.startTimestamp && | ||
GENESIS_REWARDS_TIMESTAMP <= performanceRewardsSubmission.startTimestamp, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: startTimestamp too far in the past" | ||
); | ||
require( | ||
performanceRewardsSubmission.startTimestamp + performanceRewardsSubmission.duration < block.timestamp, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: performance rewards submission is not retroactive" | ||
); | ||
|
||
// Require performanceRewardsSubmission is for whitelisted strategy or beaconChainETHStrategy | ||
address currAddress = address(0); | ||
for (uint256 i = 0; i < performanceRewardsSubmission.strategiesAndMultipliers.length; ++i) { | ||
IStrategy strategy = performanceRewardsSubmission.strategiesAndMultipliers[i].strategy; | ||
require( | ||
strategyManager.strategyIsWhitelistedForDeposit(strategy) || strategy == beaconChainETHStrategy, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: invalid strategy considered" | ||
); | ||
Comment on lines
+433
to
+436
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this propertly support longtail assets? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question. It was something I had noted down myself to check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rewards works out of the box for longtail assets without overflow since we limit the number of shares that can be minted for any strategy |
||
require( | ||
currAddress < address(strategy), | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: strategies must be in ascending order to handle duplicates" | ||
); | ||
currAddress = address(strategy); | ||
} | ||
|
||
return totalAmount; | ||
} | ||
|
||
function _checkClaim(RewardsMerkleClaim calldata claim, DistributionRoot memory root) internal view { | ||
require(!root.disabled, "RewardsCoordinator._checkClaim: root is disabled"); | ||
require(block.timestamp >= root.activatedAt, "RewardsCoordinator._checkClaim: root not activated yet"); | ||
|
@@ -430,9 +530,9 @@ contract RewardsCoordinator is | |
// forgefmt: disable-next-item | ||
require( | ||
Merkle.verifyInclusionKeccak({ | ||
root: root, | ||
index: earnerLeafIndex, | ||
proof: earnerProof, | ||
root: root, | ||
index: earnerLeafIndex, | ||
proof: earnerProof, | ||
leaf: earnerLeafHash | ||
}), | ||
"RewardsCoordinator._verifyEarnerClaimProof: invalid earner claim proof" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,6 +89,9 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { | |
/// if rewards submission hash for all stakers and operators has been submitted | ||
mapping(address => mapping(bytes32 => bool)) public isRewardsSubmissionForAllEarnersHash; | ||
|
||
/// @notice Mapping: avs => avsPerformanceRewardsSubmissionHash => bool to check if performance rewards submission hash has been submitted | ||
mapping(address => mapping(bytes32 => bool)) public isAVSPerformanceRewardsSubmissionHash; | ||
Comment on lines
+92
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was there a reason we needed separate mappings for each reward type? I just copied the current setup but questioning the need for it here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's combine into one, agreed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm assuming this is used by the rewards pipeline/sidecar in some form. I don't want to break backwards compatibility if that's the case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fine since we include the nonce in the rewards submission hash. cc @8sunyuan to work There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Internally we're not using this mapping offchain There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh if it's not being used offchain, what was the purpose of this mapping? I don't see it being used anywhere else besides just setting it during reward submission. Is it meant to be used as a view function by some other contract in the future? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @8sunyuan do you remember? I can't recall off the top of my head There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It appears it may actually have no use... potentially we wanted it for some sort of future pipeline integration |
||
|
||
constructor( | ||
IDelegationManager _delegationManager, | ||
IStrategyManager _strategyManager, | ||
|
@@ -120,5 +123,5 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { | |
* variables without shifting down storage in the inheritance chain. | ||
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps | ||
*/ | ||
uint256[40] private __gap; | ||
uint256[39] private __gap; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated this since we added the mapping above. Just wanted to double confirm that this looks right. I remember seeing a PR a while back changing this to 40. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, this is correct |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,16 @@ interface IRewardsCoordinator { | |
uint96 multiplier; | ||
} | ||
|
||
/** | ||
* @notice A reward struct for an operator | ||
* @param operator The operator to be rewarded | ||
* @param amount The reward amount for the operator | ||
*/ | ||
struct OperatorReward { | ||
address operator; | ||
uint256 amount; | ||
} | ||
|
||
/** | ||
* Sliding Window for valid RewardsSubmission startTimestamp | ||
* | ||
|
@@ -60,6 +70,42 @@ interface IRewardsCoordinator { | |
uint32 duration; | ||
} | ||
|
||
/** | ||
* Sliding Window for valid RewardsSubmission startTimestamp | ||
* | ||
* Scenario A: GENESIS_REWARDS_TIMESTAMP IS WITHIN RANGE | ||
* <--------MAX_RETROACTIVE_LENGTH--------> t (block.timestamp) | ||
* <--valid range for startTimestamp-- | ||
* ^ | ||
* GENESIS_REWARDS_TIMESTAMP | ||
* | ||
* | ||
* Scenario B: GENESIS_REWARDS_TIMESTAMP IS OUT OF RANGE | ||
* <--------MAX_RETROACTIVE_LENGTH--------> t (block.timestamp) | ||
* <----valid range for startTimestamp---- | ||
* ^ | ||
* GENESIS_REWARDS_TIMESTAMP | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the performance based rewards it's not possible to submit a reward that starts at |
||
* | ||
* @notice PerformanceRewardsSubmission struct submitted by AVSs when making performance-based rewards for their operators and stakers | ||
* PerformanceRewardsSubmission can be for a time range within the valid window for startTimestamp and must be within max duration. | ||
* See `createAVSPerformanceRewardsSubmission()` for more details. | ||
* @param strategiesAndMultipliers The strategies and their relative weights | ||
* cannot have duplicate strategies and need to be sorted in ascending address order | ||
* @param token The rewards token to be distributed. | ||
* @param operatorRewards The rewards for the operators. The sum of all operator rewards equals the total amount of tokens deposited in the submission. | ||
* The operators cannot have duplicate addresses and need to be sorted in ascending address order. | ||
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution | ||
* It is a retroactive payment and has to be strictly less than `block.timestamp`. See the diagram above. | ||
* @param duration The duration of the submission range in seconds. Must be <= MAX_REWARDS_DURATION. | ||
*/ | ||
struct PerformanceRewardsSubmission { | ||
StrategyAndMultiplier[] strategiesAndMultipliers; | ||
IERC20 token; | ||
OperatorReward[] operatorRewards; | ||
uint32 startTimestamp; | ||
uint32 duration; | ||
} | ||
|
||
/** | ||
* @notice A distribution root is a merkle root of the distribution of earnings for a given period. | ||
* The RewardsCoordinator stores all historical distribution roots so that earners can claim their earnings against older roots | ||
|
@@ -150,10 +196,19 @@ interface IRewardsCoordinator { | |
bytes32 indexed rewardsSubmissionHash, | ||
RewardsSubmission rewardsSubmission | ||
); | ||
/// @notice emitted when an AVS creates a valid PerformanceRewardsSubmission | ||
event AVSPerformanceRewardsSubmissionCreated( | ||
address indexed avs, | ||
uint256 indexed submissionNonce, | ||
bytes32 indexed performanceRewardsSubmissionHash, | ||
PerformanceRewardsSubmission performanceRewardsSubmission | ||
); | ||
/// @notice rewardsUpdater is responsible for submiting DistributionRoots, only owner can set rewardsUpdater | ||
event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater); | ||
event RewardsForAllSubmitterSet( | ||
address indexed rewardsForAllSubmitter, bool indexed oldValue, bool indexed newValue | ||
address indexed rewardsForAllSubmitter, | ||
bool indexed oldValue, | ||
bool indexed newValue | ||
); | ||
event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay); | ||
event GlobalCommissionBipsSet(uint16 oldGlobalCommissionBips, uint16 newGlobalCommissionBips); | ||
|
@@ -284,6 +339,22 @@ interface IRewardsCoordinator { | |
*/ | ||
function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) external; | ||
|
||
/** | ||
* @notice Creates a new performance-based rewards submission on behalf of an AVS, to be split amongst the operators and | ||
* set of stakers delegated to operators who are registered to the `avs`. | ||
* @param performanceRewardsSubmissions The performance rewards submissions being created | ||
* @dev Expected to be called by the ServiceManager of the AVS on behalf of which the submission is being made | ||
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION` | ||
* @dev The tokens are sent to the `RewardsCoordinator` contract | ||
* @dev The `RewardsCoordinator` contract needs a token approval of sum of all `operatorRewards` in the `performanceRewardsSubmissions`, before calling this function. | ||
* @dev Strategies must be in ascending order of addresses to check for duplicates | ||
* @dev Operators must be in ascending order of addresses to check for duplicates. | ||
* @dev This function will revert if the `performanceRewardsSubmissions` is malformed. | ||
*/ | ||
function createAVSPerformanceRewardsSubmission( | ||
PerformanceRewardsSubmission[] calldata performanceRewardsSubmissions | ||
) external; | ||
|
||
/** | ||
* @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]). | ||
* Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix this. Something happened while rebasing.