# Unchecked transfer and lossy redeem locks funds

Ignored transfer return values, lossy ERC-4626 redeem, and mid-path amount caps that strand tokens

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2025-01-08. Updated 2026-11-02._

## How it works
Bookkeeping assumes a transfer or redemption delivers exactly what was asked. That assumption breaks in three ways: an ERC-20 `transfer` may return `false` instead of reverting; an ERC-4626 `redeem` only guarantees shares are burned, not that the requested assets arrive; and a swap or router may silently consume less than the amount handed to it. In each case the contract's internal accounting (shares burned, amount approved, amount extracted) advances while the real token balance does not, so value is stranded in the contract with no path to recover it.

## Where it shows up
- Share burn or redeem followed by `_asset.transfer(...)` whose boolean return is discarded [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- `redeem(previewWithdraw(assets))` against a yield vault that can return fewer assets than requested [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- Swap helpers that clamp an intermediate amount (e.g. to `maxSwap[path[1]]`) before the next hop, with no sweep of the residual [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-peapods-finance%3AM-23.md)
- Integrations (Stargate-style routers) where the amount passed must be a multiple of a `convertRate`; unrounded amounts leave dust and live allowances [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md)
- Any code that extracts or approves a full amount but the downstream consumer takes only part of it [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md)

## How to review
State the invariant: after every burn, redeem, swap or router call, the contract's token balance must equal what the accounting says it should, and no approved amount may exceed what the callee actually consumes. Check:
- Is every ERC-20 `transfer`/`transferFrom` return value checked, or is a safe wrapper used? [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- After a redeem, is the actually-received asset amount measured and reconciled against the requested amount before shares are burned? [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- For multi-hop swaps, is any mid-path cap followed by recovery of the leftover intermediate balance? [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-peapods-finance%3AM-23.md)
- Are amounts sent to rate-constrained routers rounded down to the required multiple, and are allowances reset to zero afterward? [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md)

## How finders spotted it
- Read the two-hop branch of `_swapV2`, noticed the intermediate balance was clamped to `maxSwap` and only that portion swapped, with no sweep of the remainder [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-peapods-finance%3AM-23.md)
- Reasoned from the ERC-20 spec (transfer need not revert) and ERC-4626 spec (redeem need not deliver assets), then combined both corner cases into a proof of concept with a mock non-reverting token and a lossy vault [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- Reasoned about Stargate `convertRate` semantics (shared vs local decimals) and traced how rebalance extracts and approves amounts without rounding [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md)

## Variants seen
- Ignored boolean return on a lossy transfer after burning all shares [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- Lossy ERC-4626 redeem combined with a non-reverting token [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md)
- Mid-path swap cap stranding intermediate tokens [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-peapods-finance%3AM-23.md)
- Unrounded router amount leaving dust and dangling allowances [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md)

## Impact and severity
User funds become permanently stuck in the contract: burned shares with no assets delivered [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md), stranded intermediate tokens [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-peapods-finance%3AM-23.md), or dust plus live allowances left after a rebalance [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md). Severity is raised when a lossy upstream (vault or token) is combined with unchecked returns, since neither failure alone reverts and the loss is silent [E2](https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md).

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2025-01-peapods-finance%3AM-23.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-03-pooltogether%3AM-06.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2024-02-tapioca%3AM-15.md
