Skip to content

Commit a015dd2

Browse files
committed
fix: reduce potential setOperatorReceiver spam by requiring valid pubkey ownership
1 parent 238759e commit a015dd2

File tree

4 files changed

+45
-12
lines changed

4 files changed

+45
-12
lines changed

src/pol/interfaces/IBlockRewardController.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ interface IBlockRewardController is IPOLErrors {
167167

168168
/**
169169
* @notice Sets or updates the receiver address for an operator's base BGT rewards
170-
* @dev Only the operator can set their receiver
170+
* @dev Only the operator associated with the provided pubkey can set their receiver
171+
* @param pubkey The validator's public key used to retrieve the operator from the deposit contract
171172
* @param receiver The address that will receive base BGT rewards. Set to address(0) to receive rewards directly
172173
*/
173-
function setOperatorReceiver(address receiver) external;
174+
function setOperatorReceiver(bytes calldata pubkey, address receiver) external;
174175
}

src/pol/rewards/BlockRewardController.sol

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,12 +260,21 @@ contract BlockRewardController is IBlockRewardController, OwnableUpgradeable, UU
260260

261261
/**
262262
* @notice Sets or updates the receiver address for an operator's base BGT rewards
263-
* @dev Only the operator can set their receiver
263+
* @dev Only the operator associated with the provided pubkey can set their receiver
264+
* @param pubkey The validator's public key used to retrieve the operator from the deposit contract
264265
* @param receiver The address that will receive base BGT rewards. Set to address(0) to receive rewards directly
265266
*/
266-
function setOperatorReceiver(address receiver) external {
267-
address oldReceiver = operatorReceivers[msg.sender];
268-
operatorReceivers[msg.sender] = receiver;
269-
emit OperatorReceiverUpdated(msg.sender, oldReceiver, receiver);
267+
function setOperatorReceiver(bytes calldata pubkey, address receiver) external {
268+
// Get the operator address from the deposit contract using the provided pubkey
269+
address operator = beaconDepositContract.getOperator(pubkey);
270+
271+
// Ensure that only the operator can set their receiver
272+
if (msg.sender != operator) {
273+
NotOperator.selector.revertWith();
274+
}
275+
276+
address oldReceiver = operatorReceivers[operator];
277+
operatorReceivers[operator] = receiver;
278+
emit OperatorReceiverUpdated(operator, oldReceiver, receiver);
270279
}
271280
}

test/mock/pol/NoopBlockRewardController.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ contract NoopBlockRewardController is IBlockRewardController {
6464
function setDistributor(address _distributor) external { }
6565

6666
/// @inheritdoc IBlockRewardController
67-
function setOperatorReceiver(address _receiver) external { }
67+
function setOperatorReceiver(bytes calldata pubkey, address _receiver) external { }
6868
}

test/pol/BlockRewardController.t.sol

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ contract BlockRewardControllerTest is POLTest {
266266
address receiver = makeAddr("receiver");
267267
// Set receiver for operator
268268
vm.prank(operator);
269-
blockRewardController.setOperatorReceiver(receiver);
269+
blockRewardController.setOperatorReceiver(valData.pubkey, receiver);
270270

271271
// Verify receiver is set correctly
272272
assertEq(blockRewardController.operatorReceivers(operator), receiver);
@@ -289,11 +289,11 @@ contract BlockRewardControllerTest is POLTest {
289289
address receiver = makeAddr("receiver");
290290
// First set a receiver
291291
vm.prank(operator);
292-
blockRewardController.setOperatorReceiver(receiver);
292+
blockRewardController.setOperatorReceiver(valData.pubkey, receiver);
293293

294294
// Then clear it by setting to address(0)
295295
vm.prank(operator);
296-
blockRewardController.setOperatorReceiver(address(0));
296+
blockRewardController.setOperatorReceiver(valData.pubkey, address(0));
297297

298298
// Verify receiver is cleared
299299
assertEq(blockRewardController.operatorReceivers(operator), address(0));
@@ -339,7 +339,7 @@ contract BlockRewardControllerTest is POLTest {
339339
// Setup receivers in BlockRewardController
340340
address receiver1 = makeAddr("receiver1");
341341
vm.prank(operator);
342-
blockRewardController.setOperatorReceiver(receiver1);
342+
blockRewardController.setOperatorReceiver(valData.pubkey, receiver1);
343343

344344
// Don't set receiver for operator2
345345

@@ -453,4 +453,27 @@ contract BlockRewardControllerTest is POLTest {
453453
amount = _bound(amount, 1, type(uint128).max / 2);
454454
_helper_ActivateBoost(user, user, pubkey, amount);
455455
}
456+
457+
/// @dev Should fail if not the operator tries to set receiver
458+
function test_SetOperatorReceiver_FailIfNotOperator() public {
459+
// Try to set receiver from a non-operator address
460+
address nonOperator = makeAddr("nonOperator");
461+
vm.prank(nonOperator);
462+
vm.expectRevert(IPOLErrors.NotOperator.selector);
463+
blockRewardController.setOperatorReceiver(valData.pubkey, address(1));
464+
}
465+
466+
/// @dev Should successfully set operator receiver when called by the operator
467+
function test_SetOperatorReceiver_Success() public {
468+
address receiver = makeAddr("receiver");
469+
470+
// Set receiver as the operator
471+
vm.prank(operator);
472+
vm.expectEmit(true, true, true, true);
473+
emit IBlockRewardController.OperatorReceiverUpdated(operator, address(0), receiver);
474+
blockRewardController.setOperatorReceiver(valData.pubkey, receiver);
475+
476+
// Verify receiver is set correctly
477+
assertEq(blockRewardController.operatorReceivers(operator), receiver);
478+
}
456479
}

0 commit comments

Comments
 (0)