Skip to content

Commit

Permalink
fix: formula to compute cl rewards (#191)
Browse files Browse the repository at this point in the history
* fix: formula to compute cl rewards

* fix: formatting

* feat: update error values

* fix: remove TODO and use lastReport

* feat: rename internal var

* feat: add small comment about balance comparisons
  • Loading branch information
mortimr authored Mar 15, 2023
1 parent 4877cd8 commit 3a23e60
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 19 deletions.
42 changes: 29 additions & 13 deletions contracts/src/components/OracleManager.1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import "../state/river/LastOracleRoundId.sol";
/// @notice validators that have been activated on the consensus layer.
abstract contract OracleManagerV1 is IOracleManagerV1 {
uint256 internal constant ONE_YEAR = 365 days;
/// @notice Size of a deposit in ETH
uint256 public constant _DEPOSIT_SIZE = 32 ether;

/// @notice Handler called if the delta between the last and new validator balance sum is positive
/// @dev Must be overridden
Expand Down Expand Up @@ -305,9 +307,19 @@ abstract contract OracleManagerV1 is IOracleManagerV1 {
vars.timeElapsedSinceLastReport = _timeBetweenEpochs(cls, lastStoredReport.epoch, report.epoch);
}

IOracleManagerV1.StoredConsensusLayerReport storage lastReport = LastConsensusLayerReport.get();

// we retrieve the current total underlying balance before any reporting data is applied to the system
vars.preReportUnderlyingBalance = _assetBalance();
// we compute the time elapsed since last report based on epoch numbers
uint256 preUnderlyingBalanceIncludingExits =
lastReport.validatorsBalance + lastReport.validatorsSkimmedBalance + lastReport.validatorsExitedBalance;
{
uint256 lastReportValidatorsCount = lastReport.validatorsCount;
if (lastReportValidatorsCount < report.validatorsCount) {
preUnderlyingBalanceIncludingExits +=
(report.validatorsCount - lastReportValidatorsCount) * _DEPOSIT_SIZE;
}
}

// if we have new exited / skimmed eth available, we pull funds from the consensus layer recipient
if (vars.exitedAmountIncrease + vars.skimmedAmountIncrease > 0) {
Expand Down Expand Up @@ -338,22 +350,26 @@ abstract contract OracleManagerV1 is IOracleManagerV1 {

// we retrieve the new total underlying balance after system parameters are changed
vars.postReportUnderlyingBalance = _assetBalance();

// if the new underlying balance has increased, we verify that we are not exceeding reporting bound, and we update
// reporting variables accordingly
if (vars.postReportUnderlyingBalance >= vars.preReportUnderlyingBalance) {
uint256 postUnderlyingBalanceIncludingExits =
report.validatorsBalance + report.validatorsSkimmedBalance + report.validatorsExitedBalance;

// we can now compute the earned rewards from the consensus layer balances
// in order to properly account for the balance increase, we compare the sums of current balances, skimmed balance and exited balances
// we also synthetically increase the current balance by 32 eth per new activated validator, this way we have no discrepency due
// to currently activating funds that were not yet accounted in the consensus layer balances
if (postUnderlyingBalanceIncludingExits >= preUnderlyingBalanceIncludingExits) {
// if this happens, we revert and the reporting process is cancelled
if (vars.postReportUnderlyingBalance > vars.preReportUnderlyingBalance + maxIncrease) {
if (postUnderlyingBalanceIncludingExits > preUnderlyingBalanceIncludingExits + maxIncrease) {
revert TotalValidatorBalanceIncreaseOutOfBound(
vars.preReportUnderlyingBalance,
vars.postReportUnderlyingBalance,
preUnderlyingBalanceIncludingExits,
postUnderlyingBalanceIncludingExits,
vars.timeElapsedSinceLastReport,
rb.annualAprUpperBound
);
}

// we update the rewards based on the balance delta
vars.trace.rewards = (vars.postReportUnderlyingBalance - vars.preReportUnderlyingBalance);
vars.trace.rewards = postUnderlyingBalanceIncludingExits - preUnderlyingBalanceIncludingExits;

// we update the available amount to upper bound (the amount of eth we can still pull and stay below the upper reporting bound)
vars.availableAmountToUpperBound = maxIncrease - vars.trace.rewards;
Expand All @@ -364,18 +380,18 @@ abstract contract OracleManagerV1 is IOracleManagerV1 {
uint256 maxDecrease = _maxDecrease(rb, vars.preReportUnderlyingBalance);

// we verify that the bound is not crossed
if (vars.postReportUnderlyingBalance < vars.preReportUnderlyingBalance - maxDecrease) {
if (postUnderlyingBalanceIncludingExits < preUnderlyingBalanceIncludingExits - maxDecrease) {
revert TotalValidatorBalanceDecreaseOutOfBound(
vars.preReportUnderlyingBalance,
vars.postReportUnderlyingBalance,
preUnderlyingBalanceIncludingExits,
postUnderlyingBalanceIncludingExits,
vars.timeElapsedSinceLastReport,
rb.relativeLowerBound
);
}

// we update the available amount to upper bound to be equal to the maximum allowed increase plus the negative delta due to the loss
vars.availableAmountToUpperBound =
maxIncrease + (vars.preReportUnderlyingBalance - vars.postReportUnderlyingBalance);
maxIncrease + (preUnderlyingBalanceIncludingExits - postUnderlyingBalanceIncludingExits);
}

// if we have available amount to upper bound after the reporting values are applied
Expand Down
18 changes: 12 additions & 6 deletions contracts/src/interfaces/components/IOracleManager.1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,27 @@ interface IOracleManagerV1 {
error InvalidEpoch(uint256 epoch);

/// @notice The balance increase is higher than the maximum allowed by the upper bound
/// @param prevTotalEth The previous total balance
/// @param postTotalEth The post-report total balance
/// @param prevTotalEthIncludingExited The previous total balance, including all exited balance
/// @param postTotalEthIncludingExited The post-report total balance, including all exited balance
/// @param timeElapsed The time in seconds since last report
/// @param annualAprUpperBound The upper bound value that was used
error TotalValidatorBalanceIncreaseOutOfBound(
uint256 prevTotalEth, uint256 postTotalEth, uint256 timeElapsed, uint256 annualAprUpperBound
uint256 prevTotalEthIncludingExited,
uint256 postTotalEthIncludingExited,
uint256 timeElapsed,
uint256 annualAprUpperBound
);

/// @notice The balance decrease is higher than the maximum allowed by the lower bound
/// @param prevTotalEth The previous total balance
/// @param postTotalEth The post-report total balance
/// @param prevTotalEthIncludingExited The previous total balance, including all exited balance
/// @param postTotalEthIncludingExited The post-report total balance, including all exited balance
/// @param timeElapsed The time in seconds since last report
/// @param relativeLowerBound The lower bound value that was used
error TotalValidatorBalanceDecreaseOutOfBound(
uint256 prevTotalEth, uint256 postTotalEth, uint256 timeElapsed, uint256 relativeLowerBound
uint256 prevTotalEthIncludingExited,
uint256 postTotalEthIncludingExited,
uint256 timeElapsed,
uint256 relativeLowerBound
);

/// @notice The total exited balance decreased
Expand Down

0 comments on commit 3a23e60

Please sign in to comment.