Consider transferring stETH instead of ETH
At a very high level, the LidoVault contract implements a way for fixed-side and variable-side depositors to trustlessly coordinate and execute a mutually beneficial interest-rate swap on underlying stETH held by the contract.
The way this contract is implemented draws heavily from the assumption that the users of the contract will only handle native ETH, and so the contract is the only party interacting with Lido to stake the ETH into stETH, to hopefully generate the yield, and then unstake the stETH via the withdrawal queue to pay users back in ETH.
Contract complexity
However, we would like to point out that much of this contract's complexity come from this hard requirement. Specifically,
The withdrawal process from stETH to native ETH requires using the Lido withdrawal queue, which incurs a time delay of one or more days, typically.
This time delay means withdrawals must be finalized asynchronously, and this happens independently of the vault's start-end timeline, which adds considerable business-logic complexity.
During the withdrawal process, Lido can potentially default, and withdrawals are not guaranteed to return all of the value transferred when the withdrawal was initiated. Moreover, since stETH does not earn interest while it is in the withdrawal queue, any use of the withdrawal queue means counterparty risk is incurred without being paid for.
All fixed-side early withdrawals must be finalized before any variable-side depositor can withdraw due to the early exit fee being calculated after the withdrawal. This means the vault-finalization process cannot be constant-time without even more complex logic.
Economical inefficiencies
On the other hand, we would like to note that this requirement is actually not fundamentally necessary to implement the financial instrument the vault is supposed to implement. Specifically,
While stETH is in the withdrawal queue, it does not earn interest, which means that whenever an amount of stETH would be transferred to the withdrawal queue, it is not any more risky to just transfer it away to a user.
Users, even nontechnical users, are likely familiar with stETH as an ERC-20 token and probably have no issues manipulating it. If user-friendliness is a concern, we would recommend implementing a second, less-trusted forwarder contract whose role is to either stake or implement the unstaking of stETH (handling later asynchronous claim calls) on behalf of users who need this functionality.
Users who receive stETH from the contract for any reason can choose to swap it on the open market for ETH, instead of using the withdrawal queue, which saves them the opportunity cost of interest during the time it spends in the withdrawal queue.
If the vault both sent users stETH and took deposits in stETH, there would be no downtime for any user, variable or fixed, who wishes to continuously use the LidoVault. In the current implementation, a user who wants to continuously use Saffron's product would have to wait for stETH to be withdrawn only to immediately cause it to be deposited again by their next LidoVault. This is inefficient and also makes the implementation of perpetuals, mentioned later in the Saffron roadmap, easier.
Specific recommendations
More specifically, for all of the above reasons, we recommend the following:
Allow initial fixed deposits in stETH.
During the deposit process, fixed-side depositors should have the option of depositing stETH instead of submitting native ETH and having the contract call lido.submit
. This does not add any risk to anybody, because the contract currently unconditionally calls lido.submit
and only increases flexibility.
Allow initial fixed withdrawals in stETH.
Before the vault starts, if a fixed depositor wishes to back out, they should be able to immediately withdraw stETH. In the current implementation, these users are entitled to the entire amount of native ETH obtained after the withdrawal of a fixed amount of stETH completes, so directly transferring that stETH to the user makes no difference risk-wise to any other party. Meanwhile, it decreases the risk for the caller since they gain the option of externally swapping the stETH for ETH.
Allow ongoing fixed withdrawals in stETH by charging the early exit fee in stETH.
During the vault's active period, if a fixed depositor wishes to back out, if the early exit fee is charged in stETH, the caller can immediately be given stETH corresponding to their original deposit, minus the early exit fees.
This does change the economic design, because in the current design, if a fixed depositor requests withdrawal, and then before the withdrawal queue cycles once, Lido defaults, then the fixed depositor pays for that default out of value they would have obtained from the withdrawal due to the fee being denominated in ETH now being a larger proportion of the withdrawn native ETH.
However, this risk overlaps with risk that the fixed depositor was already compensated for. Since variable depositors can immediately withdraw their share of any value in the contract as a whole that is above the fixed deposit capacity, assuming that variable depositors always withdraw whenever there is yield to withdraw, this is not actually bad.
Moreover, if the next recommendation is implemented, and variable depositors can withdraw their share of the early exit fee in stETH, then any variable depositor who becomes concerned about a Lido default can themselves withdraw that value and put it through the Lido withdrawal queue if they wish.
Allow ongoing and after-ending variable withdrawals in stETH by charging protocol fees in stETH.
During the vault's active period and after the vault finishes, protocol fees should be charged in stETH.
The protocol fee is charged as a percentage of variable-side rewards. Therefore, no matter what the Lido share price actually is, because multiplication is commutative, charging it in stETH is equivalent to the current design of charging it in native ETH.
So, variable depositors gain the flexibility of externally swapping stETH for ETH instead of having to lock it up. The protocol-fee receiver also gains this flexibility.
Allow after-ending fixed withdrawals in stETH.
After the vault period has ended, fixed-side depositors should be given their deposit back in stETH rather than ETH.
This significantly changes the economic design, because in the current design, if Lido defaults while the vault finalization withdrawal is in the withdrawal queue, fixed-side users are still entitled to their original deposit in ETH after it is all finalized.
However, this does not actually change the economic design under the assumption that variable-side depositors continuously withdraw from the vault whenever there is value to be withdrawn.
Therefore, the only major benefit that fixed-side depositors get out of the current design, which they would not get if the vault were settled in stETH without using the withdrawal queue, is the benefit of insurance during the extra risk during the finalization process. This extra risk is something that variable-side depositors can freely opt out of donating to the fixed side, if they notice this economic discontinuity and make sure to send in a withdrawal right before the vault ends.
Summary
In summary, currently, the design of the LidoVault mandates the depositing of native ETH into Lido at the start, and it mandates the use of the withdrawal queue before any value can be taken out. However, we believe it is a better design to have the vault transact in stETH as much as possible, except for the fixed upfront premium.
If all of the above suggestions are taken, then the vault's business logic can be simplified considerably, because the vault no longer needs to deposit or withdraw Lido shares at all.
In order to maintain user-friendliness, if having users manipulate stETH is a significant concern, then a separate multicall-like contract can be deployed that handles holding a balance of Lido shares on behalf of users, depositing ETH into stETH, and claiming native ETH from the withdrawal queue after the owner of those stETH shares call for their withdrawal. This allows the withdrawal timeline to be managed completely independently from the LidoVault timelines and lifecycles, which improves usability and reduces the risk of implementation errors.