EVM Blueprint Slides EVM Blueprint
Architecture and Bytecode Execution
Virtual Machine Architecture
Module 01.1
Stack Architecture
The EVM is a 256-bit register, stack-based machine. All computations are performed on a stack with a maximum depth of 1024 elements.
Word Size
Native word size is 256 bits (32 bytes). Optimized for Keccak-256 hashes and elliptic curve operations.
Stack Top
Word 1
Word 2
Word 3
...
Last-In, First-Out (LIFO)
Data Locations
Storage
Persistent across transactions
Key-value mapping (256-bit)
Extremely expensive gas costs
Memory
Volatile (per call)
Linearly addressed byte array
Quadratic cost expansion
Calldata
Read-only input area
Holds transaction arguments
Cheaper than Memory
Decoding Bytecode
Smart contracts are compiled into bytecode: a series of 1-byte instructions called Opcodes.
// Example: Add two numbers
PUSH1 0x02 // 6002
PUSH1 0x03 // 6003
ADD // 01
Key Opcodes to Remember
SSTORE / SLOAD: Storage
MSTORE / MLOAD: Memory
CALL / DELEGATECALL
REVERT / RETURN
Execution Flow
1
Fetch Opcode at Program Counter (PC)
2
Decode Opcode and consume Gas
3
Execute (Modify Stack/Memory/Storage)
4
Increment PC and Repeat
Opcode Analyst Worksheet Opcode Analyst
Lesson 01: EVM Architecture & Bytecode
Student Name
Date
Part 1: The Stack Challenge
Trace the state of the EVM stack after each instruction. Assume the stack is initially empty. Write the stack contents as a comma-separated list, with the top of the stack on the right .
Instruction
Opcode (Hex)
Stack State (Top on Right)
PUSH1 0x42
6042
PUSH1 0x0A
600A
ADD
01
PUSH1 0x02
6002
MUL
02
Part 2: Storage Mapping
Consider the following Solidity state variables. Map them to their 32-byte storage slots (Slot 0, Slot 1, etc.). Keep in mind how the EVM packs smaller variables.
contract StorageTest {
uint256 public a; // Variable A
uint128 public b; // Variable B
uint64 public c; // Variable C
uint64 public d; // Variable D
address public e; // Variable E
}
Slot 0:
Slot 1:
Slot 2:
Hint: A uint128 is 16 bytes, uint64 is 8 bytes. A slot is 32 bytes.
Part 3: Bytecode Logic
What does the following bytecode sequence do in plain English? Think about the stack operations and memory movement.
604260005260206000f3
60: PUSH1
52: MSTORE (offset, value)
f3: RETURN (offset, length)
00/20/42: Hex Literals
Step-by-step interpretation:
EVM Deep Dive Guide EVM Deep Dive Guide
Teacher Resource • Lesson 01
Instructional Objectives
Differentiate between the three main data locations in the EVM: Storage, Memory, and Calldata.
Perform manual stack tracing for arithmetic and data-movement opcodes.
Calculate storage slot usage based on variable types and the EVM's packing rules.
The Hook: "The Hex Speaker"
"When we write Solidity, we use words like 'function' and 'mapping'. But the Ethereum network has no idea what a 'mapping' is. It only understands 256-bit numbers and instructions to move them. Today, we peel back the high-level abstraction to see the raw electrical signals of the world computer."
Key Discussion Points
Why 256-bit?
Most modern CPUs are 64-bit. Why did Ethereum choose 256? (Answer: To match the output size of Keccak-256 and Secp256k1 curves, minimizing truncation and extra hashing steps.)
The Cost of Storage
Discuss why SSTORE costs 20,000 gas while MSTORE costs 3. Explain that storage is a permanent change to the global state that every node must store forever.
Answer Key: Opcode Analyst Worksheet
Part 1: The Stack Challenge
PUSH1 0x42: [0x42]
PUSH1 0x0A: [0x42, 0x0A]
ADD: [0x4C] (which is 66 decimal + 10 decimal = 76 decimal / 0x4C hex)
PUSH1 0x02: [0x4C, 0x02]
MUL: [0x98] (76 * 2 = 152 / 0x98 hex)
Part 2: Storage Mapping
Slot 0: a (Full 32 bytes)
Slot 1: b, c, and d (Packed together: 16 + 8 + 8 = 32 bytes)
Slot 2: e (Address is 20 bytes, fits in a new slot)
Part 3: Bytecode Logic
Translation: 1. Push 0x42 (66) onto stack. 2. Push 0x00 (offset) onto stack. 3. MSTORE: Store 0x42 at memory offset 0. 4. Push 0x20 (32 bytes length) onto stack. 5. Push 0x00 (offset) onto stack. 6. RETURN: Return 32 bytes from memory starting at offset 0. Summary: The contract simply returns the value 0x42.
Advanced Blockchain Development Curriculum • Graduate Level
Solidity Logic Slides Solidity Logic
STATE • ACCESS • TRANSFERS
Smart Contract Blueprint
Core Components
State Variables: Persistent data
Functions: Execution logic
Modifiers: Reusable requirements
Events: Logged outputs
// Visibility Matters
public: Getter generated
private: Only this contract
internal: This + derived
external: Only from outside
// Mutability
view: Reads state, no write
pure: No read, no write
payable: Can receive Ether
Access Control Patterns
Ownable Pattern
Simple admin structure. One address holds absolute power over protected functions.
Role-Based (RBAC)
Granular permissions (MINTER, BURNER, ADMIN). Better for complex DAO structures.
Check-Effects-Interactions
Vital Security Pattern!
Prevents reentrancy by updating state BEFORE external calls.
Moving Value
transfer()
2300 Gas Stipend
Throws on failure
Legacy
vs
call()
Forwards all gas (customizable)
Returns boolean success
Recommended
Professional Standard
(bool success, ) = recipient.call{value: amount}("");
require(success, "Transfer failed.");
State Master Worksheet State Master
Lab 02: Solidity Logic & Modifiers
Score / 50
Student Investigator
Wallet ID (Simulated)
1
The Access Guard
Implement a Solidity modifier named onlyAfter(uint _time) that ensures a function can only be called after a specific block timestamp. Then, show how to apply it to a function.
SOL_CODE_WORKSPACE
// Write your modifier here
// Apply it to this function
function withdraw() public __________ {
// Logic here...
}
2
Vulnerability Analysis
The following function is vulnerable to a reentrancy attack . Circle the flaw and rewrite it below using the Check-Effects-Interactions pattern.
function withdrawBalance() public {
uint amount = balances[msg.sender];
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] = 0;
}
// Secure implementation:
3
Complex Data Structures
Define a state variable that maps an address (User) to another mapping of uint256 (Asset ID) to bool (Is Active).
Explain why using a mapping is usually preferred over an array for storing a list of active users in a smart contract.
Solidity Security Key Solidity Security Key
Teacher Resource • Lesson 02
Mastery Objectives
Modifier Logic
Students should grasp the execution flow of the underscore (_) placeholder.
Security Mindset
Students must internalize the dangers of external calls before state updates.
Worksheet Solution Walkthrough
1. The Access Guard
modifier onlyAfter(uint _time) {
require(block.timestamp >= _time, "Too early!");
_;
}
function withdraw() public onlyAfter(unlockTime) { ... }
Note: Ensure students understand that block.timestamp is miner-manipulatable within a few seconds, but sufficient for most time-locks.
2. Vulnerability Analysis (Reentrancy)
The flaw is that the balances[msg.sender] = 0; line happens AFTER the call(). An attacker can call withdrawBalance repeatedly from their fallback function before the balance is zeroed.
// SECURE VERSION
function withdrawBalance() public {
uint amount = balances[msg.sender];
balances[msg.sender] = 0; // Effects before Interaction
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
3. Complex Data Structures
mapping(address => mapping(uint256 => bool)) public userAssets;
Why mappings?
O(1) Access: Arrays require O(n) iteration to find an item, which consumes linear gas. Mappings are constant time.
Gas Efficiency: Iterating over large arrays can hit the Block Gas Limit, rendering the function uncallable.
Common Pitfalls to Watch For
Forgetting _;: Without the underscore, the function body never executes.
tx.origin vs msg.sender: Warn students NEVER to use tx.origin for authorization (vulnerable to phishing).
Overflows: Note that since Solidity 0.8.0, overflow checks are built-in (SafeMath is no longer required).
DeFi Architect Slides DeFi Architect
Token Standards & AMM Primitives
ERC-20
The Standard for Fungibility
Required Functions
- totalSupply()
- balanceOf(address)
- transfer(to, amount)
- approve(spender, amount)
- transferFrom(from, to, amount)
Allows tokens to be treated like currency where every unit is identical and interchangeable.
The "Allowance" Mechanism
1
User Approves Smart Contract to spend X tokens.
2
Smart Contract calls transferFrom to pull tokens.
Critical for interaction with DEXs and Lending protocols.
Automated Market Makers (AMM)
The Golden Formula
\[ x \cdot y = k \]
Reserve A
*
Reserve B
Liquidity Provision
Users deposit pairs of tokens (x and y) to provide depth. They receive "LP Tokens" representing their share of the pool.
Price Discovery
Swapping token X for Y changes their relative balances, shifting the price along the curve while keeping k constant.
ERC-721: Uniqueness
Non-Fungible
TokenID
Each token is a unique 256-bit ID. Mappings link IDs to owners, not just balances.
Metadata (URI)
Links to off-chain data (IPFS/JSON) to define traits, images, and rarity.
ID
#4821
Owner
0x7a...f2
Token Standard Lab Token Forge
Lab 03 • Standards & DeFi
BLOCK_HEIGHT: PENDING
NETWORK: ETH_MAINNET_FORK
Part 1: The ERC-20 Interface
Smart contracts often use an Interface to interact with other contracts without knowing their implementation. Fill in the missing function signatures for a standard ERC-20 interface.
interface IERC20 {
// 1. Returns the amount of tokens in existence
function external view returns (uint256);
// 2. Moves tokens from caller to recipient
function transfer(address to, uint256 amount) external returns ();
// 3. Returns remaining tokens spender is allowed to spend on behalf of owner
function external view returns (uint256);
}
Part 2: Constant Product Math
In a Uniswap V2-style pool, assume the following initial state:
Token X (DAI): 1,000
Token Y (ETH): 10
k = 10,000
Scenario A: Swap Execution
A user wants to swap 500 DAI for ETH. Ignoring fees, how much ETH will the user receive? Show your calculation using \( x \cdot y = k \).
Scenario B: Slippage & Price Impact
Explain why a swap of 10,000 DAI would be problematic for this specific pool.
Part 3: NFT Logic (ERC-721)
What is the primary difference between how "ownership" is tracked in an ERC-20 contract versus an ERC-721 contract at the state level?
ERC-20 Ownership
ERC-721 Ownership AMM Math Guide AMM Math Guide
Teacher Resource • Lesson 03
The Mathematics of Liquidity
The "Constant Product" formula is the engine behind early DeFi. It's crucial for graduate students to understand that the price is not "set" by an oracle, but derived from the ratio of reserves.
Worksheet Solution Walkthrough
Part 1: ERC-20 Interface
1. function totalSupply() external view returns (uint256);
2. returns (bool);
3. function allowance(address owner, address spender) ...
Part 2: Constant Product Math (Uniswap)
Initial: x = 1000, y = 10, k = 10,000
Scenario A: Swap 500 DAI
New X = 1,000 + 500 = 1,500
Since k must remain 10,000: \( 1500 \cdot NewY = 10,000 \)
New Y = 10,000 / 1,500 = 6.666...
Amount out = Old Y - New Y = 10 - 6.66 = 3.333 ETH
Scenario B: Slippage
Swapping 10,000 DAI into a pool with only 1,000 DAI reserve is impossible. Even at "zero" ETH price, the user would exhaust the pool. This demonstrates the Liquidity Depth concept—large trades require massive pools to avoid catastrophic price impact.
Part 3: NFT vs Token State
// ERC-20
mapping(address => uint256) balances;
// One address maps to a number.
// ERC-721
mapping(uint256 => address) owners;
// One unique ID maps to an address.
Pedagogical Tips
The "Lego" Metaphor: Explain that ERC-20 is like Lego blocks. Because they all share the same interface (transfer, approve), a DEX can list 10,000 different tokens using the exact same code.
Impermanent Loss: (Advanced Extension) Mention that liquidity providers lose value if the price of tokens diverges significantly from their entry point compared to just holding the tokens.
Gas Efficiency Slides Gas Efficiency
Mastering the Cost of Execution
21,000 GAS BASE
Why Gas Matters
Halting Problem
The EVM is Turing-complete. Gas prevents infinite loops from crashing the network by charging for every step of execution.
Economic Incentives
Miners prioritize transactions with higher gas prices. Efficient code = Lower user costs = Higher adoption.
Operation Costs
ADD / SUB / OR 3 Gas
MLOAD / MSTORE 3 Gas
SLOAD (Cold) 2,100 Gas
SSTORE (Update) 5,000 Gas
SSTORE (Init) 20,000 Gas
Optimization 1: Storage Packing
The EVM reads and writes in 32-byte slots . Grouping variables smaller than 32 bytes can save massive gas by combining multiple writes into one.
Inefficient
uint128 a;
uint256 b; // Interrupts!
uint128 c;
Result: 3 Slots used.
Optimized
uint128 a;
uint128 c; // Packed!
uint256 b;
Result: 2 Slots used.
Optimization 2: Memory vs. Calldata
Memory
Copying from calldata to memory costs gas.
Use only if you need to modify the input.
Calldata
Read-only input area. Cheapest access.
Use for external function arguments.
"The best optimization is the code you don't run."
Storage Slot Lab Storage Slot Lab
Lesson 04: Gas Optimization & Layout
Developer
Part 1: The Packing Puzzle
Consider the contract below. Draw a diagram of the storage slots (32 bytes each) and label where each variable is stored. Assume variables are packed in order of declaration.
contract GasLab {
address public owner; // 20 bytes
bool public isActive; // 1 byte
uint32 public id; // 4 bytes
uint256 public balance; // 32 bytes
uint128 public smallBal; // 16 bytes
uint64 public score; // 8 bytes
}
Slot 0:
Slot 1:
Slot 2:
Slot 3:
Sketch the internal byte-layout for each slot.
Part 2: The Gas Guzzler
The function below is highly inefficient. It reads from storage inside a loop. Refactor it to minimize gas costs.
uint[] public scores;
uint public total;
function sumScores() public {
for(uint i = 0; i < scores.length; i++) {
total += scores[i]; // Storage Write + Read
}
}
// Optimized function implementation:
Part 3: Cost Analysis
Scenario Location Gas Estimation Reading a state variable for the first time in a txn Cold Storage Enter Gas... Storing a 32-byte value in memory Memory Enter Gas...
Short Answer:
Explain why "unbounded loops" (loops that grow with user data) are considered a security risk in Ethereum.
Optimization Key Optimization Key
Teacher Resource • Lesson 04
Core Philosophy
"Optimization in Solidity is not about micro-benchmarking CPU cycles, but about minimizing the footprint on the global state. Storage is the most expensive resource; caching data in memory is the primary tool for efficiency."
Worksheet Solution Walkthrough
Part 1: The Packing Puzzle
Slot 0: [Owner (20) | isActive (1) | id (4)] // 25/32 bytes used
Slot 1: [balance (32)] // Full slot
Slot 2: [smallBal (16) | score (8)] // 24/32 bytes used
Key Insight: Even if there is space in Slot 0, uint256 always starts a new slot because it is exactly 32 bytes and cannot be split.
Part 2: The Gas Guzzler (Refactoring)
The goal is to move the total write OUTSIDE the loop.
function sumScores() public {
// 1. Cache the array in memory (saves SLOAD in loop)
uint[] memory _scores = scores;
uint _tempTotal = 0;
for(uint i = 0; i < _scores.length; i++) {
_tempTotal += _scores[i]; // Pure memory math
}
// 2. Single storage write at the end
total = _tempTotal;
}
Part 3: Cost Analysis
Cold SLOAD: 2,100 Gas (accessing a previously untouched slot).
Memory MSTORE: 3 Gas (plus dynamic expansion cost).
Unbounded Loops: Risk of hitting the Block Gas Limit . If an array grows too large, the function will exceed the gas limit and revert, permanently locking the contract's functionality.
Teaching Tip: The "Cashier" Analogy
Imagine a cashier (EVM) who charges you $20 for every time they have to walk to the back warehouse (Storage), but only 3 cents for every time they use the calculator in front of them (Memory). If they need to count 10 items, it's better to bring all 10 items to the counter once, rather than walking back and forth 10 times.
Web3 Bridge Slides Web3 Bridge
Connecting Logic to the User
Contract-to-Contract Communication
The "Interface" Pattern
Contracts don't need source code to talk; they only need the Address and the Function Signature .
// Example: Calling an ERC20
IERC20(tokenAddr).transfer(to, amt);
Call Styles
The DApp Stack
Provider
Metamask / WalletConnect. Manages keys and signing.
Ethers.js / Viem
The library that translates JS calls into JSON-RPC for the node.
ABI
The "Map". Tells JavaScript which functions exist on the contract.
const contract = new ethers.Contract(address, abi, signer);
await contract.mint(1); // One line to change state!
The World Outside
Oracles
Blockchains can't "fetch" external data (API calls are non-deterministic). Oracles like Chainlink push off-chain data onto the ledger.
Events
Contracts emit logs (Events). Frontends "listen" to these to update the UI without refreshing or polling the whole chain.
DApp Integration Worksheet DApp Integration
Lesson 05: The Final Connection
FINAL
LAB
1
Understanding the ABI
The Application Binary Interface (ABI) is a JSON file generated by the compiler. Explain why the frontend needs the ABI even though the contract bytecode is already on the blockchain.
Write your explanation here...
2
Transaction Lifecycle
Order the following steps (1-5) required to execute a function on a smart contract from a web browser using Ethers.js.
The user signs the transaction hash in their wallet (e.g., MetaMask).
Connect to the Blockchain Provider (e.g., window.ethereum).
Instantiate the Contract object using Address, ABI, and Signer.
Call the contract method and wait for the transaction to be mined.
The transaction is broadcast to the network nodes via the Provider.
3
Reacting to State
"I want my website to show a pop-up whenever someone buys a token, without the user having to refresh the page."
Which Solidity keyword must be used in the contract, and how does the frontend library handle this?
Contract Level Keyword:
Frontend Strategy:
DApp Deployment Guide DApp Deployment Guide
Teacher Resource • Lesson 05
The Deployment Workflow
The final stage of the sequence connects the abstract "on-chain" code with a practical "off-chain" interface. Students often struggle with the asynchronous nature of blockchain—waiting for block confirmations is a significant change from traditional web development.
Worksheet Solution Walkthrough
1. Understanding the ABI
Answer: The blockchain only stores bytecode (hex). The bytecode contains no information about function names or parameter types. The ABI acts as a translation layer, telling the frontend how to encode a function call (e.g., "mint(uint256)") into the 4-byte selector the EVM expects.
2. Transaction Lifecycle (Order)
Connect to the Blockchain Provider.
Instantiate the Contract object.
The user signs the transaction hash in their wallet.
The transaction is broadcast to the network nodes.
Call the contract method and wait for mining (Wait for receipts).
3. Reacting to State
Contract Level: event and emit.
Frontend Strategy: Using a WebSocket provider or periodic polling to listen for the specific event name. In Ethers.js: contract.on("EventName", (args) => { ... }).
Discussion: The "Turing-Complete Social Agreement"
Return to the Essential Question : "How can Turing-complete code automate complex agreements?" Discuss the limitations:
Deterministic Nature: Can't call a random number generator or a weather API directly.
Immutability: If the code has a bug, it's there forever (unless a proxy pattern was used).
Cost: Execution is expensive, so logic should be kept off-chain whenever possible.
© 2026 Blockchain Graduate Program • Smart Contract Architecture Sequence