# Call semantics and return value mismatches

Ignored return values, wrong call vs delegatecall, and post-conditions checked against the wrong token or balance

_Area: DeFi accounting and math bugs. Seen in 9 disclosed reports; latest 2024-08-05. Updated 2026-10-23._

## How it works
A contract assumes an external call did what it was supposed to, but the call's semantics or result don't match that assumption. Three shapes recur: the success/revert of a low-level call is ignored, so a failed action looks like success; a helper is invoked with `call` when it was written to act on the caller's balances via `delegatecall`, so it operates on the wrong context; or a post-condition is checked against a different asset than the one actually moved. In each case the contract's bookkeeping (balances, allowances, share counts) diverges from reality, and later logic trusts the wrong number.

## Where it shows up
- Low-level `.call{value:...}("")` whose success bool is never checked before continuing.
- `abi.decode` of an attacker-supplied revert payload inside a `catch` block, without validating offset/length.
- Helper/swapper contracts designed to run via `delegatecall` but invoked with a normal external call.
- Post-trade checks comparing native ETH delta while the trade actually spent/approved a wrapped token.
- ERC4626-style `maxRedeem`/`maxWithdraw` that only return a balance and never trigger the underlying redeem.
- Residual allowances left on external marketplaces after a swap.

## How to review
For every external call, ask: is the result consumed, and does the callee's execution context match its design? The invariant: after any state-changing external call, the contract's recorded balances/allowances must equal the actual on-chain state, and a failed call must abort the flow. Concretely: confirm low-level call success is checked or a typed call (`submit{value:}`) is used; confirm delegatecall-vs-call matches how the helper accesses funds; confirm post-conditions measure the token actually approved/spent; confirm redeem/withdraw paths invoke the underlying protocol rather than returning a view balance.

## Variants seen
- Swallowed revert on stETH deposit leaves ETH unstaked and user funds lost [E5](https://bugbountylibrary.com/r/c4%3A2024-06-badger%3AM-02.md).
- Malformed revert data makes error-handling itself revert, blocking keeper actions [E1](https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AH-16.md).
- Normal call to a delegatecall-designed swapper traps rewards [E3](https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AH-3.md).
- Post-trade check on ETH while WETH allowance remains spendable [E2](https://bugbountylibrary.com/r/c4%3A2023-05-particle%3AM-04.md).
- `maxRedeem` returns balance without redeeming, stranding PT [E4](https://bugbountylibrary.com/r/c4%3A2022-06-illuminate%3AH-16.md).

## Impact and severity
Funds trapped or lost, liquidations/redeems permanently reverting, and free spends via leftover allowances [E2](https://bugbountylibrary.com/r/c4%3A2023-05-particle%3AM-04.md)[E3](https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AH-3.md)[E4](https://bugbountylibrary.com/r/c4%3A2022-06-illuminate%3AH-16.md)[E5](https://bugbountylibrary.com/r/c4%3A2024-06-badger%3AM-02.md). Severity rises when the failure is silent (no revert) or blocks a keeper path, since funds stay stuck rather than failing loudly [E1](https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AH-16.md)[E5](https://bugbountylibrary.com/r/c4%3A2024-06-badger%3AM-02.md).

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2023-02-gmx%3AH-16.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-05-particle%3AM-04.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-06-tokemak%3AH-3.md
- E4: https://bugbountylibrary.com/r/c4%3A2022-06-illuminate%3AH-16.md
- E5: https://bugbountylibrary.com/r/c4%3A2024-06-badger%3AM-02.md
