[DO NOT MERGE] C9 - Revised userFunds semantics across YieldManager.sol and LidoStVaultYieldProvider.sol
#1703
+477
−1,557
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Revised semantics of
userFundsandlstLiabilityPrincipalDefinition of
userFundsWe define
userFundsprecisely as “the total funds owed to Linea bridge users.”In the current audit branch implementation,
userFundsconflates two distinct concepts:total deposits - total withdrawalsin theStakingVaultReported yield
While reported yield represents circulating L2 ETH (and therefore a legitimate component of “funds owed to Linea bridge users”), the first term —
total deposits - total withdrawals— does not always accurately track "funds owed to Linea users". The discrepancy emerges when users withdraw Liquid Staking Tokens (LSTs), as shown below.Example: Divergence Scenario
Here,
funds owed to Linea bridge usersno longer equalstotal deposits - total withdrawals. According to our chosen definition ofuserFunds, we must decouple it from the StakingVault deposit/withdrawal deltas.This choice has broad accounting and design implications that cascade through related components, as detailed below.
Relationship Between
lstLiabilityPrincipalanduserFundsWhenever LST is minted,
lstLiabilityPrincipalincreases by the ETH-equivalent value of the LST issued.In the current audit branch,
lstLiabilityPrincipalis treated as an “advance” to the Linea user againstuserFunds. However, once we adopt the stricter definition ofuserFundsas “funds owed to Linea users,” this interpretation becomes invalid.Instead, during LST withdrawal,
userFundsmust decrease in proportion to the increment inlstLiabilityPrincipal.Here,
lstLiabilityPrincipalrepresents funds deposited to the StakingVault but owed to the Lido protocol. Although the vault balance remains unchanged, the system’s liabilities have shifted — now owing 100 ETH to Linea users and 100 ETH to Lido.Functions That Mutate
lstLiabilityPrincipalFour other functions can change the value of
lstLiabilityPrincipal. We analyze each in turn.YieldManager.fundYieldProviderYieldManager._withdrawWithTargetDeficitPriorityAndLSTLiabilityPrincipalReductionLidoStVaultYieldProvider.reportYieldLidoStVaultYieldProvider._initiateOssification1.
YieldManager.fundYieldProviderThis function stakes funds from the
YieldManagerinto theStakingVault, and proactively settles any outstandinglstLiabilityPrincipal.Note that once the LST principal is settled, the discrepancy between vault balance and
userFundsdisappears.2.
YieldManager._withdrawWithTargetDeficitPriorityAndLSTLiabilityPrincipalReductionThis function withdraws funds from the
StakingVaultto theYieldManager. Under our refined semantics, withdrawals must not exceeduserFunds.Before executing the withdrawal, the function prioritizes reducing outstanding LST liabilities. The LST liability amount is locked (plus an added margin determined by collateralization ratio) by the Lido protocol, and thus unavailable for withdrawal to the L1MessageService.
Because the position is overcollateralized, repaying as much LST liability principal as possible first maximizes the amount of ETH that becomes “unlocked” and withdrawable from the
StakingVault.Revised withdrawal logic:
lstLiabilityPrincipaluserFundsExample Scenario
3.
LidoStVaultYieldProvider._initiateOssificationThis function pays all outstanding Lido protocol fees, node operator fees, and LST liabilities.
These amounts are strictly separate from
userFunds, so no adjustment touserFundsis required.4.
LidoStVaultYieldProvider.reportYieldYield is defined as:
Positive Yield Handling
Negative Yield Handling
Recording & State Management:
yield < 0: The negative amount becomesoutstandingNegativeYieldwhileuserFundsremains unmodifiedAccumulation Behavior:
Protocol Safeguards:
LST Liability Management
outstandingLSTLiabilitiesencompasses both principal and interest, eliminating the need for separatelstLiabilityPrincipalhandlinglstLiabilityPrincipalas a side effect, sourced fromoutstandingLSTLiabilities(notuserFunds)userFundsto maintain proper accounting separationFunction Behaviour
yield >0: Returns(yield, 0)yield <0: Returns(0, |yield|)Summary
userFundsrepresents only funds owed to Linea bridge users.userFundsmust not be intermingled with pending LST liability, pending node operator fees, or pending Lido protocol feesuserFundsmust not be intermingled with the Vault deposit/withdrawal delta