Banked from etherfi-protocol/smart-contracts src/Liquifier.sol @ HEAD (WALK). The canonical CORRECT way to value a non-ETH LST (stETH/cbETH/wbETH) deposited to mint an ETH-pegged token (eETH) - a positive case study + the residual to check.
A protocol that accepts LST X and mints ETH-pegged token Y must price X->ETH. Two attacks on a naive valuation:
1. Depeg arbitrage: value X at 1:1 (stETH) or at X's self-reported exchangeRate() (cbETH/wbETH). If X trades on the market BELOW that (depeg/discount), buy cheap X, deposit at the higher rate, mint over-valued Y -> drain the protocol.
2. Curve/AMM flash-manipulation: if instead you value X by an on-chain AMM spot (curve.get_dy(X->ETH)), an attacker flash-loans to imbalance the pool and inflate get_dy right before depositing.
depositWithERC20 mints quoteByDiscountedValue = (10000 - discountBps) * quoteByMarketValue / 10000, and quoteByMarketValue is:
- cbETH/wbETH: min( amount * lst.exchangeRate()/1e18 , curve.get_dy(lst->ETH, amount) ) - the LOWER of the self-rate and the AMM market price.
- stETH: min( amount , curve.get_dy(stETH->ETH, amount) ) when quoteStEthWithCurve is ON - the AMM market price, CAPPED at 1:1 (never values stETH above par).
- plus a discountInBasisPoints haircut, plus per-token time-bound + total deposit CAPS, plus _min-measured amountReceived (handles stETH 1-2 wei rounding).
Why min(rate, market) + cap defeats BOTH attacks:
- Depeg: if X depegs below its self-rate, min takes the lower MARKET value -> no over-mint. Attacker gains nothing from buying cheap X.
- Curve flash-manip UP: if the attacker pumps get_dy ABOVE the self-rate (cbETH/wbETH) or above 1:1 (stETH cap), min takes the self-rate / the 1:1 cap -> the inflated AMM price is ignored.
- Curve flash-manip DOWN: pushing get_dy lower only makes min take the lower value -> the attacker mints LESS (hurts themselves).
So the min(conservative-rate, market) + hard 1:1 cap makes the mint quote MONOTONICALLY CONSERVATIVE in every manipulation direction. This is the gold-standard LST-deposit valuation. Bank as positive case study for any "deposit LST -> mint pegged token" path.
min(self-rate, market) or just ONE of them? A single-source quote (only self-rate -> depeg-arb; only AMM-spot -> flash-manip) is the lead.get_dy/getAmountsOut) or a TWAP? Spot is fine HERE only because it's wrapped in min with a conservative rate+cap; a spot AMM quote used ALONE (not min'd) would be flash-manipulable.stETH valuation is 1:1 (no market min) when quoteStEthWithCurve is OFF (admin toggle, updateQuoteStEthWithCurve onlyAdmin). If OFF during a sustained stETH depeg larger than discountInBasisPoints, depeg-arb reopens (bounded by deposit caps). cbETH/wbETH always use min (no toggle) = always protected. So the audit action: confirm quoteStEthWithCurve is ON in production OR the stETH discount+caps cover the worst plausible depeg (~5% historically). Config/operational, not a code bug - WALK with a flag.
msg.sender == l1SyncPool (the native-minting reconciliation) - not arbitrary (depositWithERC20:151).quoteByFairValue (used for TVL getTotalPooledEther) values holdings at self-rate (NOT min-market) - correct for redemption-value TVL accounting (the protocol redeems the LST 1:1 eventually); it is NOT the mint path, so it doesn't enable over-mint.