# BBLeverage's and SGLLeverage's `buyCollateral()` remove the required funds from the target twice

BBLeverage/SGLLeverage buyCollateral pulls the swapped collateral from the user twice via _addCollateral, silently double-charging them while accounting records only one deposit.

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

**Target:** BigBang/Singularity leverage markets (BBLeverage.sol, SGLLeverage.sol)
**Root cause:** LeverageExecutor.getCollateral now transfers swapped collateral directly to the market (msg.sender) instead of the user, but buyCollateral still calls _addCollateral which invokes pearlmit.transferFromERC1155 to pull the same collateralShare from the user again.
**Steps:**
1. User calls buyCollateral with borrowAmount and sufficient pearlmit allowance to the market.
2. _borrow(from, address(this), borrowAmount) borrows asset; yieldBox.withdraw sends it to leverageExecutor.
3. leverageExecutor.getCollateral swaps and transfers collateral directly to the market contract (msg.sender).
4. Market computes collateralShare, deposits it into yieldBox to itself, then calls _addCollateral(from, from, false, 0, collateralShare).
5. _addCollateral -> _addTokens -> pearlmit.transferFromERC1155(from, address(this), yieldBox, collateralId, collateralShare) pulls the same share again from the user.
6. Only one collateralShare is credited in userCollateralShare; the second transfer is lost to the user.
**How found:** Code review of buyCollateral flow: noticed getCollateral's _swapAndTransferToSender sends output to msg.sender (the market) rather than the user, yet _addCollateral still performs a pearlmit transferFromERC1155 from the user, indicating leftover legacy logic.
**Exploitation:** Any user invoking buyCollateral with an allowance to the market loses collateralShare of collateral per call; no attacker needed, loss is unconditional on each use.
**Insight:** When a helper contract's transfer destination changes (to sender vs to user), audit every downstream accounting call that also pulls tokens from the user—double-pull bugs hide where a refactor left a redundant transferFrom after funds already arrived.
