Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

There is huff-rs and huff-neo?

Yes, there are two versions of the Huff compiler. The original compiler, huff-rs is no longer maintained, and its planned successor huff2 has been discontinued. huff-neo tries to step-in and continues the development and also tries to evolve the Huff language where necessary.

New in huff-neo

There are some new features in huff-neo that are not available in huffc.

Allowed use of built-in functions for constants and code tables

The usage of built-in functions for constants and code tables is now possible.

#define constant FUNC_TEST = __FUNC_SIG("test(uint256)")
#define constant BYTES_HELLO = __BYTES("hello")

#define code_table TEST_TABLE {
    0x123
    __FUNC_SIG("test(uint256)")
    __BYTES("hello")
    __LEFTPAD(__FUNC_SIG("test(uint256)")) // New built-in function __LEFTPAD
    [FUNC_TEST]
    [BYTES_HELLO]
}

Arithmetic expressions in constants

Constants can use arithmetic expressions evaluated at compile time.

#define constant BASE = 0x20
#define constant OFFSET = 0x04
#define constant COMBINED = [BASE] + [OFFSET]      // 0x24

#define constant WORD_SIZE = 0x20
#define constant HALF_WORD = [WORD_SIZE] / 0x02    // 0x10

#define constant COMPLEX = (0x0a + 0x05) * 0x02    // 0x1e

Supported operators: +, -, *, /, % (binary), - (unary). Parentheses () for grouping. See the Constants documentation for details.

New builtin constant: __NOOP

A special constant that generates no bytecode, useful for optional macro arguments and conditional compilation patterns.

// Macro with optional operation
#define macro EXECUTE_OPTIONAL(op) = takes(0) returns(0) {
    <op>          // Can be __NOOP to skip this operation
    0x01 0x02 add
}

// With operation
EXECUTE_OPTIONAL(pop)  // Generates: pop, push 0x01, push 0x02, add

// Without operation (generates no extra bytecode)
EXECUTE_OPTIONAL(__NOOP)  // Generates: push 0x01, push 0x02, add

See the Builtin Constants documentation for details.

New builtin functions

There are new builtin functions available in huff-neo.

  • __LEFTPAD - Left pads a hex input or the result of a passed builtin in a constant or a code table.
  • __BYTES - Converts a string to the UTF-8 representation bytes and pushes it to the stack.
  • __ASSERT_PC - Validates bytecode position at compile-time to ensure instructions are at expected offsets.
  • __argsstart - Pushes the offset of the ABI-encoded constructor arguments, so a constructor reads them as Solidity does. It replaces __CODECOPY_DYN_ARG of huff-rs.

__BYTES() example

#define macro MAIN() = takes (0) returns (0) {
    __BYTES("hello") // Will push UTF-8 encoded string (PUSH5 0x68656c6c6f)
}

__ASSERT_PC() example

Validates that bytecode is positioned at expected offsets, useful for ensuring jump destinations align correctly. Can be combined with for-loops and constants for precise bytecode positioning.

#define constant TARGET_OFFSET = 0x20

#define macro MAIN() = takes(0) returns(0) {
    __ASSERT_PC(0x00)           // Assert we're at the start

    // Fill space to reach target offset using for-loop with constant
    for(i in 0..[TARGET_OFFSET]) {
        stop  // Expands to 32 stop instructions = 32 bytes
    }

    __ASSERT_PC([TARGET_OFFSET]) // Assert we're at byte 32
    target:                      // Label for jump destination
}

See the Builtin Functions documentation for complete details.

Constructor arguments and tuple types

-i and -n append the constructor arguments as Solidity’s abi.encode does, typed by #define function constructor(...), so the same bytecode works with arguments appended by Foundry or cast. Function, event and error definitions take tuple types such as (address maker, uint256 amount), and -g declares them as structs.

First-class macros

Macros can now be passed as arguments to other macros and invoked dynamically, making code more reusable and flexible.

#define macro ADD(a, b) = takes(0) returns(1) {
    <a> <b> add
}

#define macro APPLY(fn, x, y) = takes(0) returns(1) {
    <fn>(<x>, <y>)  // Invoke macro with arguments
}

#define macro MAIN() = takes(0) returns(0) {
    APPLY(ADD, 0x05, 0x06)  // Expands to: 0x05 0x06 add
}

See the Macros and Functions documentation for more details.

Compile-time for loops

Generate repetitive code patterns at compile-time using for loops that expand before bytecode generation.

#define constant COUNT = 10

#define macro INIT_STORAGE() = takes(0) returns(0) {
    // Initialize storage slots 0 through 9 with zero
    for(i in 0..[COUNT]) {
        0x00 <i> sstore
    }
}

#define macro PUSH_SEQUENCE() = takes(0) returns(5) {
    // Generate: 0x00 0x02 0x04 0x06 0x08
    for(i in 0..10 step 2) {
        <i>
    }
}

See the Compile-Time Loops documentation for complete details and examples.

Compile-time if/else statements

Generate conditional code at compile-time using if/else/else if statements that expand before bytecode generation. Only the matching branch is compiled into the final bytecode.

#define constant MODE = 0x01
#define constant DEBUG = 0x00

#define macro MAIN() = takes(0) returns(0) {
    if ([MODE] == 0x01) {
        // This code is compiled (condition is true)
        0xAA 0x00 mstore
    } else if ([MODE] == 0x02) {
        // Not compiled
        0xBB 0x00 mstore
    } else {
        // Not compiled
        0xCC 0x00 mstore
    }

    // Supports logical NOT
    if (![DEBUG]) {
        // This code is compiled (DEBUG is 0, !0 = 1)
        0xFF 0x00 mstore
    }
}

Supported features:

  • Comparison operators: ==, !=, <, >, <=, >=
  • Logical NOT: !
  • Arithmetic expressions: ([A] + [B]) > [C]
  • Nested if statements
  • If/else if/else chains

See the Compile-Time Conditionals documentation for complete details and examples.

New test capabilities

hnc test runs tests on Foundry’s EVM executor, the same engine as forge test. Tests can use cheatcodes, fork a chain with --rpc-url, and print logs and traces with the verbosity levels of forge test. See Tests.