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

Prorated validation rewards #603

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
store uptime since validation start
  • Loading branch information
cam-schultz committed Oct 16, 2024
commit ec8b480cea1be83c61d10ab5132c0b5a1db67699
2 changes: 1 addition & 1 deletion contracts/validator-manager/PoSValidatorManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ abstract contract PoSValidatorManager is
});

$._posValidatorInfo[validationID].lastClaimMinUptime =
(claimTime - lastClaimTime) * UPTIME_REWARDS_THRESHOLD_PERCENTAGE / 100;
(claimTime - validator.startedAt) * UPTIME_REWARDS_THRESHOLD_PERCENTAGE / 100;
Copy link
Contributor

Choose a reason for hiding this comment

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

I understand that we want to "consume" from the totalUptime only what is needed to claim the reward. This allows the next claim to be more forgiving. However, it is now possible for claimTime - lastClaimTime to be less than totalUptime - lastClaimMinUptime in the next claim (i.e., an uptime that is longer than the claim period). This is not a problem, but seems like it is breaking an invariant at first glance. It may be worth documenting this.

$._posValidatorInfo[validationID].lastClaimTime = claimTime;
_reward($._posValidatorInfo[validationID].owner, reward);

Expand Down
38 changes: 26 additions & 12 deletions contracts/validator-manager/tests/PoSValidatorManagerTests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
bytes memory uptimeMsg = ValidatorMessages.packValidationUptimeMessage(
validationID, (firstClaimTime - DEFAULT_REGISTRATION_TIMESTAMP) * uptimePercentage / 100
);
uint256 expectedReward = _claimRewards({
uint256 firstExpectedReward = _claimRewards({
validationID: validationID,
uptimeMsg: uptimeMsg,
validationStartTime: DEFAULT_REGISTRATION_TIMESTAMP,
Expand All @@ -1205,8 +1205,22 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
success: true
});

// Try to end the validation with a stale uptime
// Claim rewards again
uint64 secondClaimTime = firstClaimTime + 5 hours;
uptimeMsg = ValidatorMessages.packValidationUptimeMessage(
validationID, (secondClaimTime - DEFAULT_REGISTRATION_TIMESTAMP) * uptimePercentage / 100
);
uint256 secondExpectedReward = _claimRewards({
validationID: validationID,
uptimeMsg: uptimeMsg,
validationStartTime: DEFAULT_REGISTRATION_TIMESTAMP,
claimTime: secondClaimTime,
lastClaimTime: firstClaimTime,
success: true
});

// Try to end the validation with a stale uptime
uint64 thirdClaimTime = secondClaimTime + 5 hours;
vm.expectRevert(
abi.encodeWithSelector(
PoSValidatorManager.ValidatorIneligibleForRewards.selector, validationID
Expand All @@ -1215,7 +1229,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
_initializeEndValidation({
validationID: validationID,
registrationTimestamp: DEFAULT_REGISTRATION_TIMESTAMP,
completionTimestamp: secondClaimTime,
completionTimestamp: thirdClaimTime,
expectedNonce: 1,
includeUptime: false,
force: false
Expand All @@ -1225,17 +1239,17 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
_initializeEndValidation({
validationID: validationID,
registrationTimestamp: DEFAULT_REGISTRATION_TIMESTAMP,
completionTimestamp: secondClaimTime,
completionTimestamp: thirdClaimTime,
expectedNonce: 1,
includeUptime: true,
force: false
});

uint256 secondExpectedReward = rewardCalculator.calculateReward({
uint256 thirdExpectedReward = rewardCalculator.calculateReward({
stakeAmount: _weightToValue(DEFAULT_WEIGHT),
validatorStartTime: 0,
stakingStartTime: firstClaimTime,
stakingEndTime: secondClaimTime,
stakingStartTime: secondClaimTime,
stakingEndTime: thirdClaimTime,
uptimeSeconds: 0,
initialSupply: 0,
endSupply: 0
Expand All @@ -1244,7 +1258,7 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
_completeEndValidationWithChecks({
validationID: validationID,
validatorOwner: address(this),
expectedReward: secondExpectedReward,
expectedReward: thirdExpectedReward,
validatorWeight: DEFAULT_WEIGHT
});

Expand All @@ -1253,16 +1267,16 @@ abstract contract PoSValidatorManagerTest is ValidatorManagerTest {
stakeAmount: _weightToValue(DEFAULT_WEIGHT),
validatorStartTime: 0,
stakingStartTime: DEFAULT_REGISTRATION_TIMESTAMP,
stakingEndTime: secondClaimTime,
stakingEndTime: thirdClaimTime,
uptimeSeconds: 0,
initialSupply: 0,
endSupply: 0
});
// Off-by one errors are possible due to integer rounding
if (totalExpectedReward > expectedReward + secondExpectedReward) {
assertTrue(totalExpectedReward - (expectedReward + secondExpectedReward) <= 1);
if (totalExpectedReward > firstExpectedReward + secondExpectedReward + thirdExpectedReward) {
assertTrue(totalExpectedReward - (firstExpectedReward + secondExpectedReward + thirdExpectedReward) <= 1);
} else {
assertTrue((expectedReward + secondExpectedReward) - totalExpectedReward <= 1);
assertTrue((firstExpectedReward + secondExpectedReward + thirdExpectedReward) - totalExpectedReward <= 1);
}
}

Expand Down