-
Notifications
You must be signed in to change notification settings - Fork 84
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
SSV Native staking #2015
SSV Native staking #2015
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #2015 +/- ##
==========================================
+ Coverage 60.54% 61.86% +1.31%
==========================================
Files 59 66 +7
Lines 3021 3322 +301
Branches 779 649 -130
==========================================
+ Hits 1829 2055 +226
- Misses 1189 1264 +75
Partials 3 3 ☔ View full report in Codecov by Sentry. |
contracts/contracts/strategies/NativeStaking/ValidatorRegistrator.sol
Outdated
Show resolved
Hide resolved
contracts/contracts/strategies/NativeStaking/NativeStakingSSVStrategy.sol
Outdated
Show resolved
Hide resolved
|
||
balance = activeDepositedValidators * 32 ether; | ||
balance += beaconChainRewardWETH; | ||
balance += FEE_ACCUMULATOR_ADDRESS.balance; |
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 don't think we want to include the MEV rewards in the FeeAccumulator if those are going to be harvested and sent to through the dripper.
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.
Thanks this is a nice catch. I see I haven't given it enough though as to how (W)ETH should be handled.
Lets continue discussion here so we have it all in 1 place: https://www.notion.so/originprotocol/How-should-accounting-function-handle-ETH-after-accounting-4ed3a9352c0f4fc8aa6bb866022a25cb
contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol
Outdated
Show resolved
Hide resolved
contracts/contracts/strategies/NativeStaking/ValidatorAccountant.sol
Outdated
Show resolved
Hide resolved
* Update Natspec * Generated docs for native eth strategy * Prettier and linter Fixed spelling of ValidatorAccountant events Implemented depositSSV * Updated Natspec Moved MAX_STAKE on ValidatorAccountant to a constant * Removed strategist from strategy as its already maintained in the Vault * Fix compilation error * Fix unit tests * fix linter
* Added OETH process diagram with functions calls for native staking * Native Staking Strategy now hold consensus rewards at ETH FeeAccumulator now holds execution rewards as ETH Removed WETH immutable from FeeAccumulator Converted custom errors back to require with string collect rewards now converts ETH to WETH at harvest checkBalance is now validators * 32 plus WETH balance from deposits Renamed beaconChainRewardsWETH to consensusRewards Fixed bug in stakeETH that was converting all WETH to ETH
* Fixed native staking deployment since the strategist is got from the vault * Refactor of some Native Staking events Refactor of Native Staking unit tests * Renamed AccountingBeaconChainRewards to AccountingConsensusRewards Accounting updated to handle zero ETH from the beacon chain * fixed bug not accounting for previous consensus rewards Blow fuse if ETH balance < previous consensus rewards * Pause collectRewardTokens and doAccounting on accounting failure. Validated asset on deposit to Native Staking Strategy. Moved depositSSV from NativeStakingSSVStrategy to ValidatorRegistrator moved onlyStrategist modified and VAULT_ADDRESS immutable from ValidatorAccountant to ValidatorRegistrator manuallyFixAccounting changed to use whenPaused modifier made fuseIntervalEnd inclusive Natspec updates refactoring of native staking unit tests
* add basic steps to deploy OETH to holesky * prettier * minor change * holesky deployment ifles holesky deployment files * add holesky deployment files * minor fix * minor fixes * make the fork tests run on Holesky * add some more tests * testing SSV staking on Holesky * refactor where deployment files are located * more progress on deployment * add deposit to validator deployment files * remove log * prettier * lint * move file * SSV cluster info (#2036) * add ability to fetch SSV cluster information * prettier
* manuallyFixAccounting now uses delta values and only callable by the strategist manuallyFixAccounting calls doAccounting to check the fuse is still not blown Removed accountingGovernor * Added pauseOnFail param to internal _doAccounting Increased the allowed delta values of manuallyFixAccounting * ran prettier
Posting my mostly complete review Code Review: Native StakingRequirementsOETH should be able to deposit and withdraw ETH from SSV controlled native staking as a yield earning strategy. It is planned that this will be the primary yield for OETH and that OETH will become an LST. This is a difficult strategy to build because validators operate cross chain, and the execution chain only has very poor information about the actual status of validators. What information can be gathered far to gas intensive to be effective. Because Ethereum has horrible support for LSTs, there are essentially two approaches to building an LST. The first is YOLO trust of an address that updates the execution layer about what is going on the validator layer. The second is building a massive offchain oracle infrastructure and operating it. We've chosen a third route:
The overall concept is contract enforced damage mitigation. We want to transition to fully onchain accounting once that is possible from future Ethereum updates. Authentication
Ethereum_Unlike almost all of contracts, we do send and receive ETH from this contract. However, we only send ETH to two trusted addresss. 🟠 There are three methods to prevent reentrancy: only calling trusted contracts, reentrancy guards, and writing functions in order such that reentrancy is not an issue. Usually we try to hit all three. This code only does the first.
Cryptographic codeThe only crypto used is hashing the validator public keys in order to look them up in a mapping. I don't think that can be abused to get different public keys to map to the same hash. Otherwise the contract passes through signature data, but does not use it itself. Gas problems
Black magic
Overflow
Proxy
Events🟣 Deposit SSV does not emit directly, but that's okay. We could monitor the SSV contract for this if we wished. Rounding
Dependencies
External calls
Testsnot checked yet
Deploy
Strategy SpecificStrategy checks
Accounting Invariants
What happens if:
LogicAre there bugs in the logic? Still not specifically reviewed yet
Deployment Considerations
Internal StateSee above in "Accounting Invariants" section AttackThis code is inherently dangerous. We focus on damage mitigation rather than the usual perfection. First, there is no way for a smart contract to ensure that a staking deposit will end up with correct withdrawal address in the beacon chain. We are essentially shipping out gold bars via packing labels created on an EOA. To mitigate this risk, we limit how many deposits can be made before requiring a 5 of 8 multisig to verify that the previous deposits were correctly made. This caps our max losses at about two million per strategy contract. We could reduce the deposit risk by a magnitude and remove all humans from the loop by doing the following:
By keeping a limited number of deposits in the pending state, we reduce our risk. 1 ETH instead of 32 ETH to test out a validator deposit is also a fairly big win. Secondly, it would take approximately 50% of all yield to be spent in gas to be mostly sure about what each validator is doin on the beacon chain. Instead we take a guess based on the amount of funds we see coming in. This can be wrong and need manual correction. We also throttle the amount of manual correction to avoid malicious actions. Outside the scope of this contract, failures or vulnerabilities with SSV or P2P could result in mass slashings of our validators. Withdrawing funds is also ultimately outside the contract's control. We can ask the SSV contract to emit an event which hopefully is picked up. There are other off-chain ways to kick off withdraws. SSV rewards are also outside our contracts control, since they go only to the EOA that deployed the contracts. ETH rewards are not distinguished from withdraws, both go to the same place, via the same mechanism. We use heuristics to discriminate between them. Our strategy contracts have four jobs:
Four out of four of these cannot be guaranteed by the code. Monitoring is critical here. Other code: We might be in trouble if the SSV deposit made callbacks to somewhere that an attacker could hook into. A quick glance at the SSV code shows that not only is it dynamic, but extremely dynamic in its dynamicness. 🟠 Let's add FlavorThe strategy is broken into three different files in an inheritance hierarchy. In general I'm not a fan of this, as it makes it more difficult to see the big picture, but the cutpoints here are very good, and each has clear ownership of difference concerns, and small interaction with other layers. Works here. Otherwise, the flavor is now good. |
/// The `ValidatorStakeData` struct contains the pubkey, signature and depositDataRoot. | ||
/// Only the registrator can call this function. | ||
// slither-disable-start reentrancy-eth | ||
function stakeEth(ValidatorStakeData[] calldata validators) |
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 add nonReentrant
to stakeETH, doAccounting and manuallyFixAccounting so something weird happening with SSV can't mess anything up on our side.
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've added nonReentrant
to stakeETH
, doAccounting
and manuallyFixAccounting
* Changed registerSsvValidator to registerSsvValidators so it can register multiple validators * Added length check on publicKeys and sharesData in registerSsvValidators * Added test to bulk register validators * Updated process diagrams * deployed new NativeStakingSSVStrategy to Holesky * Changes to bulk register validators * Fixed stakeValidators * Added snapStaking hardhat task * Add optional validators to registerValidators Hardhat task * stakeValidators validator logic moved * fixes to registerValidators * Saved Gnosis Safe file into contracts folder for now * New deployment to Holesky with multi validator registrations
* Added LidoWithdrawalStrategy * Added deployment of Lido withdrawal strategy * Completed Lido Withdrawal Strategy fork tests * Updated Natspec * Renamed fraxEth to stEth in LidoWithdrawalStrategy * Moved _abstractSetPToken to bottom of the LidoWithdrawalStrategy made _abstractSetPToken pure * renamed numWithdrawals to withdrawalLength * outstandingWithdrawals now accounts for stETH dust left behind * don't format Defender Action code in dist folder
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.
The NativeSSVStrategy contract is approved for use with test amounts of funds.
I have not yer reviewed the rest of this PR.
Added more logs to native staking deploy script
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.
All pre deployment checks have bene done
Contracts
Pull Requests to this branch
Related pull requests
Changes
NativeStakingSSVStrategy
that takes WETH from the Vault and stakes ETH into SSV validators.FeeAccumulator
to receive ETH execution rewards.BaseHarvester
so it can collect WETH and send it straight to theDripper
Diagrams
NativeStakingSSVStrategy
FeeAccumulator
Processes
Value Flows
The flow of native currency (ETH) and tokens between the wallets and contracts.
Validator Registration and Staking
Validator withdrawals
Validator rewards
Native Staking Admin
Testing
Unit Tests
Unit tests are in
contracts/test/strategies/nativeSSVStaking.js
yarn run test
Holesky fork tests
Holesky fork tests are in
contracts/test/strategies/nativeSsvStaking.holesky.fork-test.js
Mainnet fork tests
Mainnet fork tests are in
contracts/test/strategies/nativeSsvStaking.fork-test.js
Holesky end-to-end testing using Hardhat tasks
Deployment
The deploy script for the Native Staking Strategy is
contracts/deploy/mainnet/097_native_ssv_staking.js
.Operations
Hardhat tasks