The comprehensive EVM deep dive for Solidity developers. Made by @0xMacroSecurity

Joined January 2023
19 Photos and videos
Pinned Tweet
Visit learnevm.com to deep dive on the EVM. Follow to get updates on new chapters. Like/RT to show your appreciation 🤖 It's the little things that matter 🫡
3
21
54
5,577
Adding to this, the 1 word used for the dynamic array is the length of the array Specifically, the length is zero, so there is no more data in memory following it! If the length were (for example) three, then the total size of the dynamic array would be 4 words in memory 😀
Solidity memory lesson 9 (for Fantasy top fans): Implicit memory allocation of dynamic vs static arrays. - Dynamic array is initialized to 0x60, pointing to the zero pointer. No memory is allocated. - Static array is initialized by setting it to the location of newly allocated and zeroized memory.
2
245
⚙️ LearnEVM.com retweeted
24 Sep 2025
All EVM opcodes in one diagram by @LearnEVM
10
43
334
13,385
⚙️ LearnEVM.com retweeted
Building on the Solana virtual machine (SVM) is very different than building on the EVM. Differences include: - Data cannot be encapsulated - External call depth capped at 4 - All account reads and writes must be known ahead of time and much more (tighter transaction limits, built-in upgradability, program-derived accounts and their ability to be signers, and so on). If you're looking to build on Solana and could use an expert opinion to accelerate your development, contact us via telegram, or via inquiry form on our website. Up to 50% of your pre-audit security reviews can be applied to a future audit (limited time only). Stay secure out there 👊 - Macro Security team
3
6
36
9,466
A perfect example of why it's important to know EVM 🤓
19 May 2025
🧵How memory works under the hood in the EVM and how this knowledge led me to recently discover a ✨critical vulnerability✨ Oh and if you're new to assembly, don't worry, it's simpler than you think Memory Layout Starting with the basics, Solidity reserves the following 4 32-byte memory slots: 0x00-0x3f (64 bytes): Scratch space for hashing methods We can use this area for temporary memory usage as long as we don't need more than 64 bytes 0x40-0x5f (32 bytes): Free memory pointer This slot keeps a pointer to free memory, i.e. the point beyond which it's safe to write to memory. When we use additional memory, this slot gets updated to point beyond that used memory. It's important that we never overwrite this value or else high level solidity logic may overwrite existing memory unexpectedly 0x60-0x7f (32 bytes): Zero slot This slot is reserved as the initial value for dynamic memory arrays, as such it must always be zero Memory Management Opcodes There are several opcodes that manipulate memory, but for simplicity, we'll focus on the two most common ones: mstore and mload mstore and mload write (store) and read (load) 32 byte values to and from memory, respectively In assembly (yul), mstore takes two inputs, an offset and a (32 byte) value. The value is then placed at the provided offset in memory. Simple, right? mload works about the same, taking just an offset and returning the (32 byte) value at that offset Example Taking what we've learned so far, we can safely write and read to and from memory as follows: The Critical Bug During a recent audit, I came across a simple, yet easy to miss, assembly memory management bug The code worked by manually deriving a storage slot from the hash of a set of parameters, including the caller As commented in the snippet, we expect memory from 0x1c to 0x40 to contain the selector, followed by the caller, followed by a However, even though a is only 96 bits (12 bytes), it overwrites the last 20 bytes of the caller. Since addresses are only 20 bytes long, this overwrites the entire value. This occurs because mstore always writes a full 32 bytes to the provided offset. If a smaller value is provided, the upper bytes will be zeroed such that the full 32 bytes are overwritten (Try testing this out in chisel with !memdump to get a feel for it) As a result of this bug, the storage slot is not derived from the calller, and thus anyone calling this function will write to the same storage slot, bypassing intended authorization logic Fin Let me know if you're feeling ready for an advanced memory management writeup (😈solady style😈)
1
5
511
⚙️ LearnEVM.com retweeted
20 Jan 2025
The Solidity Developer Survey 2024 has gotten 500 responses so far. If you're yet to take the survey, you've got one last week to let us know... ✨ how you are using Solidity. 🆕 which recent changes impact(ed) you the most. 🔮 which features you anticipate the most. It takes ~10min to contribute to the future of Solidity. 🔗cryptpad.fr/form/#/2/form/vi…
1
19
47
11,585
Eth is moving forward 🫡
EIP-7907 was just approved It will more than 10X the contract size limit, significantly improving the developer experience on Ethereum. I expect it will be included in the next upgrade after Pectra
1
211
this may seem like a lot of opcodes but that's just how expensive the keccak256 operation can be 👀
Compile-time zero-cost abstraction for Solidity. When compiled (with or without --via-ir), this function gives very optimized bytecode that is faster than using `keccak256` to compare two strings.
1
4
357
Gas efficiency *without* writing in opcodes? Have to admit this is kind of impressive🙈🙊🙉
19 Mar 2025
Zolidity ERC20 is 52 lines of code. But still very gas efficient without assembly, vs. Solady ER20 (613 LOC):
6
342
What's the significance of Custom Storage Layouts? By default, Solidity starts all storage variables at slot 0. For example, if you have this contract: contract Example { uint256 x; uint256 y; } then reading x will compile to SLOAD with a key of 0x00, and reading y will compile to an SLOAD with a key of 0x01. (If you have smaller values, such as two uint128's, then Solidity will compact those into the same storage slot. But that's a discussion for another day!) Essentially, all your storage variables live right next to each other, starting at zero and incrementing onwards. However... with Custom Storage Layouts, you can now start at a *different* point than zero! contract Example layout at 0xFAFA { uint256 x; uint256 y; } In this modified example, reading x now compiles to SLOAD with a key of 0xFAFA, and y now compiles to an SLOAD with a key of 0xFAFB! This is useful for EIP-7702, which allows an EOA to "become" a smart contract! The EOA can change which smart contract it becomes multiple times, so it's important for each one to have its own isolated storage space to avoid clashing.
Solidity just added support for Custom Storage Layouts! This allows specifying that your contract storage starts at a point *other than* zero. However, this still doesn't cover the popular Namespaced Storage Layout that modern contracts often use (EIP-7201). For now, you will need to continue using the verbose (but useful!) Solidity pattern to support custom storage for inherited contracts. Hopefully we get this feature soon!
1
2
19
1,165
missing from the list: S - CODECOPY A - CREATE2 - EXTCODECOPY B - KECCAK256 C - CALLDATALOAD D - DIFFICULTY F - PREVRANDAO
13 Feb 2025
EVM opcodes ranked
1
9
566
⚙️ LearnEVM.com retweeted
I have a monopoly on arranging EVM opcodes beautifully and optimally. And it’s free and open source. Milady.
24
16
258
11,925
⚙️ LearnEVM.com retweeted
5 Feb 2025
The simplicity of the EVM is beautiful.
8
3
47
2,630
you can use bytecode as storage.
6 Feb 2025
Diamond compat is complete! The grand total is... 889 bytes! This is 5x smaller than the Solidity equivalent 🤯 And thanks to my previously conservative math, the router contract *still* supports over 4000 function selectors! 😁 As wise @optimizoor once said, "you can use bytecode as storage" 😎
2
13
1,032
⚙️ LearnEVM.com retweeted
you can use bytecode as storage
you can use bytecode as storage.
1
5
698
what does bro mean by this? ERC-7201 is Namespaced Storage Layout. It's a standard for modular, isolated storage layouts. Why is this pattern necessary? To fully understand, you first need to know a bit of how Solidity works... 🧵
ERC-7201, namespaced storage, is good but bad at the same time. The solution is to just use the first 9-bytes of the keccak. Stop wasting 32 bytes of precious bytecode space everywhere. No, I don’t think we need an ERC for this. Just code from first-principles.
2
5
48
7,594
What @optimizoor is suggesting is reducing the key size for this pattern! This allows us to only require 10 bytes of bytecode, instead of the usual 33 – giving us a savings of 69% 😎 Best of all, the chance of collision is still ridiculously low – 1 in 2^72, or 4.72×10²¹
1
1
206
To learn more about how EVM contract storage works, visit our FREE chapter on the topic 🤓 That's all for now, folks! Keep shifting those bits like a pro 😎 learnevm.com/chapters/evm/st…
2
171