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

Implement sending of allocated validator payments #11197

Merged
merged 25 commits into from
Sep 18, 2024

Conversation

m-chrzan
Copy link
Contributor

@m-chrzan m-chrzan commented Aug 23, 2024

Description

Implements sendValidatorPayment(address validator), which sends the cUSD validator payment allocated via allocateValidatorRewards to the validator, group, and delegation beneficiary.

TODO:

  • Add ERC-20 checks
  • Double check if any other checks present in distributeEpochPaymentsFromSigner need to be carried over
    • They're covered by computeEpochReward
  • Emit an event
  • NatSpecs

Questions:

  • Seems like when we added payment delegation, we didn't add the beneficiary payment to the event emitted (presumably for backwards compatibility reasons?). Do we want to add it now (or emit an additional event with delegation payment information)?
    • As discussed with @mcortesi in comments below, we'll add delegation info.

Follow-ups:

Other changes

Changes to various mock contracts. In particular:

  • The old 0.5 MockValidators.sol should probably be unified with ValidatorsMock08.sol once Move Validators.sol to 0.8 #11192 is merged. The newly added IMockValidators.sol (necessary to use an 0.5 contract in an 0.8 test) can be removed at that point.
  • EpochManager_WithMocks.sol extends the base EpochManager contract, and is used as the main contract in EpochManager tests. It behaves like the original contract, but adds a function to manually set payment allocations for easier testing.

Tested

Forge unit tests.

Related issues

Documentation

Should add docs for validators on how to call this function to claim their payments.

@m-chrzan m-chrzan marked this pull request as ready for review August 26, 2024 20:47
@m-chrzan m-chrzan requested a review from a team as a code owner August 26, 2024 20:47
@m-chrzan m-chrzan changed the title [WIP] Implement sending of allocated validator payments Implement sending of allocated validator payments Aug 26, 2024
*/
function sendValidatorPayment(address validator) external {
IAccounts accounts = IAccounts(getAccounts());
address signer = accounts.getValidatorSigner(validator);
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we didn't want to use signers @mcortesi @martinvol

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 was basing this on how the current code works:

  • the elected array in EpochManager gets set by calling Election.electNValidatorSigners
  • That functions gets validator addresses via Validators.getTopGroupValidators
  • Which grabs the validator accounts and translates them to validator signer addresses, returning those

So in the current state, the correct way to index into elected is via signer addresses.

If we want to change this logic, we should thoroughly double check everything is returning/using the correct type of validator address. As mentioned on Slack, a similar issue exists with the current use of Validators.computeEpochReward, which expects a validator account, but gets a signer address (generated by the election). I would suggest this be done in a follow-up issue/PR that covers all instances of this.

In general I agree, we can probably just use account addresses everywhere. If I understand correctly, the only reason we used signer addresses in some places was because that's what celo-blockchain cared about in the PoS logic.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, we don't want signeers. EpochManager will have a list of elected account (not signers) and we should change elections to not give signers, i believe we even have a draft methos doing that...

the client didn't care about account, only about signers and so it sent signers everywhere, but that's unnecessary complexity now

Copy link
Contributor

Choose a reason for hiding this comment

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

Created an issue to track progress on this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mcortesi, sounds great, that's how I understood things.

As mentioned, I would merge this PR as is, so it's consistent with the current state of the logic, and remove signers in the PR that will fix @soloseng's issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

PR making the changes.


IStableToken stableToken = IStableToken(getStableToken());

require(stableToken.transfer(validator, validatorPayment), "mint failed to validator");
Copy link
Contributor

Choose a reason for hiding this comment

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

not mint but transfer. Can transfer fail?

Copy link
Contributor

Choose a reason for hiding this comment

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

is validatorPayment always > 0?

Copy link
Contributor Author

@m-chrzan m-chrzan Aug 30, 2024

Choose a reason for hiding this comment

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

Can transfer fail?

If the contract doesn't have enough balance for example. Ideally that should never happen though, if our allocation and minting logic is correct. Auditors in the past have asked to always check return values of e.g. ERC-20 functions that return a success bool, as good practice.

is validatorPayment always > 0?

I guess it could be 0, if delegation and/or commission take up the whole payment. I can add an if(non-zero) around this as well. That said, transfers of 0 do not fail, as evidenced by the test_doesNothingIfNotAllocated test not reverting.

require(stableToken.transfer(beneficiary, delegatedPayment), "mint failed to delegatee");
}

emit ValidatorEpochPaymentDistributed(validator, validatorPayment, group, groupPayment);
Copy link
Contributor

Choose a reason for hiding this comment

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

this looks broken, even in Validators.sol. We record validator and group payments but not delegatee. Since this is a new event on a new contract, we should correct that


require(stableToken.transfer(validator, validatorPayment), "mint failed to validator");
if (groupPayment > 0) {
require(stableToken.transfer(group, groupPayment), "mint failed to validator group");
Copy link
Contributor

Choose a reason for hiding this comment

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

not mint but transfer

require(stableToken.transfer(group, groupPayment), "mint failed to validator group");
}
if (delegatedPayment > 0) {
require(stableToken.transfer(beneficiary, delegatedPayment), "mint failed to delegatee");
Copy link
Contributor

Choose a reason for hiding this comment

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

not mint but transfer

Copy link
Contributor

@soloseng soloseng left a comment

Choose a reason for hiding this comment

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

🚀

FixidityLib.Fraction memory remainingPayment = FixidityLib.newFixed(
totalPayment.fromFixed() - groupPayment
);
(address beneficiary, uint256 fraction) = getAccounts().getPaymentDelegation(validator);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
(address beneficiary, uint256 fraction) = getAccounts().getPaymentDelegation(validator);
(address beneficiary, uint256 delegationFraction) = getAccounts().getPaymentDelegation(validator);

So it is more clear what does it stand for ?

@martinvol martinvol merged commit 59ea380 into feat/l2-epoch-system Sep 18, 2024
21 checks passed
@martinvol martinvol deleted the m-chrzan/send-validator-payment branch September 18, 2024 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants