-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: withdrawal credentials #904
base: develop
Are you sure you want to change the base?
Conversation
Hardhat Unit Tests Coverage Summary
Diff against master
Results for commit: 6cdc711 Minimum allowed coverage is ♻️ This comment has been updated with latest results |
revert NoWithdrawalRequests(); | ||
} | ||
|
||
uint256 minFeePerRequest = getWithdrawalRequestFee(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't fee increase with each request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the fee will not increase with each request. Inside the transaction, all requests will have the same fee.
EIP 7002 uses block-by-block behavior.
If block N processes X requests, then at the end of block N the number of withdrawal requests that the chain has processed relative to the “targeted” number increases by X - TARGET_WITHDRAWAL_REQUESTS_PER_BLOCK, and so the fee in block N+1 increases by a factor of e**((X - TARGET_WITHDRAWAL_REQUESTS_PER_BLOCK) / WITHDRAWAL_REQUEST_FEE_UPDATE_FRACTION).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still see some potential for improvement
Add role ADD_FULL_WITHDRAWAL_REQUEST_ROLE for full withdrawal requests.
…hdrawal-credentials
Access pubkeys and amounts directly instead of copying them to memory.
pass pubkeys as array of bytes
contracts/0.8.9/WithdrawalVault.sol
Outdated
function addFullWithdrawalRequests( | ||
bytes calldata pubkeys | ||
) external payable onlyRole(ADD_FULL_WITHDRAWAL_REQUEST_ROLE) { | ||
uint256 prevBalance = address(this).balance - msg.value; | ||
|
||
uint256 minFeePerRequest = TriggerableWithdrawals.getWithdrawalRequestFee(); | ||
uint256 totalFee = pubkeys.length / TriggerableWithdrawals.PUBLIC_KEY_LENGTH * minFeePerRequest; | ||
|
||
if(totalFee > msg.value) { | ||
revert InsufficientTriggerableWithdrawalFee( | ||
msg.value, | ||
totalFee, | ||
pubkeys.length / TriggerableWithdrawals.PUBLIC_KEY_LENGTH | ||
); | ||
} | ||
|
||
TriggerableWithdrawals.addFullWithdrawalRequests(pubkeys, minFeePerRequest); | ||
|
||
uint256 refund = msg.value - totalFee; | ||
if (refund > 0) { | ||
(bool success, ) = msg.sender.call{value: refund}(""); | ||
|
||
if (!success) { | ||
revert TriggerableWithdrawalRefundFailed(); | ||
} | ||
} | ||
|
||
assert(address(this).balance == prevBalance); | ||
} |
Check warning
Code scanning / Slither
Divide before multiply Medium
- totalFee = (pubkeys.length / TriggerableWithdrawals.PUBLIC_KEY_LENGTH) * minFeePerRequest
contracts/0.8.9/WithdrawalVault.sol
Outdated
function addFullWithdrawalRequests( | ||
bytes calldata pubkeys | ||
) external payable onlyRole(ADD_FULL_WITHDRAWAL_REQUEST_ROLE) { | ||
uint256 prevBalance = address(this).balance - msg.value; | ||
|
||
uint256 minFeePerRequest = TriggerableWithdrawals.getWithdrawalRequestFee(); | ||
uint256 totalFee = pubkeys.length / TriggerableWithdrawals.PUBLIC_KEY_LENGTH * minFeePerRequest; | ||
|
||
if(totalFee > msg.value) { | ||
revert InsufficientTriggerableWithdrawalFee( | ||
msg.value, | ||
totalFee, | ||
pubkeys.length / TriggerableWithdrawals.PUBLIC_KEY_LENGTH | ||
); | ||
} | ||
|
||
TriggerableWithdrawals.addFullWithdrawalRequests(pubkeys, minFeePerRequest); | ||
|
||
uint256 refund = msg.value - totalFee; | ||
if (refund > 0) { | ||
(bool success, ) = msg.sender.call{value: refund}(""); | ||
|
||
if (!success) { | ||
revert TriggerableWithdrawalRefundFailed(); | ||
} | ||
} | ||
|
||
assert(address(this).balance == prevBalance); | ||
} |
Check warning
Code scanning / Slither
Dangerous strict equalities Medium
- assert(bool)(address(this).balance == prevBalance)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Minor comments about library placement, constant WITHDRAWAL_REQUEST (may be immutable), and some style fixes suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some suggestions to errors naming, to prevent clashing
…hdrawal-credentials
Summary
This PR introduces an early-stage prototype for a potential implementation of EIP-7685: General Purpose Execution Layer Requests. Specifically, it implements EIP-7002: Execution Layer Triggerable Withdrawals within the Lido WithdrawalVault contract, which serves as the withdrawal credentials address for Lido validators.
Approach
The implementation follows the first approach outlined in the ADR for Withdrawal Credentials Contract. This approach was selected due to the following advantages:
Implementation Details
In this iteration, the
WithdrawalVault
contract supports only full withdrawal requests. Partial withdrawals are not included because they are not part of the proposed Triggerable Withdrawal V1 implementation within the Lido protocol.The following pseudo-code demonstrates the approach:
Key Considerations
The modular design of separate libraries for different withdrawal request types ensures that withdrawal credentials contracts can import and use only the minimal functionality required. For example:
Notes
This PR is an initial prototype and is subject to further iterations based on feedback and evolving requirements.