diff --git a/README.md b/README.md index cab53fe..0f7085b 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,28 @@ Contracts for managing validator's rewards fees -## How it works on a high-level +## Overview -- The repo contains 2 contracts: `FeeRewardsManager` and `RewardsCollector` -- Fee manager contract `FeeRewardsManager` will be deployed once per environment +- The repo contains 2 contracts: `FeeRewardsManager` and `RewardsCollector` and a library `CalculateAndSendRewards` +- Fee manager contract `FeeRewardsManager` will be deployed once per environment. - `FeeRewardsManager` creates one `RewardsCollector` contract per withdrawal credentials (some users may have more than 1) -- On creation `FeeRewardsManager` sets a default commission fee and has permission to change that fee -- `RewardsCollector` address will be derived from `withdrawal credentials` -- `RewardsCollector` address will be set as `fee_recipient` for customers validators and earn execution rewards -- `collectRewards` function in `RewardsCollector` contract can be triggered to send rewards minus commission fee to withdrawal address +- On creation `FeeRewardsManager` sets a default commission fee and has permission to change that fee. +- `RewardsCollector` address will be derived from `withdrawal credentials`. +- `RewardsCollector` address will be set as `fee_recipient` for customers validators and earn execution rewards. +- `collectRewards` function in `RewardsCollector` contract can be triggered to send rewards minus commission fee to withdrawal .address. + +### `RewardsCollector` Contract + +- **Ownership**: This contract does not explicitly use an ownership model. Instead, it references a `parentContract`, the contract that deployed it, the `FeeRewardsManager` contract. +- **withdrawalCredential**: A crucial address that is set upon contract deployment, determining where a portion of the fees are sent. +- **feeNumerator**: A value determining the fee percentage, modifiable only by the `parentContract`. + +### `FeeRewardsManager` Contract + +- **Ownership**: Inherits from `Ownable2Step`, a variant of the OpenZeppelin `Ownable` contract, which provides a secure ownership model with a two-step transfer process to prevent accidental loss of ownership. The part that is receiving +the ownership on the transfer must confirm it with a transaction. +- **defaultFeeNumerator**: Set upon deployment and modifiable by the contract owner. +- **Eth Withdrawal**: Only the owner can withdraw Eth from the contract. ## Walkthrough a normal execution diff --git a/src/FeeRewardsManager.sol b/src/FeeRewardsManager.sol index f47d3d5..ee237cb 100644 --- a/src/FeeRewardsManager.sol +++ b/src/FeeRewardsManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.13; -import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/access/Ownable2Step.sol"; // We use a library for the `calculateRewards` function because the less code in // `RewardsCollector` the less expensive it it to deploy the collector contract. @@ -86,7 +86,7 @@ contract RewardsCollector { } } -contract FeeRewardsManager is Ownable { +contract FeeRewardsManager is Ownable2Step { uint32 public defaultFeeNumerator; constructor(uint32 _defaultFeeNumerator) { diff --git a/test/FeeRewardsManager.t.sol b/test/FeeRewardsManager.t.sol index 607c003..c959123 100644 --- a/test/FeeRewardsManager.t.sol +++ b/test/FeeRewardsManager.t.sol @@ -200,4 +200,13 @@ contract FeeRewardsTest is Test { vm.expectRevert("Failed to send Ether back to withdrawal credential"); RewardsCollector(payable(addr)).collectRewards(); } + + function testChangeOwnership() public { + feeRewardsManager.transferOwnership(address(0x105)); + assertEq(feeRewardsManager.pendingOwner(), address(0x105)); + vm.startPrank(address(0x105)); + feeRewardsManager.acceptOwnership(); + vm.stopPrank(); + assertEq(feeRewardsManager.owner(), address(0x105)); + } }