Conversation
eladiosch
left a comment
There was a problem hiding this comment.
I left a few comments. I haven't dived deeply into tests or scripts. I want to validate the approach and flows first
| * @dev Permissioned module beacon address (stored in contract storage for upgradeability) | ||
| * keccak256(abi.encode(uint256(keccak256("PufferModuleManager.permissionedModuleBeacon")) - 1)) & ~bytes32(uint256(0xff)) | ||
| */ | ||
| bytes32 private constant _PERMISSIONED_MODULE_BEACON_SLOT = |
There was a problem hiding this comment.
Any reason to follow this approach to store the beacon? Why not follow the same approach with the regular puffer module beacon? It's a bit strage to have different approaches for pretty much the same thing in the same contract
There was a problem hiding this comment.
PUFFER_MODULE_BEACON is immutable and fixed at deployment of this contract, but _PERMISSIONED_MODULE_BEACON_SLOT uses storage for post deployment upgradability
There was a problem hiding this comment.
Yes, I see that. However, since both are really similar (and now also the beacon for NRWC). Using the current approach, when deploying we need to also send 2 transactions to set these beacons (right now those are not part of the deployment flow). I think it might be easy to miss and complicated the deployment flow.
If we went with the constructor arg approach it will be simpler and if we need to upgrade any of the beacons we can upgrade the PMM just deploying a new implementation instead of sending the transactions to set the beacons. It would also mean a simpler code since we remove the setter functions and the storage slots, etc
| // Create EigenPod for restaked validators | ||
| $.eigenPod = IEigenPod(address(EIGEN_POD_MANAGER.createPod())); | ||
| // Deploy NonRestakingWithdrawalCredentials for non-restaked validators | ||
| $.nonRestakingWithdrawalCredentials = new NonRestakingWithdrawalCredentials(address(this), initialAuthority); |
There was a problem hiding this comment.
Not sure about this way of deploying NonRestakingWithdralCredentials. If we need to change the withdrawal credentials contract, we have no way of upgrading the it, maybe it should be upgradeable. Imagine we found a bug in there, or a new EIP comes with new functionality to interact with the beacon deposit contract, we don't even have custom external call (EDIT: I see we do have a call function). I think it should be upgradeable
And if we have a lot of permissioned modules in the future, it would be very tedious to upgrade the contracts one by one. I think we should use a beacon proxy, just like with the modules
There was a problem hiding this comment.
make sense. made NRWC as beacon upgradable
There was a problem hiding this comment.
LGTM. See my other comment related to how to manage the beacons
| /** | ||
| * @inheritdoc IPermissionedOracle | ||
| */ | ||
| function adjustLockedEth(bytes32 moduleName, uint256 reductionAmount) external restricted { |
There was a problem hiding this comment.
I'm unsure about this oracle approach.Since non-restaked validators don't get their rewards in the withdrawal credentials automatically (unless they get to the max 2048 ETH), the rewards will be compounding in the validator in the beaconchain. That extra ETH is not represented in our protocol in any way at the moment, so I think we should add another function here that increases the locked ETH amount that would be the auto-compounding of the rewards in the beaconchain. Otherwise, the accounting is not being totally accurate. A backend service would need to check beaconchain periodically and call this function
There was a problem hiding this comment.
as mentioned in natspec now, In oracle, adjustLockedEth is only for slashing/inactivity penalties, not rewards
Extra ETH (rewards) flows to module automatically, or keep compounding. They are not the part of the exchange rate ever - unless we plan to transfer the ETH to the vault. And for that we already have withdrawNonRestakedETH in PufferModuleManager that moves ETH from NRWC -> PermissionedModule.
And then we can call transferPermissionedModuleETHToVault , that moves ETH to the vault - increasing the exchange rate - which is intentional and if we plan to profit pufETH holders.
Otherwise we can add another function in PMM to utilize call() of PermissionedModule to transfer ETH to another recipient like external EOA/Multisig/Partner
There was a problem hiding this comment.
i'll add another function to transfer rewards to arbitrary EOA/multisig
There was a problem hiding this comment.
Ok I get it. Since the auto compounding rewards might or might not go into the vault, it shouldn't be reflected in the exchange rate, even if 32 ETH where used for a validator that currently it's at say 1k ETH in the beacon chain
There was a problem hiding this comment.
yes, that's the whole point of having permissioned validator - the rewards are revenue to the protocol or partner who's provided the ETH/ running the validator. And it's their decision whether they want to provide benefit to pufETH holders or keep the revenue to themselves.
| beaconDepositContract: _getBeaconDepositContract() | ||
| }) | ||
| beaconDepositContract: _getBeaconDepositContract(), | ||
| permissionedOracle: IPermissionedOracle(address(0)) // TODO: set actual address |
There was a problem hiding this comment.
Should add _getPermissionedOracle() function, like we do with puffer oracle
| revenueDepositor: IPufferRevenueDepositor(_getRevenueDepositor()) | ||
| }); | ||
| revenueDepositor: IPufferRevenueDepositor(_getRevenueDepositor()), | ||
| permissionedOracle: IPermissionedOracle(address(0)) // TODO: set actual address |
There was a problem hiding this comment.
Like mentioned in other comment, should call a _getPermissionedOracle() function
| beaconDepositContract: getStakingContract() | ||
| }); | ||
| beaconDepositContract: getStakingContract(), | ||
| permissionedOracle: IPermissionedOracle(address(0)) // Will be set in upgrade |
There was a problem hiding this comment.
I think permissionedOracle should be passed as a param, just like with basic oracle
| enclaveVerifier: guardiansDeployment.enclaveVerifier, | ||
| beacon: address(pufferModuleBeacon), | ||
| restakingOperatorBeacon: address(restakingOperatorBeacon), | ||
| permissionedModuleBeacon: address(0), // Set during permissioned module deployment |
There was a problem hiding this comment.
I don't think this is the right approach. These beacons (and the permissioned oracle) should be deployed here and assigned to the PufferProtocolDeployment. And the beacons should be set to the PMM, calling the setPermissionedModuleBeacon and setNRWCBeacon. Actually, I still think they should be set in the constructor, just like the PM beacon. Having to send different transactions for that seems inefficient and it can be easy to miss. I'll leave a comment in the PR about this subject
There was a problem hiding this comment.
ah, i see your point now. i'll move it to the constructor. my bad
| IPufferOracleV2(pufferOracle), | ||
| IPufferRevenueDepositor(revenueDepositor) | ||
| IPufferRevenueDepositor(revenueDepositor), | ||
| IPermissionedOracle(address(0)) |
There was a problem hiding this comment.
I think it should be passed as a param
| selectors[4] = PufferModuleManager.callRegisterOperatorToAVS.selector; | ||
| selectors[5] = PufferModuleManager.callDeregisterOperatorFromAVS.selector; | ||
| selectors[6] = PufferModuleManager.customExternalCall.selector; | ||
| selectors[7] = PufferModuleManager.transferPermissionedModuleETH.selector; |
There was a problem hiding this comment.
There are some restricted functions in PMM not reflected here
There was a problem hiding this comment.
created new script for accessmanagment: 09_GeneratePermissionedModuleCalldata.s.sol for the newly added restricted functions
|
|
||
| // Enforce FIFO ordering - only allow provisioning the next validator in line | ||
| uint256 nextToProvision = $.nextPermissionedValidatorToBeProvisionedIndices[moduleName]; | ||
| if (validatorIndex != nextToProvision) { |
There was a problem hiding this comment.
If we're enforcing FIFO there is no point in passing the validatorIndex as a param. We can simply use $.nextPermissionedValidatorToBeProvisionedIndices[moduleName]. We should delete the index parameter for both flows and use the same approach as in regular provisionNode and skipProvisioning flows
What this PR does / why we need it:
Which issue(s) does this PR fixes:
Additional comments: