Locate the Source of a State Variable Write
Trace a final storage difference back to every SSTORE, trace index, and code location that produced it.
Case objective
Determine how many times a target storage slot changed, which trace produced each write, and which write formed the final value.
Example transaction and context
This case uses an Ethereum transaction from block 17806056:
0xa84aa065ce61dbb1eb50ab6ae67fc31a9da50dd2c74eefd561661bfce2f1620cOpen the transaction in Skylens
The target is slot 8 of the Curve pETH-ETH-f pool proxy at 0x9848482da3Ee3076165ce6497eDA906E66bB85C5. During this transaction, code from implementation 0x6326DEbBAa15bCFE603d831e7D75f4fc10d9B43E writes the proxy's state several times.
Questions to answer
- What are the before and after values of slot
8? - How many intermediate writes occurred?
- Why do the code and state addresses differ?
Investigation steps
- In State Changes, expand the proxy and record the raw Before and After values for slot
8. - Open the slot's Variable History and inspect every write in trace order.
- Jump to Execution Trace, enable the SSTORE filter, and verify the executing contract, Program Counter, and parent call.
- Use Set Breakpoints to group all five writes, then compare their Call Stack and variable context in Source Debugger.
- Treat the implementation as the source of code and storage layout while keeping the proxy as the state address.
Key evidence
The current layout does not decode the variable reliably, so this case uses the proxy address, slot, and raw value as stable identifiers.
| Trace | PC | Before | After |
|---|---|---|---|
69 | 1046 | 0x14f4ef71451a6d37997 | 0x9c797cba0428105ecc1 |
87 | 7190 | 0x9c797cba0428105ecc1 | 0x283517e49e6b3069518 |
105 | 1046 | 0x283517e49e6b3069518 | 0xafba082befb269343e8 |
144 | 7190 | 0xafba082befb269343e8 | 0xec4ae2b62e2a888e17 |
194 | 3150 | 0xec4ae2b62e2a888e17 | 0x3f3278e0363aaefcf |
The full final difference in State Changes is:
Address: 0x9848482da3Ee3076165ce6497eDA906E66bB85C5
Slot: 0x0000000000000000000000000000000000000000000000000000000000000008
Before: 0x00000000000000000000000000000000000000000000014f4ef71451a6d37997
After: 0x00000000000000000000000000000000000000000000003f3278e0363aaefcfThe first and last SSTORE values match State Changes exactly, showing that the intermediate history is complete.
Conclusion
Slot
8on the proxy was written five times in one transaction. Trace69starts from the pre-transaction value and trace194produces the final value. The implementation supplied the executing code, but the state remained owned by the proxy.
Caveats
- Do not assign a variable name to a raw slot until the storage layout is verified.
- Mapping and dynamic-array slots are commonly derived with
KECCAK256. - Intermediate writes can be overwritten or reverted with a child call.
- Source shown for an implementation during
DELEGATECALLdoes not mean the implementation owns the state.
Related documentation
Trace Asset Flows Through a Transaction
Combine Balance Changes, Token Flow, and Execution Trace to reconstruct asset paths and final net changes with exact amounts.
Debug an Unverified Contract
Narrow the scope with Execution Trace, then use opcodes, PCs, stack values, and runtime data to explain a critical call.
