# Timestamp guard vs stored value mismatch

Guard validates one timestamp or formula but code stores another; check every state write bumps the field

_Area: DeFi accounting and math bugs. Seen in 7 disclosed reports; latest 2024-06-25. Updated 2026-10-23._

## How it works
A protective check reads a timestamp or computed value, but the code that should keep that value current writes something else, or writes nothing. The invariant the guard assumes — "this field reflects the last change to the protected state" — is false. Either the validated expression differs from the stored one, or a mutating path skips the field entirely, so the guard passes when it should fail.

## Where it shows up
- A function computes `block.timestamp + duration` for a check but stores `lastLockTime + duration` [E2](https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AH-02.md).
- State-mutating functions (collateral changes, debt accrual) that alter a health metric but do not refresh a `updatedAt`/version field [E1](https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AH-07.md)[E4](https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AM-09.md).
- State machines entering a time-dependent state (Late, grace period) without initializing its timestamp, leaving it zero [E3](https://bugbountylibrary.com/r/sherlock%3A2023-02-carapace%3AM-5.md).
- Any buffer/grace check of the form `field + window <= now` where `field` is set in only some code paths.

## How to review
- For each guard, identify the exact field it trusts and the property it needs: "field is bumped on every mutation of the protected quantity."
- Enumerate every function that mutates that quantity (collateral, debt, CR, lock state) and confirm each one updates the trusted field.
- Diff the validated expression against the stored expression line by line; they must be identical [E2](https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AH-02.md).
- For state transitions, confirm every entry into a timed state sets its timestamp, including first-entry from uninitialized states [E3](https://bugbountylibrary.com/r/sherlock%3A2023-02-carapace%3AM-5.md).

## Variants seen
- Collateral decrease skips `updatedAt`, enabling dispute of valid proposals [E1](https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AH-07.md).
- Bad-debt application via `proposeRedemption` skips `updatedAt` on out-of-scope records [E4](https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AM-09.md).
- Validated `block.timestamp` vs stored `lastLockTime` [E2](https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AH-02.md).
- Late-state entry without `lateTimestamp`, instant default [E3](https://bugbountylibrary.com/r/sherlock%3A2023-02-carapace%3AM-5.md).

## Impact and severity
Led to theft of proposer penalty fees [E1](https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AH-07.md)[E4](https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AM-09.md), early unlock of locked funds [E2](https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AH-02.md), and instant default of lending pools bypassing grace periods [E3](https://bugbountylibrary.com/r/sherlock%3A2023-02-carapace%3AM-5.md). Severity is high where the bypass yields direct fund loss or unlocks; worse when the stale field is reachable from a public entrypoint on records outside the caller's scope.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AH-07.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-05-munchables%3AH-02.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2023-02-carapace%3AM-5.md
- E4: https://bugbountylibrary.com/r/c4%3A2024-03-dittoeth%3AM-09.md
