Morpheus 審計報告分享3:StETH 的精度丟失轉賬機制
漏洞信息
漏洞報告
漏洞背景
StETH 是一種通過將 ETH 質押獲取的 rebasing token,在用戶持有的過程中余額會隨著獎勵的累加而自動增加。用戶只需要持有 StETH 就可以獲得 ETH 獎勵,持有的 StETH 數量與可贖回的 ETH 數量是幾乎相等的。
而實現這個 rebasing 功能依賴的是內部的 share 機制,share 的計算公式是
shares = ETHAmount * TotalPooledETH / TotalShares
ETH → StETH 的代碼實現是這樣的

而 StETH 的余額也是通過 shares 來計算得到的。

精度丟失問題
在進行轉賬時,會經過 StETH amount → shares → transfer shares → update StETH balance 的過程

而由于 StETH amount → shares 的環節是向下取整的,所以可能會存在在進行 transfer 時,實際收到的 StETH 數量比傳入的參數要小的情況。

舉例說明:
假設此時 StETH 中 shares : ETH = 1000 : 1500,UserA 向 UserB 進行轉賬
- UserA 持有 1500 StETH,對應 1000 shares
- Transfer 1300 StETH → shares = 1300 * 1000 / 1500 = 866.66… = 866
- UserB 收到 866 shares,對應 StETH = 866 * 1500 / 1000 = 1299
這就導致了 UserA 在調用 transfer 函數時傳入的 amount 為 1300,而 UserB 實際上收到的代幣數量為 1299。
漏洞案例
當合約對 AAVE 進行 supply 操作時,如果 token 為 StETH,可能會出現實際 supply 的 StETH 數量小于 amount_ 的值。而在后續的 deposited 和 lastUnderlyingBalance 變量計算中則是直接累加上了 amount_ 的值,使得它們的值比實際值要偏大。

而在后續的 distributeRewards() 函數中,首先會計算獲得的 aToken 數量(等于所提供的 StETH 數量),隨后用來減去 lastUnderlyingBalance。如果此時 StETH 的轉賬發生了精度丟失,且 aToken 的獎勵還沒開始累計,這個減法操作將會發生下溢出,導致操作回滾。

修復建議
其實 Morpheus 在 User 往 Morpheus 協議轉賬這個層面有考慮到這個問題,所以采用的是轉賬前后賬戶余額差值(實際到賬金額)作為 amount_ 的值。而在 Morpheus 協議向 AAVE 轉賬這個環節沒有采用這種實踐。

補充材料
由于 StETH 的 rebasing 特性,在 DeFi 協議中使用起來可能會難以處理。所以為了解決這個問題,官方提供了 warp StETH 實現,也就是 WstETH。WstETH 的余額不會發生 rebasing,只能在轉賬、鑄造和銷毀時更改。

從代碼實現來看,其實 WstETH 對應的就是 StETH 里面的 shares

浙公網安備 33010602011771號