Skip to content

Commit 47f1232

Browse files
authored
fix: rewards v2 audit fixes (#987)
* fix: default operator split during first initialization * test: updated split tests
1 parent 1908cc9 commit 47f1232

File tree

2 files changed

+42
-11
lines changed

2 files changed

+42
-11
lines changed

src/contracts/core/RewardsCoordinator.sol

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,6 @@ contract RewardsCoordinator is
301301
uint16 split
302302
) external onlyWhenNotPaused(PAUSED_OPERATOR_AVS_SPLIT) {
303303
require(msg.sender == operator, "RewardsCoordinator.setOperatorAVSSplit: caller is not the operator");
304-
require(split <= ONE_HUNDRED_IN_BIPS, "RewardsCoordinator.setOperatorAVSSplit: split must be <= 10000 bips");
305304

306305
uint32 activatedAt = uint32(block.timestamp) + activationDelay;
307306
uint16 oldSplit = _getOperatorSplit(operatorAVSSplitBips[operator][avs]);
@@ -313,7 +312,6 @@ contract RewardsCoordinator is
313312
/// @inheritdoc IRewardsCoordinator
314313
function setOperatorPISplit(address operator, uint16 split) external onlyWhenNotPaused(PAUSED_OPERATOR_PI_SPLIT) {
315314
require(msg.sender == operator, "RewardsCoordinator.setOperatorPISplit: caller is not the operator");
316-
require(split <= ONE_HUNDRED_IN_BIPS, "RewardsCoordinator.setOperatorPISplit: split must be <= 10000 bips");
317315

318316
uint32 activatedAt = uint32(block.timestamp) + activationDelay;
319317
uint16 oldSplit = _getOperatorSplit(operatorPISplitBips[operator]);
@@ -395,13 +393,14 @@ contract RewardsCoordinator is
395393
* @param activatedAt The timestamp when the split is activated.
396394
*/
397395
function _setOperatorSplit(OperatorSplit storage operatorSplit, uint16 split, uint32 activatedAt) internal {
396+
require(split <= ONE_HUNDRED_IN_BIPS, "RewardsCoordinator._setOperatorSplit: split must be <= 10000 bips");
398397
require(
399398
block.timestamp > operatorSplit.activatedAt,
400399
"RewardsCoordinator._setOperatorSplit: earlier split not activated yet"
401400
);
402401
if (operatorSplit.activatedAt == 0) {
403-
// If the operator split has not been initialized yet, set the old split to the default split.
404-
operatorSplit.oldSplitBips = defaultOperatorSplitBips;
402+
// If the operator split has not been initialized yet, set the old split to `type(uint16).max` as a flag.
403+
operatorSplit.oldSplitBips = type(uint16).max;
405404
} else {
406405
operatorSplit.oldSplitBips = operatorSplit.newSplitBips;
407406
}
@@ -632,8 +631,12 @@ contract RewardsCoordinator is
632631
* @return The split in basis points.
633632
*/
634633
function _getOperatorSplit(OperatorSplit memory operatorSplit) internal view returns (uint16) {
635-
if (operatorSplit.activatedAt == 0) {
634+
if (
635+
(operatorSplit.activatedAt == 0) ||
636+
(operatorSplit.oldSplitBips == type(uint16).max && block.timestamp < operatorSplit.activatedAt)
637+
) {
636638
// Return the Default Operator Split if the operator split has not been initialized.
639+
// Also return the Default Operator Split if the operator split has been initialized but not activated yet. (i.e the first initialization)
637640
return defaultOperatorSplitBips;
638641
} else {
639642
// Return the new split if the new split has been activated, else return the old split.

src/test/unit/RewardsCoordinatorUnit.t.sol

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ contract RewardsCoordinatorUnitTests_setOperatorAVSSplit is RewardsCoordinatorUn
427427
split = uint16(bound(split, ONE_HUNDRED_IN_BIPS + 1, type(uint16).max));
428428

429429
cheats.prank(operator);
430-
cheats.expectRevert("RewardsCoordinator.setOperatorAVSSplit: split must be <= 10000 bips");
430+
cheats.expectRevert("RewardsCoordinator._setOperatorSplit: split must be <= 10000 bips");
431431
rewardsCoordinator.setOperatorAVSSplit(operator, avs, split);
432432
}
433433

@@ -461,14 +461,28 @@ contract RewardsCoordinatorUnitTests_setOperatorAVSSplit is RewardsCoordinatorUn
461461
split = uint16(bound(split, 0, ONE_HUNDRED_IN_BIPS));
462462
uint32 activatedAt = uint32(block.timestamp) + activationDelay;
463463
uint16 oldSplit = rewardsCoordinator.getOperatorAVSSplit(operator, avs);
464-
assertEq(oldSplit, defaultSplitBips, "Operator split is not Default split before Initialization");
464+
// Check that the split returns the default split before initialization for the first time.
465+
assertEq(
466+
oldSplit,
467+
rewardsCoordinator.defaultOperatorSplitBips(),
468+
"Operator split is not Default split before Initialization"
469+
);
465470

466471
cheats.expectEmit(true, true, true, true, address(rewardsCoordinator));
467472
emit OperatorAVSSplitBipsSet(operator, operator, avs, activatedAt, oldSplit, split);
468473
cheats.prank(operator);
469474
rewardsCoordinator.setOperatorAVSSplit(operator, avs, split);
470475

471-
assertEq(oldSplit, rewardsCoordinator.getOperatorAVSSplit(operator, avs), "Incorrect Operator split");
476+
cheats.prank(address(this)); // Owner of RewardsCoordinator
477+
// Change default split to check if it is returned before activation
478+
rewardsCoordinator.setDefaultOperatorSplit(5000);
479+
// Check that the split returns the default split before activation for the first time.
480+
assertEq(
481+
rewardsCoordinator.defaultOperatorSplitBips(),
482+
rewardsCoordinator.getOperatorAVSSplit(operator, avs),
483+
"Operator split is not Default split before Activation for first time"
484+
);
485+
472486
cheats.warp(activatedAt);
473487
assertEq(split, rewardsCoordinator.getOperatorAVSSplit(operator, avs), "Incorrect Operator split");
474488
}
@@ -566,7 +580,7 @@ contract RewardsCoordinatorUnitTests_setOperatorPISplit is RewardsCoordinatorUni
566580
split = uint16(bound(split, ONE_HUNDRED_IN_BIPS + 1, type(uint16).max));
567581

568582
cheats.prank(operator);
569-
cheats.expectRevert("RewardsCoordinator.setOperatorPISplit: split must be <= 10000 bips");
583+
cheats.expectRevert("RewardsCoordinator._setOperatorSplit: split must be <= 10000 bips");
570584
rewardsCoordinator.setOperatorPISplit(operator, split);
571585
}
572586

@@ -595,14 +609,28 @@ contract RewardsCoordinatorUnitTests_setOperatorPISplit is RewardsCoordinatorUni
595609
split = uint16(bound(split, 0, ONE_HUNDRED_IN_BIPS));
596610
uint32 activatedAt = uint32(block.timestamp) + activationDelay;
597611
uint16 oldSplit = rewardsCoordinator.getOperatorPISplit(operator);
598-
assertEq(oldSplit, defaultSplitBips, "Operator split is not Default split before Initialization");
612+
// Check that the split returns the default split before initialization for the first time.
613+
assertEq(
614+
oldSplit,
615+
rewardsCoordinator.defaultOperatorSplitBips(),
616+
"Operator split is not Default split before Initialization"
617+
);
599618

600619
cheats.expectEmit(true, true, true, true, address(rewardsCoordinator));
601620
emit OperatorPISplitBipsSet(operator, operator, activatedAt, oldSplit, split);
602621
cheats.prank(operator);
603622
rewardsCoordinator.setOperatorPISplit(operator, split);
604623

605-
assertEq(oldSplit, rewardsCoordinator.getOperatorPISplit(operator), "Incorrect Operator split");
624+
cheats.prank(address(this)); // Owner of RewardsCoordinator
625+
// Change default split to check if it is returned before activation
626+
rewardsCoordinator.setDefaultOperatorSplit(5000);
627+
// Check that the split returns the default split before activation for the first time.
628+
assertEq(
629+
rewardsCoordinator.defaultOperatorSplitBips(),
630+
rewardsCoordinator.getOperatorPISplit(operator),
631+
"Operator split is not Default split before Activation for first time"
632+
);
633+
606634
cheats.warp(activatedAt);
607635
assertEq(split, rewardsCoordinator.getOperatorPISplit(operator), "Incorrect Operator split");
608636
}

0 commit comments

Comments
 (0)