Assessment reports>Lido Fixed Income>Medium findings>Variable-side yield on yield is unfairly split
Category: Protocol Risks

Variable-side yield on yield is unfairly split

Medium Severity
Medium Impact
High Likelihood

Description

During a vault's lifetime, the staked stETH grows due to Lido yield, and that stETH belongs to the variable-side depositors. At any time, a variable-side depositor can request the disbursement of their share of the gains from that yield:

function withdraw(uint256 side) external {
  // [...] [ case !isEnded() && side == VARIABLE ]

  uint256 lidoStETHBalance = stakingBalance();
  uint256 fixedETHDeposits = fixedETHDepositTokenTotalSupply;

  // staking earnings have accumulated on Lido
  if (lidoStETHBalance > fixedETHDeposits) {
    (uint256 currentState, uint256 ethAmountOwed) = calculateVariableWithdrawState(
      (lidoStETHBalance - fixedETHDeposits) + withdrawnStakingEarnings + totalProtocolFee,
      variableToWithdrawnStakingEarnings[msg.sender].mulDiv(10000, 10000 - protocolFeeBps)
    );

    if (ethAmountOwed >= minStETHWithdrawalAmount()) {
      // estimate protocol fee and update total - will actually be applied on withdraw finalization
      uint256 protocolFee = ethAmountOwed.mulDiv(protocolFeeBps, 10000);
      totalProtocolFee += protocolFee;

      withdrawnStakingEarnings += ethAmountOwed - protocolFee;
      variableToWithdrawnStakingEarnings[msg.sender] = currentState - currentState.mulDiv(protocolFeeBps, 10000);

      variableToVaultOngoingWithdrawalRequestIds[msg.sender] = requestWithdrawViaETH(
        msg.sender,
        ethAmountOwed
      );

Consider this early partial-withdrawal decision from a variable-side depositor's perspective. If Alice, a variable-side depositor, is allowed to withdraw 1 ETH of value currently held in stETH but chooses not to, then that 1 stETH continues to earn yield from Lido. The longer the duration of the vault, the more this compounding effect increases total yield percentage.

However, if Alice does not withdraw from the vault, then the compounded value is not actually given to her; it is currently not distinguished from yields earned on the original principal, which means it is evenly (based on deposit) distributed across all variable depositors. So, Alice will favor withdrawing the partial value immediately whenever she can (notwithstanding the Lido minimum withdrawal and the price of gas), in order to restake that in Lido herself and get the full amount of yield on that yield.

Impact

This means that all profit-maximizing active variable-side investors should withdraw as often as possible, which ultimately decreases net yield due to stETH not earning interest while in the withdrawal queue. Additionally, this effect is unfriendly to passive investors and causes users to have to spend more gas.

Recommendations

A more succinct description of the underlying mathematical miscalculation is that withdrawnStakingEarnings is a fixed quantity denominated in past stETH, a quantity that does not change as the Lido share price changes. If Lido earns yield and does not default, then the share price should gradually be increasing, so past stETH should be worth more than present stETH, so keeping withdrawnStakingEarnings constant results in more value being allocated to any early withdrawer.

Instead of denominating withdrawnStakingEarnings in ETH, it should be denominated in Lido shares to better represent the permanent withdrawal of future earnings that a present variable-side withdrawal causes. Whenever the withdraw function is called, it should calculate the total amount of Lido shares, originally entirely owned by the fixed side, that the entire variable side is entitled to using the current share price, and allow a withdrawal of the rest of the Lido shares that a particular variable depositor is entitled to (subtracting out the Lido shares they have already withdrawn).

Remediation

Zellic © 2024Back to top ↑