# Stale or shadowed variable restores cleared state

A local copy or shadowing variable written back over newer storage, reviving cleared flags or stale values

_Area: Smart contract access control and control flow. Seen in 2 disclosed reports; latest 2025-07-03. Updated 2026-11-02._

## How it works
A function reads a packed config word, a status flag, or a cached parameter into a local variable, then later writes that local back to storage. If something else in the same transaction already changed the real storage value, the write-back silently reverts it to the old value. The same failure happens when a local declaration shadows a contract-level variable: the intended write goes to the local and storage is never updated. Either way the contract's state and the code's belief about that state diverge, and a later read acts on the stale value.

## Where it shows up
- Functions that take a packed config word (bitfields, flags) by value and write it back to storage [E1](https://bugbountylibrary.com/r/cantina%3Ainstadapp_september2024%3A3.1.2.md)
- A helper called with an old copy of a variable that an earlier call in the same path already mutated [E1](https://bugbountylibrary.com/r/cantina%3Ainstadapp_september2024%3A3.1.2.md)
- Local declarations whose name matches a contract-level state variable in a setter or execute path [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-18.md)
- Periphery contracts that cache parameters the core contract silently overrides [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-smilee-finance%3AM-2.md)
- Governance/emission code that reads a status variable written by another function [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-18.md)

## How to review
- For every storage write of a local copy, ask: has this storage slot already been changed earlier in the same transaction? If yes, the write-back is unsafe.
- The invariant: a value written back to storage must be the current storage value plus intended changes, never a snapshot taken before other mutations.
- Grep the setter/execute path for local declarations sharing a name with state variables; a shadowed write is a no-op on storage [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-18.md).
- Compare what the core contract actually uses against what the periphery stores; any divergence in a persisted field is a bug [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-smilee-finance%3AM-2.md).
- Confirm that a flag cleared by one function cannot be re-set by a later write-back in the same call chain [E1](https://bugbountylibrary.com/r/cantina%3Ainstadapp_september2024%3A3.1.2.md).

## How finders spotted it
- Read `_getPricesAndExchangePrices` and noticed `_calcRangeShifting` received the old `dexVariables2_`, whose write-back would resurrect a bit already cleared [E1](https://bugbountylibrary.com/r/cantina%3Ainstadapp_september2024%3A3.1.2.md).
- Compared `PositionManager.mint` against `IG.mint`, saw the core discards the strike argument and uses `currentStrike`, while the periphery persists the user-supplied strike; a test with strike+1 confirmed the burn revert [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-smilee-finance%3AM-2.md).
- Code review of `execute()` spotted a local `status` shadowing the contract state variable, then traced `nudge()`'s read to confirm it never changes [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-18.md).

## Variants seen
- Stale packed-config copy written back, reviving a cleared bit and causing division by zero [E1](https://bugbountylibrary.com/r/cantina%3Ainstadapp_september2024%3A3.1.2.md)
- Periphery caching a parameter the core overrides, leaving positions unburnable [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-smilee-finance%3AM-2.md)
- Local variable shadowing a state variable, so a status write never lands [E3](https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-18.md)

## Impact and severity
E1 locked all Fluid DEX operations via division by zero, a full denial of service. E2 left user positions unburnable and funds stuck. E3 disabled the nudge/tail-emission adjustment entirely, breaking distribution control. Severity rises when the stale value gates a core operation (E1) or traps user funds (E2); a shadowed status silently disables a safety mechanism (E3).

## Evidence
- E1: https://bugbountylibrary.com/r/cantina%3Ainstadapp_september2024%3A3.1.2.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-02-smilee-finance%3AM-2.md
- E3: https://bugbountylibrary.com/r/c4%3A2025-05-blackhole%3AM-18.md
