Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EVM Inline Assembly & Yul Masterclass

Solidity Assembly Coverage

A highly optimized low-level smart contract framework demonstrating core EVM mechanics, custom Yul error handling, bitwise packing structures, and manual execution context overrides. The codebase bypasses high-level Solidity safety layers to write custom gas-efficient mathematical assertions, environment analysis, and manual Ether transfers using raw inline assembly.


🏗 Architecture & Technical Deep Dive

1. EVM Storage Mechanics & Bitwise Packing

  • Context: EVM storage is structured as a key-value store mapping 256-bit slots to 256-bit values. A standard SSTORE write operation costs up to 20,000 gas for uninitialized slots. Storing two distinct uint128 values in separate variables wastes a full 32-byte slot, incurring massive gas overhead.
  • Implementation: The AssemblyUtils contract implements low-level bitwise packing (packTwo128) and unpacking (unpackTwo128) to fit two distinct 128-bit unsigned integers into a single 256-bit slot.
    • Packing: Shits the upper value a left by 128 bits using shl(128, a) and executes a bitwise or() with the lower value b to yield the packed representation: $$\text{packed} = (a \ll 128) \mid b$$
    • Unpacking: Shifts the packed word right by 128 bits (shr(128, packed)) to isolate a, and applies a bitwise and() mask (0xffffffffffffffffffffffffffffffff) to extract the lower 128 bits representing b. This allows two storage variables to share a single slot, saving approximately 20,000 gas on initial writes.

2. EVM Memory Management & Scratch Space Hashing

  • Context: EVM memory is a volatile linear byte array formatted in 32-byte words. In high-level Solidity, operations like keccak256(abi.encodePacked(a, b)) allocate fresh memory, copy the operands, and query the compiler's free memory pointer (0x40). This overhead adds substantial execution gas.
  • Implementation: The AssemblyUtils.efficientHash function leverages the EVM scratch space located at 0x00 to 0x3f (first 64 bytes of memory).
    • High-level Solidity reserves this scratch space specifically for transient hashing operations.
    • By executing mstore(0x00, a) and mstore(0x20, b), we write values directly to the scratch space and hash them in-place with keccak256(0x00, 0x40). This bypasses the free memory pointer update and copies, saving substantial gas.

3. Low-Level Yul Error Handling & Reverts

  • Context: When Solidity executes a revert message or a standard requirement check, it utilizes the Error(string) signature format, which requires ABI-encoding a long error string, causing significant gas bloat. Custom errors using 4-byte function selectors offer dramatic gas savings.

  • Implementation: The AssemblyErrors contract defines several custom error selectors:

    • Overflow() $\rightarrow$ 0x35278d12
    • ConditionFailed() $\rightarrow$ 0x0b1ad13b
    • Underflow() $\rightarrow$ 0xcf48f4cf

    When an assertion fails (e.g., in safeAdd or safeSub), Yul stores the 4-byte selector at memory offset 0x00 and invokes the raw revert(offset, size) opcode:

    mstore(0x00, 0xcf48f4cf00000000000000000000000000000000000000000000000000000000)
    revert(0x00, 0x04)

    This returns exactly the 4-byte selector data to the caller, bypassing any string allocation or memory-shifting logic.

4. Custom Yul Math & Value Transfers

  • Safe Subtraction (safeSub): High-level Solidity 0.8+ automatically inserts underflow checks. In Yul, subtraction is unsigned modular arithmetic that silently wraps. safeSub implements an explicit underflow check using the gt opcode: if b > a, the execution immediately reverts with the custom error Underflow(), preserving safe execution at minimal gas cost.
  • Low-Level ETH Transfers (safeTransferETH): Replaces high-level Solidity payable(to).transfer() or .send() calls (which are capped at 2,300 gas and fail on complex multisigs) with a raw call opcode. It specifies custom error handling for maximum robust execution:
    let success := call(gas(), to, amount, 0, 0, 0, 0)
    if iszero(success) {
        mstore(0x00, 0x90b8ecaa00000000000000000000000000000000000000000000000000000000) // TransferFailed()
        revert(0x00, 0x04)
    }
    This transfers the exact amount with all available gas, reverting cleanly with TransferFailed() on failure.

🧪 Testing & Quality Assurance

The test suite is built using Foundry, asserting absolute functional invariants, overflow/underflow boundaries, bitwise integrity, and custom reverting conditions to achieve 100.00% Line Coverage.

Test Suite Highlights

  • Coverage Excellence: Tests every single low-level opcode and comparison branch in AssemblyBasics, AssemblyUtils, and AssemblyErrors.
  • Fuzzing Engine: Integrates bounded fuzzing tests verifying safeAdd, safeSub, and pack/unpack transformations across random inputs and large number ranges.
  • Transfer Failure Mocking: Deploys a mock recipient contract (RevertingReceiver) that explicitly reverts on receiving Ether. This triggers the low-level call failure path to validate correct revert bubbles.

Executing the Test Suite

To execute the tests:

forge test

To run code coverage analysis:

forge coverage

📊 Coverage Report

╭-------------------------+------------------+------------------+----------------+----------------╮
| File                    | % Lines          | % Statements     | % Branches     | % Funcs        |
+=================================================================================================+
| src/AssemblyBasics.sol  | 100.00% (34/34)  | 100.00% (34/34)  | 100.00% (0/0)  | 100.00% (17/17)|
| src/AssemblyErrors.sol  | 100.00% (16/16)  | 100.00% (18/18)  | 100.00% (8/8)  | 100.00% (5/5)  |
| src/AssemblyUtils.sol   | 100.00% (16/16)  | 100.00% (16/16)  | 100.00% (2/2)  | 100.00% (8/8)  |
|-------------------------+------------------+------------------+----------------+----------------|
| Total                   | 100.00% (66/66)  | 100.00% (68/68)  | 100.00% (10/10)| 100.00% (30/30)|
╰-------------------------+------------------+------------------+----------------+----------------╯

About

Low-level Yul assembly masterclass in Solidity 0.8.26 covering EVM opcodes, memory layout, and gas optimization.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages