# Same-timestamp checkpoint key collision

Multiple writes sharing one timestamp or key overwrite each other, corrupting checkpoints, votes, or balances

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2025-11-20. Updated 2026-10-24._

## How it works
Checkpoint and persistence code assumes each write gets a unique timestamp or key. When several writes happen in one block, transaction, or clock tick, they share that value. The later write either overwrites the earlier record or appends a duplicate entry under the same key. Readers that binary-search or take the latest entry then return a value that does not reflect all the writes, so the stored accounting diverges from reality.

## Where it shows up
- Checkpoint writers that append a new entry per call without batching by `block.timestamp` [E1](https://bugbountylibrary.com/r/c4%3A2022-09-nouns-builder%3AH-03.md).
- Epoch counters incremented unconditionally, even when the new point has the same timestamp as the last [E2](https://bugbountylibrary.com/r/c4%3A2025-10-hybra-finance%3AM-08.md).
- Database or map keys derived solely from a clock value (nanoseconds, seconds) [E3](https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AM-04.md).
- Loops or chunking that emit many records within one tick [E3](https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AM-04.md).
- Readers using binary search over timestamps or reading only the latest epoch [E1](https://bugbountylibrary.com/r/c4%3A2022-09-nouns-builder%3AH-03.md)[E2](https://bugbountylibrary.com/r/c4%3A2025-10-hybra-finance%3AM-08.md).

## How to review
Identify every write path and its key. The invariant: for any timestamp or key, at most one record exists, and it holds the aggregate of all writes at that time. Check whether writers batch same-timestamp updates into the existing entry rather than appending. For readers, confirm the lookup returns the correct value when duplicates could exist. Compare a multi-call path against a single-call path that should reach the same end state; any divergence is a bug [E2](https://bugbountylibrary.com/r/c4%3A2025-10-hybra-finance%3AM-08.md). For persistence, confirm the key includes a non-clock component (sequence, hash, index) [E3](https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AM-04.md).

## Variants seen
- Vote checkpoints: multiple same-block writes make `getPastVotes` return wrong weight [E1](https://bugbountylibrary.com/r/c4%3A2022-09-nouns-builder%3AH-03.md).
- ve-style escrow: same-timestamp lock and increase create a duplicate epoch, understating balance and rewards [E2](https://bugbountylibrary.com/r/c4%3A2025-10-hybra-finance%3AM-08.md).
- Off-chain DB: nanosecond-timestamp key collides across batches, dropping pending messages [E3](https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AM-04.md).

## Impact and severity
Wrong vote weight enables governance manipulation [E1](https://bugbountylibrary.com/r/c4%3A2022-09-nouns-builder%3AH-03.md); understated voting power and rewards shortchange users [E2](https://bugbountylibrary.com/r/c4%3A2025-10-hybra-finance%3AM-08.md); dropped messages cause skipped broadcasts and lost transactions [E3](https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AM-04.md). Severity rises when the collision is attacker-triggerable (spamming checkpoints) or silently corrupts persisted state that later restarts rely on.

## Why fixes fail
Evidence does not show incomplete fixes.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2022-09-nouns-builder%3AH-03.md
- E2: https://bugbountylibrary.com/r/c4%3A2025-10-hybra-finance%3AM-08.md
- E3: https://bugbountylibrary.com/r/c4%3A2025-01-initia-rollup-modules%3AM-04.md
