57663 sc insight gas storage optimization erc1155info struct in structures sol can save one slot through field reordering
Submitted on: Oct 27th 2025 at 23:19:41 UTC by @chief_hunter888 for Audit Comp | Belong
Report ID: #57663
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/Structures.sol
Description
Brief Summary
The Structures.sol file defines multiple custom data structures (AccessTokenInfo, ERC1155Info, CustomerInfo, PromoterInfo, etc.) that contain a mix of fields: address, bool, and smaller integer types (uint96, uint128, uint24, etc.).
Problem: In the Structures.sol struct layout, several structs are not optimally packed for efficient storage utilisation, resulting in unnecessary consumption of additional 32-byte storage slots. This increases gas cost for storing these structs. Solidity packs contiguous smaller types (<32 bytes) together if adjacent in declaration order and combined size ≤ 32 bytes. Dynamic types and large types (address, uint256, string, bytes, mapping) start a new slot.
Solution: Move the bool transferable in ERC1155Info next to the static fields (addresses) so it can be packed into an existing slot rather than occupying its own slot. This reduces the number of storage slots used per ERC1155Info struct from 8 to 7, saving one 32-byte slot (≈ ~20,000 gas on initial write).
Context: Solidity Storage Basics - How to Optimize Solidity Storage
Each storage slot = 32 bytes (256 bits). Solidity packs contiguous smaller types (<32 bytes) together into the same slot if:
They are adjacent in declaration order.
Their combined size ≤ 32 bytes.
Group smaller types together before introducing larger ones (address, uint256, string, bytes, mapping, etc. always start a new slot).
Below are the relevant structs and the suggested reordering for ERC1155Info.
3. ERC1155Info
ERC1155InfoCurrent declaration in Structures.sol:
Improvement Suggestion
Dynamic fields (string) always occupy their own slots, so packing is limited. The bool transferable could be grouped before the dynamic fields (string) to share a slot with address burner (or any adjacent address). Reorder to place bool transferable adjacent to the addresses so it fits into the remaining bytes of an address slot instead of forcing a new slot.
Suggested optimized layout:
Rationale: The four addresses (4 × 20 bytes = 80 bytes) still occupy four slots, but the bool (1 byte) can now be packed into the slot containing an address, saving one full slot compared to the original layout where the bool was declared after dynamic fields and forced into its own slot.
✅ Saves 1 storage slot vs current layout.
ERC1155Info Finding Summary Details
ERC1155Info Finding Summary DetailsFinding: The struct ERC1155Info — Can save 1 storage slot
Current Layout (rough):
Slot 1-2: string name, string symbol (dynamic)
Slot 3: address defaultAdmin (20 bytes) → 12 bytes wasted
Slot 4: address manager (20 bytes) → 12 bytes wasted
Slot 5: address minter (20 bytes) → 12 bytes wasted
Slot 6: address burner (20 bytes) → 12 bytes wasted
Slot 7+: string uri (dynamic)
Slot 8+: bool transferable (1 byte) → 31 bytes wasted
Optimized: Move bool transferable next to any address to pack them together (20 + 1 = 21 bytes in one slot).
Improved storage layout (example):
Slot 1-2: string name, string symbol (dynamic)
Slot 3: address defaultAdmin (20 bytes) + bool (1 byte) → 11 bytes wasted
Slot 4: address manager (20 bytes) → 12 bytes wasted
Slot 5: address minter (20 bytes) → 12 bytes wasted
Slot 6: address burner (20 bytes) → 12 bytes wasted
Slot 7+: string uri (dynamic)
One full slot saved.
Example docstring for the optimized struct:
Summary of Potential Storage Improvements
NftMetadata
0
optimal
AccessTokenInfo
0
Optimal
ERC1155Info
1 slot
Move bool above dynamic fields
VestingWalletInfo
0
Optimal
StaticPriceParameters
0
Optimal
DynamicPriceParameters
0
Optimal
VenueRules
0
Optimal
VenueInfo
0
Optimal
CustomerInfo
0
Optimal
PromoterInfo
0
Optimal
Impact Details
Reordering the fields of ERC1155Info achieves a saving of one 32-byte storage slot. Each eliminated slot corresponds to a reduction of approximately:
~20,000 gas when first written (cold SSTORE), and
~5,000 gas for subsequent updates (warm writes differ depending on state transitions and EVM specifics).
This improvement is non-invasive, requires no logic changes, and directly enhances contract performance for storage-heavy operations (deployments, updates to these structs, or repeated writes).
Proof of Concept
The optimized Structures.sol file (showing the adjusted ERC1155Info and full file for context):
Summary
Reordering
bool transferableto sit next to address fields inERC1155Infosaves one storage slot per struct instance.This is a low-risk, non-functional change that reduces gas cost for writes and updates related to
ERC1155Info.No logic changes required — only declaration order adjustment to improve packing.
Was this helpful?