# Non-standard token return and transfer semantics

ERC20/native assumptions in transfers, approvals, balance checks, and event emission that break on real tokens

_Area: DeFi accounting and math bugs. Seen in 26 disclosed reports; latest 2026-09-11. Updated 2026-10-22._

## How it works
Code assumes every asset behaves like a plain ERC20: transfers return a bool, `approve` sets an exact allowance, `balanceOf` works on the asset address, and a transfer helper moves value. Real tokens and native currency break these assumptions. When the code trusts the assumption instead of the actual outcome, bookkeeping diverges from reality: events claim a transfer that failed, approvals leave spendable residue, or a path reverts and locks funds.

## Where it shows up
- Transfer helpers that hardcode `value=0` (e.g. Solady `safeTransfer`) on paths that may hold native ETH [E6](https://bugbountylibrary.com/r/cantina%3Adoppler%3A3.1.3.md)
- `IERC20(asset).balanceOf` / `transfer` called where `asset` may be the native sentinel [E3](https://bugbountylibrary.com/r/sherlock%3A2025-07-mellow-flexible-vaults%3AH-3.md)
- `approve` of an amount larger than the downstream contract actually pulls [E5](https://bugbountylibrary.com/r/sherlock%3A2025-05-dodo-cross-chain-dex%3AM-1.md)
- Allowance revocation after a user-directed swap that can target the protocol's own pool [E4](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-5.md)
- Events emitted on failure/refund branches with the original intended recipient [E1](https://bugbountylibrary.com/r/c4%3A2024-06-thorchain%3AH-02.md)
- ERC165 dispatch that checks one interface before another for dual-standard tokens [E2](https://bugbountylibrary.com/r/c4%3A2022-06-infinity%3AH-06.md)
- Loops over a registry of external dependencies with no removal path [E7](https://bugbountylibrary.com/r/c4%3A2023-03-asymmetry%3AH-03.md)
- Token lists consumed in one path but special-cased in another [E8](https://bugbountylibrary.com/r/sherlock%3A2023-07-blueberry%3AM-10.md)

## How to review
For each asset-moving path, confirm the code reflects the actual result, not the intended one:
- Every failure/refund branch emits fields matching the real recipient and amount [E1](https://bugbountylibrary.com/r/c4%3A2024-06-thorchain%3AH-02.md).
- Approved amount equals what the spender pulls; no residual allowance on a contract holding balances [E5](https://bugbountylibrary.com/r/sherlock%3A2025-05-dodo-cross-chain-dex%3AM-1.md).
- Revocation cannot target a spender the protocol itself relies on [E4](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-5.md).
- Native-asset paths use `address(this).balance` and value-bearing calls, not ERC20 calls [E3](https://bugbountylibrary.com/r/sherlock%3A2025-07-mellow-flexible-vaults%3AH-3.md)[E6](https://bugbountylibrary.com/r/cantina%3Adoppler%3A3.1.3.md).
- Interface dispatch matches the token's actual transfer semantics and quantity [E2](https://bugbountylibrary.com/r/c4%3A2022-06-infinity%3AH-06.md).
- Every registry entry can be disabled/removed so one bad dependency cannot revert the loop [E7](https://bugbountylibrary.com/r/c4%3A2023-03-asymmetry%3AH-03.md).
- Every token in a reward/withdraw list is handled the same way across all paths [E8](https://bugbountylibrary.com/r/sherlock%3A2023-07-blueberry%3AM-10.md).

## Variants seen
- Failed native send still logged as success [E1](https://bugbountylibrary.com/r/c4%3A2024-06-thorchain%3AH-02.md)
- Dual ERC721/ERC1155 token routed to wrong transfer, wrong quantity [E2](https://bugbountylibrary.com/r/c4%3A2022-06-infinity%3AH-06.md)
- Native asset queried via ERC20 `balanceOf`, blocking withdrawal [E3](https://bugbountylibrary.com/r/sherlock%3A2025-07-mellow-flexible-vaults%3AH-3.md)
- Allowance revoked on protocol's own pool, blocking deposits [E4](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-5.md)
- Over-approval leaves spendable residue, drains refunds [E5](https://bugbountylibrary.com/r/sherlock%3A2025-05-dodo-cross-chain-dex%3AM-1.md)
- `safeTransfer` with zero value cannot move native ETH [E6](https://bugbountylibrary.com/r/cantina%3Adoppler%3A3.1.3.md)
- Unremovable reverting derivative DoSes unstake [E7](https://bugbountylibrary.com/r/c4%3A2023-03-asymmetry%3AH-03.md)
- Non-transferable stash token transferred directly, locking deposits [E8](https://bugbountylibrary.com/r/sherlock%3A2023-07-blueberry%3AM-10.md)

## Impact and severity
Outcomes range from locked user funds [E3](https://bugbountylibrary.com/r/sherlock%3A2025-07-mellow-flexible-vaults%3AH-3.md)[E7](https://bugbountylibrary.com/r/c4%3A2023-03-asymmetry%3AH-03.md)[E8](https://bugbountylibrary.com/r/sherlock%3A2023-07-blueberry%3AM-10.md) and permanently blocked deposits [E4](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-5.md), to drained contract balances [E5](https://bugbountylibrary.com/r/sherlock%3A2025-05-dodo-cross-chain-dex%3AM-1.md) and off-chain accounting recording transfers that never happened [E1](https://bugbountylibrary.com/r/c4%3A2024-06-thorchain%3AH-02.md). Severity rises when the contract holds refund/other-user balances (residual allowance becomes a spendable budget) and when a single bad dependency or token sits in a shared loop or list, turning one failure into a protocol-wide lockout.

## Why fixes fail
Special-casing a token in one path (AuraSpell) while another path (WAuraPools) still transfers it directly leaves the bug live [E8](https://bugbountylibrary.com/r/sherlock%3A2023-07-blueberry%3AM-10.md). Treating allowance revocation as always-safe ignores that the revoked spender may be the protocol's own pool [E4](https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-5.md).

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2024-06-thorchain%3AH-02.md
- E2: https://bugbountylibrary.com/r/c4%3A2022-06-infinity%3AH-06.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2025-07-mellow-flexible-vaults%3AH-3.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2025-06-notional-exponent%3AM-5.md
- E5: https://bugbountylibrary.com/r/sherlock%3A2025-05-dodo-cross-chain-dex%3AM-1.md
- E6: https://bugbountylibrary.com/r/cantina%3Adoppler%3A3.1.3.md
- E7: https://bugbountylibrary.com/r/c4%3A2023-03-asymmetry%3AH-03.md
- E8: https://bugbountylibrary.com/r/sherlock%3A2023-07-blueberry%3AM-10.md
