Storage Layout
DISCLAIMER // NFA // DYOR
This analysis is based on observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.
⊙ generated by robots | curated by humans
| METADATA | |
|---|---|
| Contract Address | 0x82eb1246...90cC37 (etherscan) |
| Network | Ethereum Mainnet |
| Analysis Date | 2026-06-02 |
Variables
All persistent state lives in slots 0–25. The contract's configuration is held in immutable/constant fields, which the compiler embeds in bytecode rather than storage — so the relay address, verifiers, denominations, asset id, and tree constants occupy no storage slot. The inherited ReentrancyGuardTransient lock uses EIP-1153 transient storage, which also consumes no persistent slot.
Values below were read on-chain at analysis date via cast storage.
| SLOT | VARIABLE NAME | TYPE | CURRENT VALUE | PURPOSE |
|---|---|---|---|---|
| 0 | _pools |
mapping(bytes32 => Pool) |
0x0 (base) |
Per-pool state, keyed by pid = keccak256(ASSET_ID, denomination). Members live at keccak-derived slots (see below) |
| 1 | totalBalance |
uint256 |
90000000000000 (9e13 wei) |
Aggregate escrowed ETH; the solvency gate for withdrawals |
| 2 | poolVerifiers |
mapping(bytes32 => IPoolRootVerifier) |
0x0 (base) |
Pool → bound SP1 pool-root verifier (all 8 → 0x42Ab3d9d...2a3CCb (etherscan)) |
| 3 | everKnownRoot |
mapping(bytes32 => mapping(bytes32 => bool)) |
0x0 (base) |
Pool → root → was-ever-current flag |
| 4 | rootAccumulator |
mapping(bytes32 => bytes32) |
0x0 (base) |
Pool → running SHA-256 of all historical roots (read by the SP1 verifier) |
| 5 | poolIds |
bytes32[] |
length 8 |
Enumerable list of the 8 pool ids |
| 6 | zeros[0] |
bytes32 |
0x0 |
Empty-subtree hash at level 0 (the zero leaf) |
| 7 | zeros[1] |
bytes32 |
0x2098f5fb...b64864 |
Poseidon(0,0) — canonical empty-subtree hash at level 1 |
| 8–24 | zeros[2..18] |
bytes32 |
precomputed | Empty-subtree hashes, each Poseidon(zeros[i-1], zeros[i-1]) |
| 25 | zeros[19] |
bytes32 |
0x1830ee67...f72cca |
Empty-subtree hash at level 19 (top precomputed level) |
Pool struct (value type of _pools)
Each pool's fields are laid out sequentially from its base slot keccak256(pid . 0):
| OFFSET | FIELD | TYPE | PURPOSE |
|---|---|---|---|
| +0 | denomination |
uint256 |
Wei denomination; 0 means "pool does not exist" |
| +1 | nextLeafIndex |
uint256 |
Count of deposited leaves (deposit-tree fill level) |
| +2 | currentRoot |
bytes32 |
Latest deposit Merkle root |
| +3 | verifierDenomIdx |
uint8 |
Index of this denom in the SP1 verifier's array (packed in the same slot) |
| +4 | filledSubtrees |
mapping(uint256 => bytes32) |
Cached right-edge subtree hashes for incremental insertion |
| +5 | burnNullifiers |
mapping(bytes32 => bool) |
Spent burn nullifiers (double-spend guard) |
| +6 | commitments |
mapping(bytes32 => bool) |
Used deposit commitments (duplicate guard) |
Storage notes
- ◇ The mapping bases (slots 0, 2, 3, 4) read as zero — expected, since mapping contents hash to derived slots, not the base slot.
- ◇
zeros[]is a 20-entry fixed array filling slots 6–25 contiguously;zeros[1]matching the well-known Poseidon(0,0) constant0x2098f5fb…confirms the tree hash is Poseidon Hash, the same primitive used inside the withdrawal SNARK. - ☑ No storage slot holds an owner, admin, or pause flag — consistent with the role-free design.
Diagrams
graph TB
subgraph Core["Core State — Slots 0-4"]
S0["Slot 0: _pools mapping (base)"]
S1["Slot 1: totalBalance — 9e13 wei"]
S2["Slot 2: poolVerifiers mapping"]
S3["Slot 3: everKnownRoot mapping"]
S4["Slot 4: rootAccumulator mapping"]
end
subgraph List["Enumerable — Slot 5"]
S5["Slot 5: poolIds[] — length 8"]
end
subgraph Zeros["Precomputed Empty-Subtree Hashes — Slots 6-25"]
S6["Slot 6: zeros[0] = 0x0"]
S7["Slot 7: zeros[1] = Poseidon(0,0)"]
S25["Slot 25: zeros[19]"]
end
subgraph Derived["Hash-Derived (per pool)"]
P["Pool struct: denomination, nextLeafIndex,<br/>currentRoot, verifierDenomIdx,<br/>filledSubtrees, burnNullifiers, commitments"]
end
Core --> List --> Zeros
S0 -.->|"keccak256(pid . 0)"| Derived
style S1 fill:#ffe1e1
style S0 fill:#e1e8ff