How to Use Inline Assembly to Manipulate Storage Variables in Solidity
Introduction
Solidity is a high-level language for writing smart contracts on Ethereum, but it also provides a low-level feature called inline assembly. This powerful construct gives developers direct access to the Ethereum Virtual Machine (EVM) opcodes and storage layout, enabling optimizations or specialized logic that can’t be easily expressed in standard Solidity syntax. One key use case is manipulating storage variables directly, which can help in advanced scenarios like complex data structures, gas optimizations, or specialized upgrade patterns.
In this article, we’ll explore a small code snippet that demonstrates how to read and modify storage slots for two deposit variables: charlesDeposits and bobDeposits. You’ll learn how to identify which storage slot each variable occupies, how to read and write values from that slot, and best practices to avoid pitfalls. If you need professional security audits or advanced consulting on inline assembly usage, consider Bailsec’s audit services.
1. Understanding Storage Slots in Solidity
Solidity stores contract state variables in storage, which is mapped into a key-value store. The compiler assigns slots to each variable based on its declaration order and size. For instance, if you have:

- charlesDeposits might occupy slot 0.
- bobDeposits might occupy slot 1.
This slot-based layout is critical for inline assembly. By referencing the correct slot, you can directly read or modify the data within it.
2. The Code Snippet: increaseDeposits
Below is a simplified version of the snippet showing how to manipulate charlesDeposits:

Key Steps
- Identify Slot: We set bytes32 sSlot = 0; referencing slot 0, which belongs to charlesDeposits.
- Load Value: let s := sload(sSlot) reads the current value from storage.
- Modify Value: s := add(s, amount) increments s by the amount passed to the function.
- Store Value: sstore(sSlot, s) writes the updated value back into slot 0.
In this example, we’re specifically modifying charlesDeposits. Meanwhile, bobDeposits remains unchanged in slot 1.
3. Why Use Inline Assembly?
- Gas Optimization: For certain operations, especially those involving bitwise manipulation or direct storage references, inline assembly can reduce gas costs.
- Complex Data Structures: If you’re implementing advanced data layouts or upgrading older contracts with specific storage patterns, inline assembly might be necessary to handle them precisely.
- Low-Level Access: Some EVM instructions aren’t directly exposed by Solidity. Inline assembly lets you use these instructions for advanced operations.
However, inline assembly also introduces risks, as the compiler can’t check correctness at the same level as standard Solidity code. Mistakes in slot references or operations can lead to severe bugs or security vulnerabilities.
4. Best Practices and Pitfalls
4.1. Always Verify Slot Assignments
Solidity’s slot assignments depend on declaration order and data type packing. A single error in referencing a slot can overwrite the wrong variable or even break the entire contract’s logic. Tools like Remix or the solc compiler’s debugging features can help confirm slot mappings.
4.2. Maintain Code Readability
Inline assembly is less readable than standard Solidity. Provide clear comments explaining which slot you’re accessing and why. For example:

4.3. Avoid Overly Complex Inline Assembly
Inline assembly can quickly become unreadable and error-prone. Keep it minimal. If a straightforward Solidity approach is possible, prefer that for clarity and safety.
4.4. Reentrancy and Security
When modifying storage, ensure you follow standard security practices like Checks-Effects-Interactions. If your inline assembly code interacts with external contracts or calls call, reentrancy could become a risk. Using a ReentrancyGuard or marking your function as nonReentrant might be necessary in more complex scenarios.
4.5. Consider Using a Library
If you frequently manipulate storage, consider writing a small library of inline assembly functions for reading/writing slots. This approach centralizes your low-level logic, making it easier to audit and reuse.
5. Potential Use Cases
- Upgradeable Contracts
- When using proxy patterns, the storage layout must remain consistent. Inline assembly might help handle advanced re-mapping or merging of new variables into old slots.
- Custom Data Structures
- If you’re storing large arrays, mapping structures, or multi-dimensional data, you may use inline assembly for direct indexing and advanced bitwise operations.
- Cross-Contract Interactions
- Some advanced cross-contract flows might rely on inline assembly to pass specific data to external calls in an optimized format.
6. Example Extension: Adding Bob’s Logic
Suppose we want a function that modifies bobDeposits in slot 1. We’d do something like:

This approach is nearly identical, but references slot 1 instead of slot 0.
7. Security Considerations
7.1. Storage Collisions
If you’re working in a complex inheritance hierarchy, you risk colliding with inherited variables or libraries that assume certain slots. Make sure your contract’s entire storage layout is well-documented.
7.2. Overflow and Underflow
Even with Solidity 0.8.x’s automatic overflow checks, inline assembly can bypass these checks if you do low-level arithmetic with EVM instructions. If you’re adding or subtracting values in assembly, consider implementing your own overflow checks or verifying that the values can’t exceed 2^256-1.
7.3. Auditing
Inline assembly is often tricky to review. Tools like Slither or MythX might not fully parse or interpret your inline assembly logic. For a robust audit, you might need specialized knowledge or manual code review. Bailsec’s reviews can help ensure your inline assembly is both correct and secure.
8. Checks-Effects-Interactions (CEI) Reminder
Even if your code is mostly about reading and writing storage, a single external call (e.g., to transfer Ether or tokens) within inline assembly can open the door to reentrancy attacks. Always separate checks (like verifying the user’s balance or input) from your state modifications, and then make external calls last. For instance:
- Checks: Verify function conditions in standard Solidity code.
- Effects: Use inline assembly to update the storage variables.
- Interactions: Perform external calls after your contract’s state is settled.
This pattern remains a cornerstone of Solidity security, regardless of whether you’re writing standard code or inline assembly.
Conclusion
Manipulating storage variables with inline assembly is a powerful technique for advanced Solidity developers. By referencing specific storage slots (sload and sstore), you can directly read and modify data in ways that standard Solidity syntax might not allow or optimize. However, with this power comes responsibility—slot references must be carefully validated, and all typical security practices (like reentrancy checks, overflow checks, and code clarity) still apply.
If you’re implementing inline assembly for specialized data structures, upgradeable contracts, or gas optimizations, thorough testing and professional audits are essential. A single oversight in slot referencing or arithmetic can break your contract’s logic or expose it to exploits. For deeper insights or an expert code review, check out Bailsec’s services. And for more Solidity best practices, read our blog where we regularly publish articles on advanced development and security topics.
Disclaimer: This post is for informational purposes only and does not constitute legal or financial advice. Always conduct extensive testing and consider professional audits to ensure your smart contracts meet robust security standards.