# Allowances is double spent in BBLeverage's and SGLLeverage's `sellCollateral()`

BBLeverage/SGLLeverage sellCollateral() spends caller allowance twice (via _allowedBorrow and _repay), doubling allowance consumption and reverting correctly-sized approvals.

- Payout: Contest reward
- Severity: medium
- Program: Tapioca
- Credited: hyh
- Disclosed: 2024-02-14
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2024-02-tapioca-judging/issues/141
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-32
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** BBLeverage/SGLLeverage sellCollateral() lending market contracts
**Root cause:** sellCollateral() calls _allowedBorrow(from, share) to spend allowance for collateral removal, then _repay() also spends allowance from the same caller since msg.sender != from, deducting allowance twice.
**Steps:**
1. Call `sellCollateral(from, share, data)` where msg.sender != from with allowance set to exactly `share`.
2. Observe `_allowedBorrow(from, share)` deducts allowance once.
3. Observe `_repay(from, from, part)` re-enters allowance check and deducts again (up to double).
4. Correctly-sized allowance causes revert; user must approve ~2x.
**How found:** Code reading of sellCollateral() flow: noticed both _allowedBorrow() and _repay() spend allowance from caller, but collateral removal is unconditional so allowance should only be spent once.
**Insight:** In leverage/repay flows, check whether allowance is charged at both the collateral-removal step and the internal repay step; a shared _repay() that always checks allowance double-charges when the caller already paid at entry.
