# Incorrect math means data.removeAndRepayData.removeAssetFromSGL will never work once SGL has accrued interest

MagnetarOptionModule passes a YieldBox share amount to Singularity.removeAsset, which expects a fraction, so removeAssetFromSGL breaks once SGL accrues interest.

- Payout: Contest reward
- Severity: high
- Program: Tapioca DAO
- Credited: GalloDaSballo
- Disclosed: 2024-05-23
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-02-tapioca-findings/issues/91
- Library page: https://bugbountylibrary.com/r/c4%3A2024-02-tapioca%3AH-07
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:precision-loss

**Target:** MagnetarOptionModule.removeAssetFromSGL / Singularity SGLCommon._removeAsset
**Root cause:** Code converts _removeAmount to a YieldBox share via yieldBox_.toShare and passes it as the fraction argument to singularity_.removeAsset, but Singularity interprets fraction against elastic + borrowed shares, so the two units diverge once interest accrues.
**Steps:**
1. Call Magnetar removeAndRepayData with removeAssetFromSGL set and _removeAmount > 0.
2. Observe share = yieldBox_.toShare(_assetId, _removeAmount, false) computed in YieldBox units.
3. singularity_.removeAsset(user, to, share) treats share as a fraction of totalAsset.base.
4. In SGLCommon._removeAsset, share = (fraction * allShare) / _totalAsset.base where allShare = elastic + toShare(totalBorrow.elastic).
5. After any interest accrual, fraction != intended share, so the removal reverts or removes wrong amount.
**How found:** Noticed the argument passed to removeAsset is a YieldBox share while Singularity's _removeAsset signature expects a fraction, then compared the two conversion formulas and wrote a Foundry PoC showing fraction and share diverge after interest.
**Insight:** When a protocol layers a rebasing market (Singularity) over a share-based vault (YieldBox), audit every boundary where a value crosses between the two unit systems; a toShare() result passed into a fraction parameter silently breaks once elastic != base.
