---
# System prepended metadata

title: Ultrasound LST high level design

---

# Ultrasound LSD high level design v2



[TOC] 

## Comparison of oracle vs no-oracle solution 

- with oracle 
	- upside 
		- smart contract 
			- much simpler (no need to launch + manage minipools)
			- cheaper operation (less gas)
	- downside 
		- potential exposure to oracle bugs
		- more opinionated solution
			- need to set performance target for operators
		- ? cost of running the oracle 

puffer d

## Highlevel obeservations


- Validators are created & deposited by operators via the pool after they provide deposit. The pool checks the withdrawal address, which has to match the one set by the pool (probably the pool itself). Thus the pool receives all consensus rewards & Operator all execution layer ones.

> 	- *Problem - operators are not incentivized to perform well on the validator duties. They could simply choose to not participate unless they are a block proposer of which rewards are they recipients*
> 		- *Solution 1* 
> 			- **Create a trustless oracle, which can determine consensus rewards**
> 				- *? Is it possible to determine which exact validator are the rewards coming from? Probably not*
> 					- *If NOT, they may be a separate dummy contract necessary for each Operator that would act as the Withdrawal address for its validators.*
> 		- *Solution 2*
> 			- *Single Secret Leader Election (SSLE) if implemented should solve this? If Operator does not know in advance if he is a slot proposer(? is this true?), he wouldn't be able not to run a validator since he is risking loss of execution rewards.

- Operators bid for the privilege to run validators by setting `maxBidPerValidator` and they receive execution layer rewards(MEV).

- At the end of the Validation period(1 year), If there have been no slashing events and period is not prolonged the **Operator receives 4 ETH exactly**. 
	- The amount Operators actually pay for this privilege is determined fully by the market. Under normal conditions, this should be higher than 4 ETH.
	- *NOTICE - This is very similar to zero bond from trad fi. Amount received at the end is constant and Operators' profits are equal to the delta between how much they get from the MEV rewards during the period(1 year) of operation minus how much they pay for the privilege.*
- Operator profit
	- $executionRewards + depositReceived - effectiveDeposit$
		- $effectiveDeposit$ - is determined by the auction. 
			- If $executionRewards$ are larger than the cost of running a validator it will be more than 4 ETH. This should be the case 99.9% of times as the HW costs are low and going lower. 
> 			- *Potential issue (small) - If in the future $executionRewards$ are less than the cost of running a validator the $effectiveDeposit$ could be less than 4ETH. This seems highly unlikely but possible. It is reasonable to expect that this cost should be no more than 0.5% of validator effective balance (0.16ETH). Thus the min $depositReceived$ could be set to 99.5% of $effectiveDeposit$ (3.84). The min $effectiveDeposit$ hence loss could be capped to e.g. 0.16 ETH in which case no more than this amount would be lost If a max slashing event takes place.*  
> 				- *the min $effectiveDeposit$ could be a variable controlled by the governance, once there is sufficient trust this is not an issue in practice the governance could be set to zero address.* 
		
- *NOTICE* - *Since Operator is using `uETH` as a deposit, he is implicitly getting the consensus rewards.* 




## Pool interactions 

### Staking & unstaking


- `deposit(amount)`
	- deposits `ETH` and receives `uETH` in return. 
- `withdraw(amount)`
	-  deposits `uETH` and receives `ETH` in return. 

- `forceWithdrawRequest(amount)`
	- deposits `uETH` and requests `ETH` in return. 
- `forceWithdraw(amount)`
	- receives `ETH` the funds need to be available. 

- `wrap(amount)`
	- wraps `uETH` (same as with stETH) and receives `wuETH`. 
- `unwrap(amount)`
	- unwraps `wuETH` (same as with stETH) and receives `uETH`.


### Operating validators

- `provideCollateral(amount)`
- `removeCollateral(amount)`
- `requestValidators(numOfValidators, maxBidPerValidator)` 
- `depositValidators(depositData[])`

Anybody can Operate a validator. They need to `provideCollateral()` in `uETH` to the smart contract, and send `requestValidators()` once auction starts. If their `maxBidPerValidator` is sufficient they will be able to `depositValidators()` and run them on the pool's behalf.  

After the Validator Auction has finished, Operator can send `depositValidators()` tx. The pool checks the withdrawal addresses, which has to match the one set by the pool (probably the pool itself) and will deposit the validator. 
After this step operator can remove remaining collateral and send `removeCollateral(amount)` 



### Running Validator auction 

- `startAuction()`
- `endAuction()`

The pool operator (or whoever) can trigger these functions. Good way how to incentivize this, is to provide a checkpoint (block number) since which can the auction be successfully triggered. This can be done only once per epoch. The triggerer will receive reward from the pool on triggering this function, the reward will increase in time as the delta between current_block and checkpoint increases.

Once `startAuction()` is triggered, the bidding process for operating the latest batch of validators is on the way. Now operators can bid with `requestValidators()`. The bidding period will be determined by certain amount of blocks (corresponding ~7days, this is mainly due to the gas effectiveness) counted from the block in which auction has been started. 
It will also set checkpoint (2 weeks / 1 month)after which the another successful `startAuction()` can be triggered and trigger `_updateRebase()`.

After auction period has ended `endAuction()` can be triggered. This will determine the $effectiveDeposit$ per validator, lock the corresponding `uETH` and allow Operators to `depositValidators()` and `removeCollateral()`.



### Triggering oracle 

- `reportSlashing(validators[])`
	- Reports Slashing Events
- `reportBadPerformance(validators[])`
	- Reports subpar Operator performance

The triggerer will receive reward from the pool on triggering this function, the reward will increase in time as the delta between the timestamp of the reported incident and the block timestamp increases. 
	- For this incentivization to work it is necessary for the Oracle to prove the timestamp too.


### Triggering rebasing update

- `_updateRebase()` `internal`

The token will be rebasing, the rebase would be similar to `stETH`.
Rebase Rate update will be triggered when `startAuction()` is triggered.  
$rebaseRate$ will be updated based on the rewards from the previous period and will slowly redistribute the accumulated rewards over the upcoming period like so: 

$$
rebaseRate = \frac{currentBalance - pastBallance}{nextRebaseBlock - currentBlock}
$$

## Mechanisms 

### Running Validators

#### Depositing 

The amount of how many validators need to be deposited will be determined by a target. Hence as the pool grows it will automatically request for validators to be Deposited. This would be done on a periodic basis(week / monthly) at which point a **validator auction** will be held.

**Setting the Target**
This can be relative as a % of pooled funds (all funds above 5%) or by absolute value(all funds above 100ETH) or a combination of the two. Reasonable approach seems to be a % target that would go down as the size of the pool increases which could start at 5% and could decrease by 10% with each doubling of the pool size. The number used here are arbitrary, the final ones would be set based on historical analysis of other pools. A mechanism similar to TWAP should be utilized to smooth out the target and make pool demands on the number of needed validators more predictable.  

- *This could be a variable controlled by the governance, once the mechanism is battle tested the governance could be set to zero address.* 

#### Validator auction
For this a Dutch auction with a uniform price (lowest winning bid) would seem to be the most reasonable. Operators simply deposit `uETH` into the pool and send tx `requestValidators(numOfValidators, maxBidPerValidator)`. For this function to be successful it requires the deposit to be sufficient. After the auction is done, Operators can deposit validators by sending tx `depositValidators`. They can also withdraw the remaining `uETH` not used for the Validator deposit. 


#### Exiting

- Validators will be automatically exited after the predefined period (year) if Operator does no action. If Operator wishes to continue running validators he needs to make sure he has enough `uETH` deposited in the pool and calls `requestValidators()`. 
	- *NOTICE* - *Operators are incentivized to continue running the existing validators, rather than depositing new once, since they save gas on depositing as well as have longer effective operation period than newly deposited validators.*

- `uETH` holders can request funds with `forceWithdraw()` from the pool. This will carry a significant fee (0.5%) to discourage user triggered exits. This will puts them first in line to receiving `ETH` from the pool. 
	- *NOTICE* - *Under normal circumstances the pool should have enough funds to honor withdrawals, without triggering exits. This should be the option of last resort and should be discouraged*
	- the pool would simply not extend the period for validators that are at the end of their yearly lifecycle
		- effects 
			- no added complexity 
			- users requesting exit must wait for 
				- ETH deposits from other users 
				- End of validators' life cycle 
	*- ?exit existing validators? (PROBABLY NOT necessary)
		- options 
			- have some pseudorandom mechanism on which validators to exit. 
				- adds more complexity to the system*


### Trustless oracle 

This design requires an oracle. For this added complexity the pool can enjoy much greater simplicity on the pool design itself, which would be dead simple. Counting balances is extremely simple + straight forward basically doing `balanceOf.address(this)`, no need to create additional contracts for each operator and keep track of their balances & performance.

After [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) which will include beacon block root in EVM this should be possible. Also Diva team is already working on this. 


**Principles**
- No oracle triggers are necessary for normal operation of the pool
- Oracle could be triggered by anyone and this action would be incentivized to cover the gas cost 


**Actions**
- Reports Slashing Events
	- If validator is slashed oracle can be triggered.
		- If successful it will reward the tx originator to provide incentives and lower the effective bond
			- *? should we exit validator at this stage? 
				- if max slashable balance is 4 before the validator is exited this does not seem to be necessary.* 
	
- Reports bad Operator performance
	- If validator is is not hitting the performance target (e.g. 99% effectivness) oracle can be triggered.
		- If successful it will reward the tx originator to provide incentives
		  
> - potential problem
> 	- cost
> 		- ? what will be a cost of these actions? 
> 		- ? how often will they be triggered?* 
> 			*- solution - we could allow for bulk reporting* 


