# Zero-address recipient fund burn

Transfers, mints or sweeps whose recipient defaults to address(0) or a stale cached value

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

## How it works
A transfer, mint or sweep needs a recipient. When that recipient is never explicitly set, it falls back to a default: an unset struct field, an uninitialized variable, or a hardcoded `address(0)`. Tokens sent to `address(0)` are unrecoverable, so the funds are burned. The broken assumption is that "the recipient is always populated" — but Solidity zero-initializes everything, so any path that skips assignment silently sends value to the burn address. A second shape: a cached recipient keyed on a "previous" variable that is never reassigned, so the cache stays stale or zero [E2](https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md).

## Where it shows up
- A struct with both a top-level `to`/`_to` parameter and a per-route `receiver` field; the internal swap reads one and ignores the other [E1](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-09.md).
- Loops that cache a derived address keyed on `prevX`, where `prevX` is read in the condition but never written inside the loop [E2](https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md).
- Sweep/interest functions that call `token.transfer(address(0), balance)` instead of `redeem(...)` [E3](https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AH-03.md).
- Any `transfer`/`mint`/`safeTransfer` whose recipient argument is a struct field, a cached variable, or a literal zero.

## How to review
For every value-moving call, trace the recipient back to where it is assigned and confirm it is set on every reachable path before use. The invariant: **the recipient passed to a transfer/mint/sweep is a non-zero, freshly-computed address on all code paths.** Specifically:
- If a struct carries both a `to` parameter and a per-route `receiver`, check which one the internal function actually consumes, and whether the other is ever populated [E1](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-09.md).
- In caching loops, confirm the "previous" key variable is reassigned each iteration, and that the sentinel initial value (0) cannot collide with a real entry [E2](https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md).
- In accounting/sweep functions, confirm the function redeems or moves assets to a live address, not `address(0)` [E3](https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AH-03.md).

## How finders spotted it
- Read `_swap`, noticed it ignores the `_to` parameter and relies solely on `routes[i].receiver`; then traced route construction in the public swap functions and confirmed `receiver` is never set [E1](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-09.md).
- Reviewed a caching optimization, noticed `prevAgentId` was read in the loop condition but never written inside the loop; traced `agentTba` across iterations with a crafted array [E2](https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md).
- Read `sweepInterest`, saw `transfer(address(0), ...)` where a `redeem` was expected — an unconditional asset-destruction mistake [E3](https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AH-03.md).

## Variants seen
- Unset struct field defaults to zero; internal function uses it as recipient while ignoring the explicit `to` [E1](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-09.md).
- Stale/zero cache from a missing `prevX = x` assignment in a batch loop [E2](https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md).
- Hardcoded `address(0)` in a sweep where redeem was intended [E3](https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AH-03.md).

## Impact and severity
Total, permanent loss of the moved funds in each case: swapped tokens burned [E1](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-09.md), user tokens sent to zero or the wrong agent [E2](https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md), interest-bearing collateral destroyed and user repayments blocked [E3](https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AH-03.md). Severity is high because the loss is irreversible and hits user or protocol funds directly; impact scales with the amount routed through the affected path.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-09.md
- E2: https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-06.md
- E3: https://bugbountylibrary.com/r/c4%3A2022-06-canto%3AH-03.md
