# `mTOFT` can be forced to receive the wrong ERC20 leading to token lockup

Balancer.rebalance decodes unvalidated src/dst poolIds from _ercData, letting a keeper swap into a mismatched token that the destination mTOFT cannot use, locking funds.

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

**Target:** Balancer.sol rebalance/_sendToken/_routerSwap Stargate router swap
**Root cause:** _sendToken abi.decodes _srcPoolId/_dstPoolId from caller-supplied _ercData and passes them straight to router.swap without checking they match the OFT's actual token; initConnectedOFT stores poolIds but rebalance never enforces them.
**Steps:**
1. Keeper calls `rebalance(srcOft, dstChainId, slippage, amount, ercData)` where srcOft is the USDC mTOFT on Ethereum.
2. ercData encodes `(srcPoolId=USDC pool, dstPoolId=USDT pool on Avalanche)`.
3. _sendToken decodes these and calls `_routerSwap` -> `router.swap(dstChainId, srcPoolId, dstPoolId, ...)` with no validation.
4. Stargate takes USDC on Ethereum and delivers USDT on Avalanche to the destination mTOFT whose erc20 is USDC.
5. USDT sits as an unusable balance in the mTOFT contract, irreversibly locked.
**How found:** Code reading of Balancer.sol: noticed _ercData is decoded and forwarded to the Stargate router without cross-checking against the poolIds saved in initConnectedOFT, combined with knowledge that Stargate supports cross-token swaps between correlated stablecoins.
**Exploitation:** Requires the trusted rebalancer/keeper to submit mismatched poolIds (or a compromised/decentralized keeper operator). The swap executes and the wrong token is delivered to the destination mTOFT, where it is stranded since the contract only handles its configured erc20.
**Insight:** When a contract stores trusted config (poolIds) at init but a later function accepts the same parameters from calldata, check whether the runtime path re-validates against stored config; Stargate's cross-token swap paths make mismatched poolIds silently deliver a different asset.
