Skip to content
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

staking rewards to any #647

Merged
merged 10 commits into from
Nov 21, 2024
Merged

staking rewards to any #647

merged 10 commits into from
Nov 21, 2024

Conversation

richardpringle
Copy link
Contributor

@richardpringle richardpringle commented Nov 15, 2024

Why this should be merged

Closes #555

How this works

I use another mapping to set the reward-recipient.

TODO: I should probably add another method that allows the validator to change the recipient before completeEndValidation is called.

How this was tested

Unit tests
TODO: test delegator reward

How is this documented

TODO

Copy link
Contributor

@geoff-vball geoff-vball left a comment

Choose a reason for hiding this comment

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

This is looking good! When I had originally envisioned this, I was thinking of an external function that just lets the owner of a validation/delegation change their rewards address, which would obviate the need for passing around the address in the initialize functions. I think your way works just as well, except if the staker wants to change the reward address in between the initialize and complete steps. Having the rewards address change in a separate step would also let the caller verify the address is correctly set before calling to disburse the rewards.

We could also set rewardRecipient = owner when starting a staking period, which would prevent us from having to check if the address is 0 later.

@richardpringle
Copy link
Contributor Author

This is looking good! When I had originally envisioned this, I was thinking of an external function that just lets the owner of a validation/delegation change their rewards address, which would obviate the need for passing around the address in the initialize functions. I think your way works just as well, except if the staker wants to change the reward address in between the initialize and complete steps. Having the rewards address change in a separate step would also let the caller verify the address is correctly set before calling to disburse the rewards.

We could also set rewardRecipient = owner when starting a staking period, which would prevent us from having to check if the address is 0 later.

I still need to add the functionality to change the reward-recipient between initialize and complete.

As for always setting the reward-recipient (defaulting to the owner), it's cheaper not to set it. I'm happy to do things either way though. It's one of those things where we save the extra storage where it isn't necessary or we make the cost consistent (no matter where you withdraw the reward)

@richardpringle richardpringle force-pushed the staking-rewards-to-any branch 4 times, most recently from 79a1984 to 0380f82 Compare November 18, 2024 23:14
@richardpringle
Copy link
Contributor Author

I think all that's left is exposing the changeRewardRecipient functions in the interface and some documentation.

@richardpringle
Copy link
Contributor Author

I think all that's left is exposing the changeRewardRecipient functions in the interface and some documentation.

Oh actually, I think I need a couple more tests. Will leave comments in the code.

@richardpringle richardpringle force-pushed the staking-rewards-to-any branch 3 times, most recently from ca5f8e0 to c290490 Compare November 19, 2024 17:59
@richardpringle richardpringle marked this pull request as ready for review November 20, 2024 22:33
@richardpringle richardpringle requested a review from a team as a code owner November 20, 2024 22:33
Copy link
Contributor

@iansuvak iansuvak left a comment

Choose a reason for hiding this comment

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

Looks good to me overall! Just a couple of minor questions and a method name typo.

contracts/validator-manager/PoSValidatorManager.sol Outdated Show resolved Hide resolved
contracts/validator-manager/PoSValidatorManager.sol Outdated Show resolved Hide resolved
tests/utils/validator_manager.go Show resolved Hide resolved
Comment on lines +803 to +805
if (rewardRecipient != address(0)) {
$._delegatorRewardRecipients[delegationID] = rewardRecipient;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it maybe make sense to set this in initializeEndDelegation, so that we don't have to pass the parameter down another level?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I actually just changed this because of this comment.

Is there a problem passing this down? More expensive? I can revert my change, but this definitely is cleaner (ignoring gas cost)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah no, this is good :)

revert InvalidRewardRecipient(rewardRecipient);
}

PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();
Copy link
Contributor

Choose a reason for hiding this comment

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

Idiomatically we always place this at the top of the function before any checks. If a call reverts, it uses all the gas anyway, so there are no potential savings.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What if the address is 0, though?

Copy link
Contributor

Choose a reason for hiding this comment

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

Either ordering gives exactly the same effects in all cases, since reverted transactions cause all gas to be use, and any side-effects are not saved. Happy to explain more if that doesn't explain it fully

Comment on lines +303 to +317
if (rewardRecipient == address(0)) {
revert InvalidRewardRecipient(rewardRecipient);
}

PoSValidatorManagerStorage storage $ = _getPoSValidatorManagerStorage();

if ($._delegatorStakes[delegationID].owner != _msgSender()) {
revert UnauthorizedOwner(_msgSender());
}

if (rewardRecipient == _msgSender()) {
delete $._delegatorRewardRecipients[delegationID];
} else {
$._delegatorRewardRecipients[delegationID] = rewardRecipient;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be worth encapsulating this logic in a private function and having the external func call the private func. Then we could call the private func from initializeEndDelegation. Then we wouldn't have the different logical handling that I mentioned in another comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See this response. TL;DR I think I could clean that up in a follow up, but I think this works and solves the problem, can we land this PR before it diverges any further from main?

@bernard-avalabs
Copy link
Contributor

As for always setting the reward-recipient (defaulting to the owner), it's cheaper not to set it. I'm happy to do things either way though. It's one of those things where we save the extra storage where it isn't necessary or we make the cost consistent (no matter where you withdraw the reward)

My personal preference is to set the reward-recipient to the owner by default. It is a bit less error prone since we won't need to special case the 0 address. I imagine the storage cost is pretty small.

Copy link
Contributor

@bernard-avalabs bernard-avalabs left a comment

Choose a reason for hiding this comment

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

Generally looks good to me. I left a comment about preferring to set the owner as the default reward recipient, but I'm fine either way.

@richardpringle richardpringle force-pushed the staking-rewards-to-any branch 2 times, most recently from 90cc2a6 to a388dc1 Compare November 21, 2024 19:58
@richardpringle
Copy link
Contributor Author

As for always setting the reward-recipient (defaulting to the owner), it's cheaper not to set it. I'm happy to do things either way though. It's one of those things where we save the extra storage where it isn't necessary or we make the cost consistent (no matter where you withdraw the reward)

My personal preference is to set the reward-recipient to the owner by default. It is a bit less error prone since we won't need to special case the 0 address. I imagine the storage cost is pretty small.

🤔 I actually agree, I think that's the cleaner solution. However... this works, so I think it would make sense to do in a follow up (locking in the tests and everything now).

Thoughts @geoff-vball and @bernard-avalabs?

@richardpringle richardpringle merged commit aec3442 into main Nov 21, 2024
17 checks passed
@richardpringle richardpringle deleted the staking-rewards-to-any branch November 21, 2024 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Allow stakers to specify a different rewards address
4 participants