Skip to content

feat: ERC-7201 Storage Layout#15299

Open
wjmelements wants to merge 12 commits into
foundry-rs:masterfrom
wjmelements:feat/erc7201-storage-layout
Open

feat: ERC-7201 Storage Layout#15299
wjmelements wants to merge 12 commits into
foundry-rs:masterfrom
wjmelements:feat/erc7201-storage-layout

Conversation

@wjmelements

@wjmelements wjmelements commented Jun 22, 2026

Copy link
Copy Markdown

This implements ERC-7201 for forge inspect storageLayout.

Motivation

I was implementing a library contract that would have delcared its storage using this annotation but the declared storage doesn't show up in the storage layout inspection.
We use this layout inspection to detect harmful regressions in the storage layout when maintaining a delegatecall proxy's implementation.
For library functionality such as the ERC-1967 upgrade location (not implemented here) and ERC-7201 custom-storage-location, we would like to be able to detect and include these slots in the layout description.
Without this feature, we would have to detect all of these locations ad-hoc.

Changes

  • use solar to collect erc-7201 entries
  • add hir_type_storage_info to expand entries for the storageLayout inspection output
  • add integration tests to verify that entries show up in the storage layou

Comment thread crates/forge/src/cmd/inspect.rs
Comment thread crates/forge/src/cmd/inspect.rs Outdated
… array sizes

Assisted-by: Claude:claude-sonnet-4-6
…d packing loop

Assisted-by: Claude:claude-sonnet-4-6
Comment thread crates/forge/src/cmd/inspect.rs
Comment thread crates/forge/src/cmd/inspect.rs Outdated
Comment thread crates/forge/src/cmd/inspect.rs Outdated
@mablr mablr requested review from figtracer and mablr June 30, 2026 19:06
Assisted-by: Claude:claude-sonnet-4-6
…positive

Assisted-by: Claude:claude-sonnet-4-6
… ERC-7201 slots

Assisted-by: Claude:claude-sonnet-4-6
…ic array

Assisted-by: Claude:claude-sonnet-4-6
};
(bytes, 0, "inplace")
}
TypeKind::Custom(_) | TypeKind::Err(_) => (32, 1, "inplace"),

@mablr mablr Jul 2, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Blocker] Contract/interface-typed fields fall through to unknown, so they are treated as 32-byte slot-boundary values instead of 20-byte packable addresses. I reproduced this with IERC20 token; bool paused;: the normal solc layout packs paused at slot 0 offset 20, but the ERC-7201 synthetic layout emits token as unknown and moves paused to the next slot.

Consider handling ItemId::Contract(_) with a solc-compatible contract label and 20-byte inplace storage info.

for struct_id in hir.strukt_ids() {
let strukt = hir.strukt(struct_id);

let Some(struct_contract_id) = strukt.contract else { continue };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] This skips every @custom:storage-location erc7201:* struct declared at file scope, because strukt.contract is None. Solidity accepts NatSpec on file-level structs, and a library-style accessor using that struct currently compiles but forge inspect FileStorageLib storageLayout --json returns empty storage/types. Consider including file-level annotated structs that are referenced by the target/library path, or otherwise documenting/rejecting that pattern.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't ever used this annotation at file scope. Might be hard to identify consumers. I'll think about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants