KeeperHub / KeeperHub/keeperhub
simulate-sequence keeps a slot an earlier call cleared, so a drained allowance simulates as available
- Dominant language
- TypeScript
- Stars
- 24
- Forks
- 93
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 253
Description
`simulateCallSequence`'s state-overrides fallback accumulates each call's writes by merging the `prestateTracer` diff into an override map (`mergeDiffIntoOverrides`, `lib/execute/simulate-sequence.ts:311-339`). The merge is additive: it copies every slot present in `post.storage` over the accumulator and leaves every other slot alone.
geth never reports a slot cleared to zero. In `processDiffState` (`eth/tracers/native/prestate.go`) the storage branch is:
```go
} else {
modified = true
if newVal != (common.Hash{}) {
postAccount.Storage[key] = newVal
}
}
```
A slot whose new value is zero is marked modified and then omitted from `post`. So a call that zeroes a slot leaves the accumulator holding the stale non-zero value, and every later call in the sequence simulates against state that call already cleared.
The reachable case is an allowance drain. `approve(vault, 1000)`, then `deposit(1000)` which spends the allowance to zero, then a second `deposit`: call three runs against an override still claiming an allowance of 1000 and is reported as succeeding, where on chain it reverts. That is a silent wrong answer on the preflight an agent uses to decide whether to broadcast.
This is independent of #2517 - it is still wrong once the trace runs on the correct base - and it is the remaining hole in the promise that each call resolves against the state the one before it produced.
The fix has to read cleared slots out of `pre` rather than `post`: a key present in `pre[addr].Storage` and absent from `post[addr].Storage`, on an account that `post` reports as modified, has been set to zero.
Contributor guide
Research direction
Start in lib/execute/simulate-sequence.ts:311-339 at mergeDiffIntoOverrides, then read geth's processDiffState in eth/tracers/native/prestate.go to understand how cleared storage is represented. Trace the approve, allowance-draining deposit, and second deposit sequence; done means a slot absent from modified post storage is treated as zero so the final simulation matches on-chain behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, typescript
- Domain
- backend, blockchain
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100