-
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
Conversation
3832b9d
to
72cf05e
Compare
lib/forge-std
Outdated
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.
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.
This file was touched since dev
wasn't compiling and I manually made it _verifyContractsInitialized(false);
. But now I need to figure out what's up with my linting. Either these existing files haven't been linted using prettier or we're currently not using forge fmt (My IDE is auto linting them on save).
function createAVSRewardsSubmission( | ||
RewardsSubmission[] calldata rewardsSubmissions | ||
) external onlyWhenNotPaused(PAUSED_AVS_REWARDS_SUBMISSION) nonReentrant { |
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.
This was changed due to auto linting.
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.
Multiple other auto-linting instances in this PR.
* @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 comment
The reason will be displayed to describe this comment to others. Learn more.
Not checking for MAX_FUTURE_LENGTH
(Since Performance based reward submissions are retroactive) or MAX_REWARDS_AMOUNT
(Since we no longer have the 1e38 - 1
limitation in the offchain calculation.
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.
could u add this in code comments?
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.
Done in 179aa1f as a @dev
natspec.
/// @notice Mapping: avs => avsPerformanceRewardsSubmissionHash => bool to check if performance rewards submission hash has been submitted | ||
mapping(address => mapping(bytes32 => bool)) public isAVSPerformanceRewardsSubmissionHash; |
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.
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 comment
The 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 comment
The 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 comment
The 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 comment
The 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 comment
The 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 comment
The 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 comment
The 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 comment
The 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
@@ -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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, this is correct
function processClaims( | ||
RewardsMerkleClaim[] calldata claims, | ||
address recipient |
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.
We could also claim for multiple recipients instead of claiming to a single recipient. Thoughts?
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.
single recipient seems fine
* @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 comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on using revert
with custom errors? Or just custom errors in general instead of error strings? I kept it similar to the current setup but using custom errors will be more gas efficient.
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.
let's do that with slashing like we are on #727
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.
Alright holding off on custom errors for now.
|
||
uint256 totalAmount = _validatePerformanceRewardsSubmission(performanceRewardsSubmission); | ||
|
||
isAVSPerformanceRewardsSubmissionHash[msg.sender][performanceRewardsSubmissionHash] = true; |
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.
do we need to check that it already exists
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
ah, sounds good
currOperatorAddress < operatorReward.operator, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: operators must be in ascending order to handle duplicates" |
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.
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 comment
The 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 comment
The 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 comment
The 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.
require( | ||
strategyManager.strategyIsWhitelistedForDeposit(strategy) || strategy == beaconChainETHStrategy, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: invalid strategy considered" | ||
); |
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.
does this propertly support longtail assets?
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.
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 comment
The 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( | ||
operatorReward.amount > 0, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: operator reward amount cannot be 0" | ||
); |
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.
What are the gas costs for 200,500,1000 operators?
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
The latter
* <--------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 comment
The reason will be displayed to describe this comment to others. Learn more.
GENESIS_REWARDS_TIMESTAMP
is never in range?
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.
What do you mean?
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.
For the performance based rewards it's not possible to submit a reward that starts at GENESIS_REWARDS_TIMESTAMP
(ie. scenario B)
require( | ||
strategyManager.strategyIsWhitelistedForDeposit(strategy) || strategy == beaconChainETHStrategy, | ||
"RewardsCoordinator._validatePerformanceRewardsSubmission: invalid strategy considered" | ||
); |
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.
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
@@ -57,7 +57,7 @@ abstract contract RewardsCoordinatorStorage is IRewardsCoordinator { | |||
*/ | |||
DistributionRoot[] internal _distributionRoots; | |||
|
|||
/// Slot 3 | |||
/// Slot 2 |
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.
Updated the comment here. It is in fact Slot 2 since we start from Slot 0 (rather than Slot 1)
Motivation
As part of the Rewards v2 release, we need to support the following features:
Modifications
IRewardsCoordinator
:PerformanceRewardsSubmission
struct added.OperatorReward
struct added.AVSPerformanceRewardsSubmissionCreated
event added.createAVSPerformanceRewardsSubmission
external function added.processClaims
external function added.OperatorAVSCommission
struct added.OperatorAVSCommissionBipsSet
event added.setOperatorAVSCommission
external function added.RewardsCoordinator
:PAUSED_AVS_PERFORMANCE_REWARDS_SUBMISSION
constant added,createAVSPerformanceRewardsSubmission
external function added._validatePerformanceRewardsSubmission
internal function added.processClaims
external function added._processClaim
internal function added.processClaim
external function was refactored to use_processClaim
setOperatorAVSCommission
external function added.RewardsCoordinatorStorage
:isAVSPerformanceRewardsSubmissionHash
nested mapping added.operatorAVSCommissionBips
nested mapping added.isAVSPerformanceRewardsSubmissionHash
andoperatorAVSCommissionBips
TODO
operatorCommissionBips
view function to have logic for operatorAVSCommission too.setOperatorAVSCommission
.setOperatorAVSCommission
.createAVSPerformanceRewardsSubmission
and related stuff to be delegation-aware and future-proofed by takingavs
as a param.Open Questions
Result
Rewards v2 release.