<100 subscribers

What's happening to Farcaster?
The pivot to a trader-focused-social-wallet, the drama, future of Farcaster and other Clients

Please Stop Making The Audience Fall Asleep At Your IRL Workshop
How to make engaging technical workshops on any topic and make people getting addicted to learning it

How To Actually Learn Things Now That Cursor Writes Code For Us
(If you don't like rants, do not read this article)

What's happening to Farcaster?
The pivot to a trader-focused-social-wallet, the drama, future of Farcaster and other Clients

Please Stop Making The Audience Fall Asleep At Your IRL Workshop
How to make engaging technical workshops on any topic and make people getting addicted to learning it

How To Actually Learn Things Now That Cursor Writes Code For Us
(If you don't like rants, do not read this article)


Solidity is the most widely used language for writing Ethereum smart contracts, offering high-level abstractions that make development accessible. However, every Solidity contracts ultimately compiles down to EVM bytecode, a sequence of low-level instructions called opcodes that the Ethereum Virtual Machine executes.
Understanding opcodes gives you deeper insight into gas costs, optimization opportunities, security considerations, and how contracts truly behave on-chain. This article breaks down what opcodes are, why they exist, how they are used, examples of inline assembly in Solidity, and touches on formal verification.
Opcodes are the primitive instructions of the Ethereum Virtual Machine. Each opcode is a single byte (0x00 to 0xff), defining a specific operation the EVM can perform.
The EVM is a stack-based virtual machine: most opcodes pop operands from a 1024-item stack, perform an operation, and push results back.
Opcodes interact with memory, storage, the program counter, and the outside world (calls, blockchain data, etc.).
The full opcode reference is available at evm.codes, an interactive playground where you can explore every opcode, its gas cost, and stack effects. I strongly recommend to have a look at that.
The EVM must run deterministically on thousands of nodes worldwide, without relying on any operating system or external dependencies.
A simple, well-defined instruction set (the opcodes indeed) achieves this.
Opcodes enable:
Deterministic execution → Every node reaches the same result.
Gas metering → Each opcode has a precise gas cost, preventing infinite loops and DoS attacks.
Turing completeness → Combined with jumps and stack operations, the instruction set can compute anything computable.
Security and auditability → Low-level operations are easier to formally reason about than high-level code.
Thus, High-level languages like Solidity compile to bytecode (an encoded list of opcodes essentially!) to ensure compatibility across the entire network.
The stack refers to the EVM primary data structure. It's a last-in-first-out (LIFO) array limited to 1024 slots, each holding a 256-bit (32-byte) word.
Almost every EVM opcode operates directly on this stack, instructions do:
pop the required number of items from the top -->
perform the operation -->
push the result back.
Solidity's high-level code abstracts this away, so developers rarely interact with the stack directly, but the compiler translates all expressions, function calls, and variable operations into stack manipulations.
Understanding the stack is crucial for gas optimization and for writing efficient inline assembly, where you explicitly manage stack items to achieve lower-level control or tighter gas usage.
When you deploy a contract, the transaction sends init code (constructor + deployment logic). This init code typically ends by returning the runtime bytecode (the permanent contract code).
A classic pattern uses these opcodes:
Set up free memory pointer (PUSH1 0x80, PUSH1 0x40, MSTORE).
Compute runtime code offset and size.
CODECOPY: copy the runtime bytecode (appended after the init code) to memory starting at offset 0.
RETURN: return the copied bytes as the deployed code.
A minimal deployment bytecode often looks like (in hex):
6080604052...6000803e610xxx56fe
Breaking it down:
PUSH1 0x80 / PUSH1 0x40 / MSTORE --> standard memory setup.
Later: CODECOPY (0x39) copies runtime code.
RETURN (0xf3) finalizes deployment.
This pattern is generated automatically by the Solidity compiler for most contracts.
Solidity allows inline assembly for fine-grained control, gas savings, or operations not available in high-level syntax.
Here’s a simple function that adds two numbers entirely in assembly:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract AssemblyExample {
function add(uint256 a, uint256 b) public pure returns (uint256 result) {
assembly {
// Load free memory pointer
let freeMem := mload(0x40)
// Perform addition
result := add(a, b)
// Store result in memory
mstore(freeMem, result)
// Return 32 bytes from freeMem
return(freeMem, 0x20)
}
}
}
Another common use: efficient hashing of dynamic data:
function keccak256Hash(bytes memory data) public pure returns (bytes32) {
bytes32 hash;
assembly {
hash := keccak256(add(data, 0x20), mload(data))
}
return hash;
}
Assembly bypasses some Solidity safety checks, so use it carefully!
Huff is an extremely low-level programming language for the Ethereum Virtual Machine that allows developers to write smart contracts almost directly in opcodes, with only minimal syntactic sugar in the form of macros.
Unlike Solidity, which compiles to bytecode through layers of abstraction, or even Solidity’s inline assembly, which still operates within Yul’s structured constraints, Huff gives near-total control over the stack, memory, and opcode sequence.
It has no built-in types, no safety checks, and no high-level constructs; everything is explicit.
This makes it possible to produce the most gas-efficient contracts on Ethereum, often beating hand-optimized Yul assembly by a few percent.
Huff is particularly popular in the Foundry ecosystem and has been used to implement highly optimized libraries, minimal proxies, and even entire DeFi primitives.
However, the trade-off is important: the language is notoriously difficult to read, audit, and debug, and a single misplaced opcode can create catastrophic bugs.
Huff is therefore reserved for extreme optimization scenarios or educational purposes rather than general-purpose contract development.
Formal verification is the process of using mathematical proofs to guarantee that a smart contract behaves correctly under all possible conditions, rather than merely testing specific cases.
Because Solidity code ultimately compiles to EVM bytecode, the most rigorous verification approaches target the opcodes directly; where the exact semantics of each instruction are defined without the abstractions or optimizations introduced by the high-level compiler.
I strongly recommend following the Solidity Assembly & Formal Verification Course from Cyfrin Updraft.
Opcodes are the DNA of every Ethereum smart contract. While most developers work comfortably in high-level Solidity, understanding opcodes unlocks advanced optimization, deeper security audits, and appreciation for the elegant simplicity of the EVM.
Be careful tho! Using assembly or huff can lead to unexpected errors. be sure to use these way to write code very carefully, and balance your needs. Always ask yourself if you really need to use that to ship mainnet contracts.
Personally I prefer readability vs efficiency if the marginal improvement of contract efficiency is low. But hey, there are crazy and skilled solidity dev out there.
Whether you're minimizing gas, writing libraries, or diving into formal verification, spending time with opcodes pays off.
Start exploring at evm.codes, try disassembling your own contracts and see the magic underneath.
Never Stop Building please, comment and subscribe. Thanks!
Solidity is the most widely used language for writing Ethereum smart contracts, offering high-level abstractions that make development accessible. However, every Solidity contracts ultimately compiles down to EVM bytecode, a sequence of low-level instructions called opcodes that the Ethereum Virtual Machine executes.
Understanding opcodes gives you deeper insight into gas costs, optimization opportunities, security considerations, and how contracts truly behave on-chain. This article breaks down what opcodes are, why they exist, how they are used, examples of inline assembly in Solidity, and touches on formal verification.
Opcodes are the primitive instructions of the Ethereum Virtual Machine. Each opcode is a single byte (0x00 to 0xff), defining a specific operation the EVM can perform.
The EVM is a stack-based virtual machine: most opcodes pop operands from a 1024-item stack, perform an operation, and push results back.
Opcodes interact with memory, storage, the program counter, and the outside world (calls, blockchain data, etc.).
The full opcode reference is available at evm.codes, an interactive playground where you can explore every opcode, its gas cost, and stack effects. I strongly recommend to have a look at that.
The EVM must run deterministically on thousands of nodes worldwide, without relying on any operating system or external dependencies.
A simple, well-defined instruction set (the opcodes indeed) achieves this.
Opcodes enable:
Deterministic execution → Every node reaches the same result.
Gas metering → Each opcode has a precise gas cost, preventing infinite loops and DoS attacks.
Turing completeness → Combined with jumps and stack operations, the instruction set can compute anything computable.
Security and auditability → Low-level operations are easier to formally reason about than high-level code.
Thus, High-level languages like Solidity compile to bytecode (an encoded list of opcodes essentially!) to ensure compatibility across the entire network.
The stack refers to the EVM primary data structure. It's a last-in-first-out (LIFO) array limited to 1024 slots, each holding a 256-bit (32-byte) word.
Almost every EVM opcode operates directly on this stack, instructions do:
pop the required number of items from the top -->
perform the operation -->
push the result back.
Solidity's high-level code abstracts this away, so developers rarely interact with the stack directly, but the compiler translates all expressions, function calls, and variable operations into stack manipulations.
Understanding the stack is crucial for gas optimization and for writing efficient inline assembly, where you explicitly manage stack items to achieve lower-level control or tighter gas usage.
When you deploy a contract, the transaction sends init code (constructor + deployment logic). This init code typically ends by returning the runtime bytecode (the permanent contract code).
A classic pattern uses these opcodes:
Set up free memory pointer (PUSH1 0x80, PUSH1 0x40, MSTORE).
Compute runtime code offset and size.
CODECOPY: copy the runtime bytecode (appended after the init code) to memory starting at offset 0.
RETURN: return the copied bytes as the deployed code.
A minimal deployment bytecode often looks like (in hex):
6080604052...6000803e610xxx56fe
Breaking it down:
PUSH1 0x80 / PUSH1 0x40 / MSTORE --> standard memory setup.
Later: CODECOPY (0x39) copies runtime code.
RETURN (0xf3) finalizes deployment.
This pattern is generated automatically by the Solidity compiler for most contracts.
Solidity allows inline assembly for fine-grained control, gas savings, or operations not available in high-level syntax.
Here’s a simple function that adds two numbers entirely in assembly:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract AssemblyExample {
function add(uint256 a, uint256 b) public pure returns (uint256 result) {
assembly {
// Load free memory pointer
let freeMem := mload(0x40)
// Perform addition
result := add(a, b)
// Store result in memory
mstore(freeMem, result)
// Return 32 bytes from freeMem
return(freeMem, 0x20)
}
}
}
Another common use: efficient hashing of dynamic data:
function keccak256Hash(bytes memory data) public pure returns (bytes32) {
bytes32 hash;
assembly {
hash := keccak256(add(data, 0x20), mload(data))
}
return hash;
}
Assembly bypasses some Solidity safety checks, so use it carefully!
Huff is an extremely low-level programming language for the Ethereum Virtual Machine that allows developers to write smart contracts almost directly in opcodes, with only minimal syntactic sugar in the form of macros.
Unlike Solidity, which compiles to bytecode through layers of abstraction, or even Solidity’s inline assembly, which still operates within Yul’s structured constraints, Huff gives near-total control over the stack, memory, and opcode sequence.
It has no built-in types, no safety checks, and no high-level constructs; everything is explicit.
This makes it possible to produce the most gas-efficient contracts on Ethereum, often beating hand-optimized Yul assembly by a few percent.
Huff is particularly popular in the Foundry ecosystem and has been used to implement highly optimized libraries, minimal proxies, and even entire DeFi primitives.
However, the trade-off is important: the language is notoriously difficult to read, audit, and debug, and a single misplaced opcode can create catastrophic bugs.
Huff is therefore reserved for extreme optimization scenarios or educational purposes rather than general-purpose contract development.
Formal verification is the process of using mathematical proofs to guarantee that a smart contract behaves correctly under all possible conditions, rather than merely testing specific cases.
Because Solidity code ultimately compiles to EVM bytecode, the most rigorous verification approaches target the opcodes directly; where the exact semantics of each instruction are defined without the abstractions or optimizations introduced by the high-level compiler.
I strongly recommend following the Solidity Assembly & Formal Verification Course from Cyfrin Updraft.
Opcodes are the DNA of every Ethereum smart contract. While most developers work comfortably in high-level Solidity, understanding opcodes unlocks advanced optimization, deeper security audits, and appreciation for the elegant simplicity of the EVM.
Be careful tho! Using assembly or huff can lead to unexpected errors. be sure to use these way to write code very carefully, and balance your needs. Always ask yourself if you really need to use that to ship mainnet contracts.
Personally I prefer readability vs efficiency if the marginal improvement of contract efficiency is low. But hey, there are crazy and skilled solidity dev out there.
Whether you're minimizing gas, writing libraries, or diving into formal verification, spending time with opcodes pays off.
Start exploring at evm.codes, try disassembling your own contracts and see the magic underneath.
Never Stop Building please, comment and subscribe. Thanks!
Share Dialog
Share Dialog
No comments yet