@@ -35,19 +35,35 @@ contract OperatorRewarder {
3535 mapping (address => int256 ) private _rewardsPaid;
3636 mapping (address => address ) private _authorizedClaimers;
3737
38- /// @notice Emitted when the beneficiary is transferred.
38+ /**
39+ * @notice Emitted when the beneficiary is transferred.
40+ * @param oldBeneficiary The previous beneficiary address.
41+ * @param newBeneficiary The new beneficiary address.
42+ */
3943 event BeneficiaryTransferred (address oldBeneficiary , address newBeneficiary );
4044
4145 /// @notice Emitted when the contract is shut down.
4246 event Shutdown ();
4347
44- /// @notice Emitted when the maximum fee is updated.
48+ /**
49+ * @notice Emitted when the maximum fee is updated.
50+ * @param oldFee The previous maximum fee in basis points.
51+ * @param newFee The new maximum fee in basis points.
52+ */
4553 event MaxFeeUpdated (uint16 oldFee , uint16 newFee );
4654
47- /// @notice Emitted when the fee is updated.
55+ /**
56+ * @notice Emitted when the fee is updated.
57+ * @param oldFee The previous fee in basis points.
58+ * @param newFee The new fee in basis points.
59+ */
4860 event FeeUpdated (uint16 oldFee , uint16 newFee );
4961
50- /// @notice Emitted when an address is authorized to claim rewards on behalf of the receiver address.
62+ /**
63+ * @notice Emitted when an address is authorized to claim rewards on behalf of the receiver address.
64+ * @param receiver The address that will receive the rewards.
65+ * @param claimer The address authorized to claim rewards on behalf of the receiver.
66+ */
5167 event ClaimerAuthorized (address receiver , address claimer );
5268
5369 /// @notice Error for invalid claimer address.
@@ -326,19 +342,34 @@ contract OperatorRewarder {
326342 return SafeCast.toUint256 (SignedMath.max (0 , allocation - _rewardsPaid[account]));
327343 }
328344
345+ /**
346+ * @notice Returns the total historical rewards distributed.
347+ * @dev This amount is computed as the sum of:
348+ * - the total rewards accumulated in the contract (see `_totalAssetsPlusPaidRewards()`) from
349+ * the start of the contract
350+ * - minus the fees not yet claimed by the beneficiary (see `_unpaidFee()`)
351+ * @return The total historical rewards amount.
352+ */
329353 function historicalReward () public view virtual returns (uint256 ) {
330354 uint256 totalAssetsPlusPaidRewards = _totalAssetsPlusPaidRewards ();
331355 return totalAssetsPlusPaidRewards - _unpaidFee (totalAssetsPlusPaidRewards);
332356 }
333357
334358 /**
335- * @notice Returns unpaid fee.
359+ * @notice Returns unpaid fee (not yet claimed by the beneficiary) .
336360 * @return Amount of unpaid fee.
337361 */
338362 function unpaidFee () public view virtual returns (uint256 ) {
339363 return _unpaidFee (_totalAssetsPlusPaidRewards ());
340364 }
341365
366+ /**
367+ * @notice Transfers the specified amount of tokens to the specified address.
368+ * @dev If the amount to transfer is greater than the balance of the rewarder, it will first
369+ * claim rewards from the ProtocolStaking contract.
370+ * @param to The address to transfer the tokens to.
371+ * @param amount The amount of tokens to transfer.
372+ */
342373 function _doTransferOut (address to , uint256 amount ) internal {
343374 IERC20 token_ = token ();
344375 if (amount > token_.balanceOf (address (this ))) {
@@ -370,7 +401,12 @@ contract OperatorRewarder {
370401 function _claimFee () internal virtual {
371402 uint256 totalAssetsPlusPaidRewards = _totalAssetsPlusPaidRewards ();
372403 uint256 unpaidFee_ = _unpaidFee (totalAssetsPlusPaidRewards);
404+
405+ // Update the last claim value used to define the next unpaid fee (see `_unpaidFee()`).
406+ // This amount is exactly the same as `historicalReward()`, but we need to get the unpaid
407+ // fee separately in order to send the fee to the beneficiary below.
373408 _lastClaimTotalAssetsPlusPaidRewards = totalAssetsPlusPaidRewards - unpaidFee_;
409+
374410 if (unpaidFee_ > 0 ) {
375411 _doTransferOut (beneficiary (), unpaidFee_);
376412 }
@@ -410,19 +446,52 @@ contract OperatorRewarder {
410446 _feeBasisPoints = basisPoints;
411447 }
412448
449+ /**
450+ * @notice Returns the total assets plus earned rewards plus paid rewards.
451+ * @dev This amount is computed as the sum of:
452+ * - the balance of the rewarder contract (includes: total claimed but unpaid rewards + total donation + unpaid fees)
453+ * - the earned rewards by the operator staking contract (total earned but unpaid rewards)
454+ * - the total rewards paid to the delegators (total paid rewards)
455+ * @return Total assets plus earned rewards plus paid rewards.
456+ */
413457 function _totalAssetsPlusPaidRewards () internal view returns (uint256 ) {
414458 return
415459 token ().balanceOf (address (this )) +
416460 (isShutdown () ? 0 : protocolStaking ().earned (address (operatorStaking ()))) +
417461 _totalRewardsPaid;
418462 }
419463
464+ /**
465+ * @notice Returns the unpaid fee.
466+ * @dev This amount is computed as a percentage (defined in basis points) of the amount of rewards
467+ * accumulated since the last time fees were claimed. This works because:
468+ * - claiming fees snapshots the historical rewards amount in the `_lastClaimTotalAssetsPlusPaidRewards`
469+ * value, which monitors all rewards accumulated since the start of the contract by excluding fees.
470+ * - the total rewards amount (`_totalAssetsPlusPaidRewards()`) is computed such as it is always
471+ * increasing, except when fees are claimed (where fees are transferred to the beneficiary).
472+ * This makes sure that the difference between both above values does not take claimed fees
473+ * into account when computing the next unpaid fees.
474+ * @param totalAssetsPlusPaidRewards The total assets plus earned rewards plus paid rewards.
475+ * @return Amount of unpaid fee.
476+ */
420477 function _unpaidFee (uint256 totalAssetsPlusPaidRewards ) internal view returns (uint256 ) {
421478 uint256 totalAssetsPlusPaidRewardsDelta = totalAssetsPlusPaidRewards - _lastClaimTotalAssetsPlusPaidRewards;
422479 return (totalAssetsPlusPaidRewardsDelta * feeBasisPoints ()) / 10_000 ;
423480 }
424481
425- /// @dev Compute total allocation based on number of shares and total shares. Must take paid rewards into account after.
482+ /**
483+ * @notice Compute total allocation based on number of shares and total shares.
484+ * @param share The number of shares.
485+ * @param total The total number of shares.
486+ * @return The total allocation.
487+ * The allocation corresponds to the rewards (both real and virtual) a user would receive if
488+ * the current weight distribution, with their updated stake, was constant since the deployment
489+ * of the protocol.
490+ * Total reward amount is computed as the sum of:
491+ * - historical rewards: total of all rewards generated up to that point
492+ * - paid virtual rewards: a pool of "virtual" rewards that account for changes in the weight distribution
493+ * Note: the `mulDiv` rounds down: floor(totalRewards * share / total)
494+ */
426495 function _allocation (uint256 share , uint256 total ) private view returns (uint256 ) {
427496 return
428497 SafeCast.toUint256 (SafeCast.toInt256 (historicalReward ()) + _totalVirtualRewardsPaid).mulDiv (share, total);
0 commit comments