# BaseTOFTLeverageModule.sol: leverageDownInternal tries to burn tokens from wrong address

In Tapioca's BaseTOFTLeverageModule, leverageDownInternal burns TOFT from msg.sender (the LZ endpoint) instead of address(this), so all cross-chain leverage-down calls revert.

- Payout: Contest reward
- Severity: high
- Program: Tapioca DAO
- Credited: carrotsmuggler
- Disclosed: 2023-11-16
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-07-tapioca-findings/issues/1034
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-33
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** BaseTOFTLeverageModule.sol cross-chain leverage-down handler (LayerZero tOFT)
**Root cause:** _unwrap calls _burn(msg.sender, amount), but under delegatecall from _nonblockingLzReceive msg.sender is the LayerZero endpoint, while the credited TOFT balance sits in address(this).
**Steps:**
1. Chain A: user calls BaseTOFT.sendForLeverage, delegatecalls BaseTOFTLeverageModule.sendForLeverage, sends LZ message
2. Chain B: lzEndpointB calls BaseTOFT._nonblockingLzReceive, delegatecalls leverageDown, which delegatecalls leverageDownInternal
3. In leverageDown, contract credits itself: `_creditTo(_srcChainId, address(this), amount)`
4. leverageDownInternal calls `_unwrap(address(this), amount)` which executes `_burn(msg.sender, _amount)`
5. msg.sender is lzEndpointB holding zero TOFT, so burn reverts and the whole cross-chain call fails
**How found:** Traced the delegatecall chain from sendForLeverage through _nonblockingLzReceive to leverageDownInternal to determine the actual msg.sender, then compared it against where leverageDown credits the TOFT balance (address(this)).
**Insight:** In delegatecall-based cross-chain handlers, msg.sender is preserved from the entrypoint (the LZ endpoint), not the calling contract; always verify which address actually holds credited balances versus what _burn/_transfer uses as msg.sender.
