-
Notifications
You must be signed in to change notification settings - Fork 197
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
[VAULTS] PredepositGuarantee #932
base: feat/vaults
Are you sure you want to change the base?
Conversation
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.
👀
bytes32 _expectedGlobalDepositRoot, | ||
bytes calldata _signature | ||
) external { | ||
function depositToBeaconChain(Deposit[] calldata _deposits) external { |
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.
strawman sanity checks would be needed for the input data
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 BLS check todo, needs clarification on best use for precompile
@@ -68,6 +68,7 @@ contract StakingVault is IStakingVault, OwnableUpgradeable { | |||
uint128 locked; | |||
int128 inOutDelta; | |||
address nodeOperator; | |||
// depositGuardian becomes the depositor, instead of just guardian, perhaps a renaming is needed 🌚 |
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.
maybe make depositGuardian
immutable
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.
Changable but only for unconnceted vaults
|
||
// TODO: think about naming. It's not a deposit guardian, it's the depositor itself | ||
// TODO: minor UX improvement: perhaps there's way to reuse predeposits for a different validator without withdrawing | ||
contract PredepositGuardian { |
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.
contract PredepositGuardian { | |
contract PredepositGuarantee { |
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.
fixed
mapping(bytes32 validatorId => bool isPreDeposited) public validatorPredeposits; | ||
mapping(bytes32 validatorId => bytes32 withdrawalCredentials) public validatorWithdrawalCredentials; |
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.
mapping(bytes32 validatorId => bool isPreDeposited) public validatorPredeposits; | |
mapping(bytes32 validatorId => bytes32 withdrawalCredentials) public validatorWithdrawalCredentials; | |
mapping(address nodeOperator => uint256) public nodeOperatorGuarantee; | |
mapping(bytes validatorPubkey => bytes32 withdrawalCredentials) public validatorWithdrawalCredentials; |
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.
fixed
mapping(bytes32 validatorId => bytes32 withdrawalCredentials) public validatorWithdrawalCredentials; | ||
|
||
// Question: predeposit is permissionless, i.e. the msg.sender doesn't have to be the node operator, | ||
// however, the deposit will still revert if it wasn't signed with the validator private key |
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.
didn't get this
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.
this function can't be permissionless
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.
- let's include accounting and 'outsourcing' for funding
|
||
// called by the staking vault owner if the predeposited validator has a different withdrawal credentials than the vault's withdrawal credentials, | ||
// i.e. node operator was malicious | ||
function withdrawDisprovenPredeposits( |
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.
not sure what should be done here
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.
let's implement optionality in Dashboard
(either fund stVault or withdraw to the outer address)
// set flag to false to prevent double withdrawal | ||
validatorPredeposits[validatorId] = false; | ||
|
||
(bool success, ) = _recipient.call{value: 1 ether}(""); |
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.
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.
fixed
stakingVault.depositToBeaconChain(deposits); | ||
} | ||
|
||
function proveValidatorWithdrawalCredentials( |
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.
should combine prove + deposit
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.
fixed
…o predeposit-guardian-fixes
feat: enhance PredepositGuardian with events, errors, fix bugs
contracts/0.8.25/lib/GIndex.sol
Outdated
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.
this looks like it should be collected under a library
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.
Yes, but
using
allows it act as one- this 100% unchanged CSM code, which is easier to trust and audit
* @notice Interface for the `StakingVault` contract with `owner()` method from OZ `OwnableUpgradeable` | ||
*/ | ||
interface IStakingVaultOwnable is IStakingVault { | ||
function owner() external view returns (address); |
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.
Consider adding this to the interface above
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.
The reason it's outside is because owner() cannot be added to IStakingVaults due to conflicts inside StakingVault without adding extra hack code to StakingVault contract. This interface avoids changes to contract.
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol
Outdated
Show resolved
Hide resolved
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol
Outdated
Show resolved
Hide resolved
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.
👀
/// @solidity memory-safe-assembly | ||
assembly { | ||
// Store `left` at memory position 0x00 | ||
mstore(0x00, left) |
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.
let's revisit this later: 'The zero slot is used as initial value for dynamic memory arrays and should never be written to (the free memory pointer points to 0x80 initially)'
https://docs.soliditylang.org/en/latest/internals/layout_in_memory.html
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.
It's okay to use 64 bytes of scratch space to store precomile input, it will be overwritten by staticall.
// Zero the remaining 16 bytes to form a 64‐byte block. | ||
// (0x30 = 48, so mstore at 0x30 will zero 32 bytes covering addresses 48–79; | ||
// only bytes 48–63 matter for our 64-byte input.) | ||
mstore(0x30, 0) |
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.
it corrupts the free memory slot
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.
Fixed
contracts/0.8.25/lib/SSZ.sol
Outdated
calldatacopy(0x00, pubkey.offset, 48) | ||
|
||
// Zero the remaining 16 bytes to form a 64-byte input block | ||
mstore(0x30, 0) |
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.
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.
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.
fixed
contracts/0.8.25/vaults/predeposit_guarantee/CLProofVerifier.sol
Outdated
Show resolved
Hide resolved
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol
Outdated
Show resolved
Hide resolved
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol
Outdated
Show resolved
Hide resolved
contracts/0.8.25/vaults/predeposit_guarantee/PredepositGuarantee.sol
Outdated
Show resolved
Hide resolved
* @custom:inOutDelta Net difference between ether funded and withdrawn from StakingVault | ||
* @custom:nodeOperator Address of the node operator | ||
* @custom:beaconChainDepositsPaused Whether beacon deposits are paused by the vault owner | ||
* @custom: report Latest report containing valuation and inOutDelta |
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.
i think the space breaks the natspec custom tag directive
https://docs.soliditylang.org/en/latest/natspec-format.html#tags
*/ | ||
struct ERC7201Storage { | ||
Report report; | ||
uint128 locked; | ||
int128 inOutDelta; | ||
address nodeOperator; | ||
address depositGuardian; |
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.
let's rename to trustedDepositor, or something
* @param _pubkey of validator that was proven invalid in PDG | ||
* @param _recipient address to receive the `PREDEPOSIT_AMOUNT` | ||
*/ | ||
function withdrawDisputedValidator(bytes calldata _pubkey, address _recipient) external { |
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.
Why is it called "disputed"? It can either be proven of disproven?
* Staking Vault does not have to be connected to Lido or any other system to be compatible with PDG | ||
* but a reverse constraint can be AND are applied. | ||
*/ | ||
contract PredepositGuarantee is CLProofVerifier, PausableUntilWithRoles { |
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.
Why do need to pause it?
This pull request introduces PredepositGuarantee contract that acts as deposit security layer for all Lido connected vaults.