Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
IT Security Toolszitadel v4.18.0(22.09.2026 um 11:25 Uhr)
IT Security ToolsPodroid v1.2.9(22.09.2026 um 12:05 Uhr)
IT Security NachrichtenHow the CIA captured Carlos the Jackal(22.09.2026 um 13:00 Uhr)
Sicherheitslücken (CVE)Aikido Security Unveils Altar-1 Open-Weight AI for Cybersecurity Defense(22.09.2026 um 12:50 Uhr)
Sicherheitslücken (CVE)IT Security News Hourly Summary 2026-09-22 13h : 23 posts(22.09.2026 um 13:00 Uhr)
IT Security NachrichtenHow a Managed SOC works: What happens when a cyberattack begins?(22.09.2026 um 13:02 Uhr)
Sicherheitslücken (CVE)[UPDATE] [mittel] libxml2: Schwachstelle ermöglicht Denial of Service(22.09.2026 um 12:47 Uhr)
IT Security Toolszitadel v4.18.0(22.09.2026 um 11:25 Uhr)
IT Security ToolsPodroid v1.2.9(22.09.2026 um 12:05 Uhr)
IT Security NachrichtenHow the CIA captured Carlos the Jackal(22.09.2026 um 13:00 Uhr)
Sicherheitslücken (CVE)Aikido Security Unveils Altar-1 Open-Weight AI for Cybersecurity Defense(22.09.2026 um 12:50 Uhr)
Sicherheitslücken (CVE)IT Security News Hourly Summary 2026-09-22 13h : 23 posts(22.09.2026 um 13:00 Uhr)
IT Security NachrichtenHow a Managed SOC works: What happens when a cyberattack begins?(22.09.2026 um 13:02 Uhr)
Sicherheitslücken (CVE)[UPDATE] [mittel] libxml2: Schwachstelle ermöglicht Denial of Service(22.09.2026 um 12:47 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

How I Saved 20,000 Gas Per Transaction by Reordering One Line in Solidity

While building a smart wallet contract for Fishnet — an AI agent transaction security proxy — I ran a self-imposed code review and found a subtle optimization that every Solidity developer should know about. One variable reorder. 20,000 ga…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

While building a smart wallet contract for Fishnet — an AI agent transaction security proxy — I ran a self-imposed code review and found a subtle optimization that every Solidity developer should know about.



One variable reorder. 20,000 gas saved per transaction.



Here's the full breakdown.









The Problem: Silent Storage Slot Waste



My state variables looked like this:




address public owner;          // 20 bytes → Slot 0
address public fishnetSigner; // 20 bytes → Slot 1
mapping(uint256 => bool) public usedNonces; // Slot 2
bool public paused; // 1 byte → Slot 3 ← wasting 31 bytes






That bool paused at the bottom? It's only 1 byte, but it was consuming an entire 32-byte storage slot. That's 31 bytes of wasted space — and more importantly, an extra SLOAD/SSTORE on every pause check.






Why the EVM cares



The EVM operates on 32-byte words. Every storage slot is exactly 32 bytes. When the Solidity compiler lays out your state variables, it goes top to bottom in declaration order:




Slot 0: [owner ─────────────── 20 bytes][── 12 bytes empty ──]
Slot 1: [fishnetSigner ─────── 20 bytes][── 12 bytes empty ──]
Slot 2: [usedNonces mapping hash ───────────────── 32 bytes ─]
Slot 3: [paused ─ 1 byte][─────── 31 bytes empty ───────────]






The compiler does not reorder your variables for you. If a variable can't fit in the remaining space of the current slot, it starts a new one. An address is 20 bytes. A bool is 1 byte. They fit together with 11 bytes to spare — but only if they're adjacent in your declaration.









The Fix: Storage Slot Packing



Move paused right after owner:




address public owner;          // 20 bytes ─┐
bool public paused; // 1 byte ──┘ Slot 0 (21/32 bytes)
address public fishnetSigner; // 20 bytes → Slot 1
mapping(uint256 => bool) public usedNonces; // Slot 2






New layout:




Slot 0: [owner ─────────────── 20 bytes][paused 1B][─ 11 bytes empty ─]
Slot 1: [fishnetSigner ─────── 20 bytes][── 12 bytes empty ──────────]
Slot 2: [usedNonces mapping hash ───────────────── 32 bytes ─────────]






4 slots → 3 slots. One fewer storage slot touched at runtime.



EVM Storage Slot Packing - Before and After









The Gas Math



Here's what this saves in practice:
































Operation Before (separate slots) After (packed) Savings
Cold SLOAD (first read in tx) 2,100 gas × 2 slots 2,100 gas × 1 slot 2,100 gas
Cold SSTORE (pause/unpause) ~20,000 gas 0 (slot already warm from owner) ~20,000 gas

whenNotPaused modifier per call
Reads its own slot Reads owner's slot (often already warm) Up to 2,000 gas


The big win is the cold SSTORE elimination. Writing to a storage slot that hasn't been accessed in the current transaction costs ~20,000 gas. But if owner has already been read (which it almost always has in the same transaction context), the slot containing paused is now warm — and a warm SSTORE costs only ~2,900 gas.









How to Check Your Own Contracts



Foundry makes this trivial:




forge inspect YourContract storage-layout






This outputs every state variable with its slot number, offset, and byte size. Look for:





  • Variables that could pack together (combined size ≤ 32 bytes) but are in separate slots


  • bool, uint8, uint16, address separated by mappings or larger types


  • Related variables read together that are in different slots



Example output:




| Name          | Type                        | Slot | Offset | Bytes |
|---------------|-----------------------------|------|--------|-------|
| owner | address | 0 | 0 | 20 |
| paused | bool | 0 | 20 | 1 |
| fishnetSigner | address | 1 | 0 | 20 |
| usedNonces | mapping(uint256 => bool) | 2 | 0 | 32 |






When Offset > 0, you've got packing happening. When small types have Offset = 0 and their own slot — that's a packing opportunity.









5 Other Things I Found in the Same Review



Storage packing was the optimization win, but the same code review caught much more:






1. Critical permit.value vulnerability



The execute() function accepted a permit signature but never validated that permit.value matched msg.value. An attacker could get a permit signed for 0.01 ETH but submit the transaction with 100 ETH, draining the wallet.




// Before: no validation
function execute(Permit calldata permit, ...) external payable {
// permit.value could be anything vs msg.value
}

// After: explicit check
require(permit.value == msg.value, InsufficientValue());









2. Chain ID validation for fork protection



The contract cached DOMAIN_SEPARATOR at deployment but never recomputed it. On a chain fork (like ETH/ETH Classic), signatures from one chain would be valid on the other.




function _domainSeparator() internal view returns (bytes32) {
if (block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
}
return _computeDomainSeparator(); // recompute on fork
}









3. Fail-fast signature validation



The original code ran an expensive keccak256 hash before checking if the signature was even the right length. Flipping the order saves gas on every invalid input.




// Before: hash first, then check length
bytes32 hash = keccak256(abi.encodePacked(...));
require(signature.length == 65, InvalidSignature());

// After: check length first, hash only if valid
require(signature.length == 65, InvalidSignature());
bytes32 hash = keccak256(abi.encodePacked(...));









4. Custom errors over string reverts



Replaced all require(condition, "String message") with custom errors. Each string revert stores the message in bytecode and costs ~50 extra gas per revert.




// Before
require(msg.sender == owner, "Not authorized");

// After
error Unauthorized();
if (msg.sender != owner) revert Unauthorized();









5. Dead test code cleanup



Found leftover console.log imports and unused test helper functions that had accumulated during rapid iteration. They don't affect runtime gas, but they bloat deployment bytecode.









Key Takeaway



Code review isn't just about finding bugs. It's about understanding the machine your code runs on.



The EVM has a 32-byte word size, and every storage slot costs real money. Knowing how the compiler lays out storage is the difference between a contract that costs users $2 per transaction and one that costs $5.



Run forge inspect YourContract storage-layout. Look at your slot assignments. You might be surprised what you find.






This came out of building Fishnet — an open-source security proxy for AI agent transactions on Ethereum. If you're working on AI × Web3 infra, check it out.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How I Saved 20,000 Gas Per Transaction by Reordering One Line in Solidity

Thematisch verwandte Begriffe: Saved, 20000, Transaction, Reordering · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94493 | A vulnerability was detected in Gigatech PDV5701 1.0.31_240305_112640. T…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick