# transferNotionalFrom doesn't check from != to

VaultTracker.transferNotionalFrom lacks a from!=to check, so self-transfer overwrites the from balance with the to balance, minting unbacked notional.

- Payout: Audit contest
- Severity: high
- Program: Swivel
- Found by: gpersoon
- Disclosed: 2021-11-05
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-09-swivel-findings/issues/65
- Library page: https://bugbountylibrary.com/r/c4%3A2021-09-swivel%3AH-03
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** VaultTracker.sol / MarketPlace.transferVaultNotional (Solidity smart contract)
**Root cause:** transferNotionalFrom loads vaults[f] and vaults[t] into memory, mutates them, then writes vaults[f]=from and vaults[t]=to; when f==t the second write clobbers the decremented balance with the incremented one.
**Steps:**
1. Call MarketPlace.transferVaultNotional(u, m, t, a) with t == msg.sender (the from address).
2. MarketPlace forwards to VaultTracker.transferNotionalFrom(msg.sender, t, a) where f == t.
3. Inside, `from` and `to` both alias vaults[f]; from is decremented, to is incremented.
4. `vaults[f] = from` then `vaults[t] = to` overwrites the decrement, leaving only the increase.
5. Repeat to inflate notional balance arbitrarily.
**How found:** Code review of the memory-variable write-back pattern in transferNotionalFrom: noticing that from and to are cached in memory and written back separately, so aliasing f==t causes the second write to overwrite the first.
**Exploitation:** Any user calls transferVaultNotional with their own address as both sender and recipient; the self-transfer nets a positive balance increase instead of a no-op, effectively printing notional that can be redeemed.
**Insight:** When a function caches storage structs into memory locals and writes them back, check for aliasing (from==to, same id) — the later write silently discards the earlier mutation, turning a no-op transfer into a mint.

