[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-9-huff-sprachgrundlagen-makros-labels-opcodes":3},{"article":4,"author":54},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":34,"related_articles":35},"d7000000-0000-0000-0000-000000000109","a0000000-0000-0000-0000-000000000072","Deep EVM #9: Huff-Sprachgrundlagen — Makros, Labels und rohe Opcodes","deep-evm-9-huff-sprachgrundlagen-makros-labels-opcodes","Eine praktische Einfuehrung in Huff, die Low-Level-EVM-Assemblersprache, die Ihnen direkte Kontrolle ueber jeden Opcode, jedes Byte Bytecode und jede Gas-Einheit gibt.","## Was ist Huff?\n\nSolidity ist eine wunderbare Abstraktion — bis sie es nicht mehr ist. Wenn Sie einen Contract brauchen, der in 100 Bytes Runtime-Bytecode passt, Funktionen in O(1) mit einer gepackten Sprungtabelle dispatcht oder 200 Gas auf einem heissen Pfad einspart, brauchen Sie etwas naeher am Metall. Dieses Etwas ist **Huff** — eine Low-Level-EVM-Assemblersprache mit einem duennen Makrosystem, das Ihnen direkte Kontrolle ueber jeden Opcode gibt.\n\n## Huff vs. Yul vs. Solidity\n\n| Merkmal | Solidity | Yul | Huff |\n|---------|----------|-----|------|\n| Abstraktionsniveau | Hoch | Mittel | Niedrig |\n| Typ-System | Stark | Keines | Keines |\n| Variablen | Ja | Ja | Nein |\n| Stack-Kontrolle | Automatisch | Semi-automatisch | Manuell |\n| Bytecode-Groesse | Am groessten | Mittel | Am kleinsten |\n\nIn Huff gibt es keine Variablen. Sie arbeiten direkt mit dem Stack und muessen den Zustand jedes Elements im Kopf behalten.\n\n## Grundlegende Syntax\n\n### Makros — die grundlegende Einheit\n```huff\n#define macro MAIN() = takes(0) returns(0) {\n    \u002F\u002F Funktionsselektor aus Calldata laden\n    0x00 calldataload 0xe0 shr\n    \n    \u002F\u002F Gegen bekannte Selektoren pruefen\n    dup1 __FUNC_SIG(transfer) eq transfer jumpi\n    dup1 __FUNC_SIG(balanceOf) eq balanceOf jumpi\n    \n    \u002F\u002F Kein Match -> revert\n    0x00 0x00 revert\n    \n    transfer:\n        TRANSFER()\n    balanceOf:\n        BALANCE_OF()\n}\n```\n\n### takes() und returns()\n`takes(n)` und `returns(m)` deklarieren, wie viele Stack-Elemente ein Makro erwartet und wie viele es zuruecklaesst. Dies ist rein deklarativ — der Compiler erzwingt es nicht, aber es dient als Dokumentation:\n\n```huff\n\u002F\u002F Erwartet 2 Stack-Elemente, laesst 1 zurueck\n#define macro ADD_TWO() = takes(2) returns(1) {\n    add  \u002F\u002F Nimmt 2, gibt 1\n}\n```\n\n### Konstanten und Jump-Labels\n```huff\n#define constant OWNER_SLOT = FREE_STORAGE_POINTER()\n#define constant MAX_SUPPLY = 0x989680  \u002F\u002F 10,000,000\n\n#define macro CHECK_OWNER() = takes(0) returns(0) {\n    caller [OWNER_SLOT] sload eq is_owner jumpi\n    0x00 0x00 revert\n    is_owner:\n}\n```\n\n## Funktionsdispatch in Huff\n\nIm Gegensatz zu Solidity, wo der Compiler den Funktionsdispatch automatisch generiert, muessen Sie ihn in Huff manuell implementieren:\n\n```huff\n#define function transfer(address,uint256) nonpayable returns (bool)\n#define function balanceOf(address) view returns (uint256)\n\n#define macro MAIN() = takes(0) returns(0) {\n    0x00 calldataload 0xe0 shr  \u002F\u002F Selektor extrahieren\n    \n    dup1 __FUNC_SIG(transfer) eq transfer_jump jumpi\n    dup1 __FUNC_SIG(balanceOf) eq balance_jump jumpi\n    0x00 0x00 revert\n    \n    transfer_jump:\n        TRANSFER()\n    balance_jump:\n        BALANCE_OF()\n}\n```\n\n## Einen einfachen ERC-20 in Huff\n\n### Storage-Layout\n```huff\n\u002F\u002F Slot 0: totalSupply\n\u002F\u002F Slot 1: name (String-Pointer)\n\u002F\u002F mapping(address => uint256) balances: keccak256(address, 2)\n\u002F\u002F mapping(address => mapping(address => uint256)) allowances: keccak256(spender, keccak256(owner, 3))\n\n#define constant BALANCE_SLOT = 0x02\n#define constant ALLOWANCE_SLOT = 0x03\n```\n\n### Balance-Abfrage\n```huff\n#define macro BALANCE_OF() = takes(0) returns(0) {\n    \u002F\u002F Adresse aus Calldata laden\n    0x04 calldataload        \u002F\u002F [address]\n    \n    \u002F\u002F Storage-Slot berechnen: keccak256(address, BALANCE_SLOT)\n    0x00 mstore              \u002F\u002F Memory[0x00] = address\n    [BALANCE_SLOT] 0x20 mstore  \u002F\u002F Memory[0x20] = 2\n    0x40 0x00 sha3           \u002F\u002F [hash]\n    \n    sload                    \u002F\u002F [balance]\n    \n    \u002F\u002F Ergebnis zurueckgeben\n    0x00 mstore\n    0x20 0x00 return\n}\n```\n\n## Bytecode-Groessenvergleich\n\nEin minimaler ERC-20:\n- Solidity (OpenZeppelin): ~2.800 Bytes Runtime\n- Yul: ~1.200 Bytes Runtime\n- Huff: ~600 Bytes Runtime\n\nWeniger Bytecode bedeutet niedrigere Bereitstellungskosten (200 Gas pro Byte) und potenziell bessere Performance, da weniger Code geladen werden muss.\n\n## Debugging von Huff\n\nHuff bietet keine Fehlermeldungen zur Laufzeit. Wenn Ihr Contract revertiert, erhalten Sie nur ein leeres Revert-Payload. Debugging-Strategien:\n\n1. **Stack-Kommentare** — Dokumentieren Sie den Stack-Zustand nach jedem Opcode\n2. **Inkrementelles Testen** — Jedes Makro einzeln mit Foundry testen\n3. **cast run** — Transaktionen auf einer Fork nachspielen und Opcode-Traces analysieren\n4. **forge debug** — Schritt-fuer-Schritt durch den Bytecode navigieren\n\n## Wann Huff verwenden?\n\n### Ja:\n- MEV-Bots, bei denen jede Gas-Einheit zaehlt\n- Minimale Proxy-Contracts (EIP-1167)\n- Vanity-Contracts mit spezifischen Bytecode-Anforderungen\n- Wenn Sie die EVM wirklich verstehen wollen\n\n### Nein:\n- Standard-Geschaeftslogik\n- Wenn das Team keine tiefen EVM-Kenntnisse hat\n- Wenn Auditierbarkeit prioritaet hat\n- Fuer Contracts mit komplexer Logik (die Fehlerquote ist zu hoch)\n\n## Fazit\n\nHuff ist die ultimative Low-Level-Sprache fuer die EVM. Kein Compiler-Overhead, kein Typ-System, keine Sicherheitsnetze — nur Sie und die Opcodes. Diese Macht hat ihren Preis: hoeheres Fehlerrisiko und schwierigeres Debugging. Aber fuer leistungskritische Anwendungen wie MEV-Bots ist Huff der Goldstandard.","\u003Ch2 id=\"was-ist-huff\">Was ist Huff?\u003C\u002Fh2>\n\u003Cp>Solidity ist eine wunderbare Abstraktion — bis sie es nicht mehr ist. Wenn Sie einen Contract brauchen, der in 100 Bytes Runtime-Bytecode passt, Funktionen in O(1) mit einer gepackten Sprungtabelle dispatcht oder 200 Gas auf einem heissen Pfad einspart, brauchen Sie etwas naeher am Metall. Dieses Etwas ist \u003Cstrong>Huff\u003C\u002Fstrong> — eine Low-Level-EVM-Assemblersprache mit einem duennen Makrosystem, das Ihnen direkte Kontrolle ueber jeden Opcode gibt.\u003C\u002Fp>\n\u003Ch2 id=\"huff-vs-yul-vs-solidity\">Huff vs. Yul vs. Solidity\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Merkmal\u003C\u002Fth>\u003Cth>Solidity\u003C\u002Fth>\u003Cth>Yul\u003C\u002Fth>\u003Cth>Huff\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Abstraktionsniveau\u003C\u002Ftd>\u003Ctd>Hoch\u003C\u002Ftd>\u003Ctd>Mittel\u003C\u002Ftd>\u003Ctd>Niedrig\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Typ-System\u003C\u002Ftd>\u003Ctd>Stark\u003C\u002Ftd>\u003Ctd>Keines\u003C\u002Ftd>\u003Ctd>Keines\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Variablen\u003C\u002Ftd>\u003Ctd>Ja\u003C\u002Ftd>\u003Ctd>Ja\u003C\u002Ftd>\u003Ctd>Nein\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Stack-Kontrolle\u003C\u002Ftd>\u003Ctd>Automatisch\u003C\u002Ftd>\u003Ctd>Semi-automatisch\u003C\u002Ftd>\u003Ctd>Manuell\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Bytecode-Groesse\u003C\u002Ftd>\u003Ctd>Am groessten\u003C\u002Ftd>\u003Ctd>Mittel\u003C\u002Ftd>\u003Ctd>Am kleinsten\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>In Huff gibt es keine Variablen. Sie arbeiten direkt mit dem Stack und muessen den Zustand jedes Elements im Kopf behalten.\u003C\u002Fp>\n\u003Ch2 id=\"grundlegende-syntax\">Grundlegende Syntax\u003C\u002Fh2>\n\u003Ch3>Makros — die grundlegende Einheit\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro MAIN() = takes(0) returns(0) {\n    \u002F\u002F Funktionsselektor aus Calldata laden\n    0x00 calldataload 0xe0 shr\n    \n    \u002F\u002F Gegen bekannte Selektoren pruefen\n    dup1 __FUNC_SIG(transfer) eq transfer jumpi\n    dup1 __FUNC_SIG(balanceOf) eq balanceOf jumpi\n    \n    \u002F\u002F Kein Match -&gt; revert\n    0x00 0x00 revert\n    \n    transfer:\n        TRANSFER()\n    balanceOf:\n        BALANCE_OF()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>takes() und returns()\u003C\u002Fh3>\n\u003Cp>\u003Ccode>takes(n)\u003C\u002Fcode> und \u003Ccode>returns(m)\u003C\u002Fcode> deklarieren, wie viele Stack-Elemente ein Makro erwartet und wie viele es zuruecklaesst. Dies ist rein deklarativ — der Compiler erzwingt es nicht, aber es dient als Dokumentation:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Erwartet 2 Stack-Elemente, laesst 1 zurueck\n#define macro ADD_TWO() = takes(2) returns(1) {\n    add  \u002F\u002F Nimmt 2, gibt 1\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Konstanten und Jump-Labels\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define constant OWNER_SLOT = FREE_STORAGE_POINTER()\n#define constant MAX_SUPPLY = 0x989680  \u002F\u002F 10,000,000\n\n#define macro CHECK_OWNER() = takes(0) returns(0) {\n    caller [OWNER_SLOT] sload eq is_owner jumpi\n    0x00 0x00 revert\n    is_owner:\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"funktionsdispatch-in-huff\">Funktionsdispatch in Huff\u003C\u002Fh2>\n\u003Cp>Im Gegensatz zu Solidity, wo der Compiler den Funktionsdispatch automatisch generiert, muessen Sie ihn in Huff manuell implementieren:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define function transfer(address,uint256) nonpayable returns (bool)\n#define function balanceOf(address) view returns (uint256)\n\n#define macro MAIN() = takes(0) returns(0) {\n    0x00 calldataload 0xe0 shr  \u002F\u002F Selektor extrahieren\n    \n    dup1 __FUNC_SIG(transfer) eq transfer_jump jumpi\n    dup1 __FUNC_SIG(balanceOf) eq balance_jump jumpi\n    0x00 0x00 revert\n    \n    transfer_jump:\n        TRANSFER()\n    balance_jump:\n        BALANCE_OF()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"einen-einfachen-erc-20-in-huff\">Einen einfachen ERC-20 in Huff\u003C\u002Fh2>\n\u003Ch3>Storage-Layout\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Slot 0: totalSupply\n\u002F\u002F Slot 1: name (String-Pointer)\n\u002F\u002F mapping(address =&gt; uint256) balances: keccak256(address, 2)\n\u002F\u002F mapping(address =&gt; mapping(address =&gt; uint256)) allowances: keccak256(spender, keccak256(owner, 3))\n\n#define constant BALANCE_SLOT = 0x02\n#define constant ALLOWANCE_SLOT = 0x03\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Balance-Abfrage\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro BALANCE_OF() = takes(0) returns(0) {\n    \u002F\u002F Adresse aus Calldata laden\n    0x04 calldataload        \u002F\u002F [address]\n    \n    \u002F\u002F Storage-Slot berechnen: keccak256(address, BALANCE_SLOT)\n    0x00 mstore              \u002F\u002F Memory[0x00] = address\n    [BALANCE_SLOT] 0x20 mstore  \u002F\u002F Memory[0x20] = 2\n    0x40 0x00 sha3           \u002F\u002F [hash]\n    \n    sload                    \u002F\u002F [balance]\n    \n    \u002F\u002F Ergebnis zurueckgeben\n    0x00 mstore\n    0x20 0x00 return\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"bytecode-groessenvergleich\">Bytecode-Groessenvergleich\u003C\u002Fh2>\n\u003Cp>Ein minimaler ERC-20:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Solidity (OpenZeppelin): ~2.800 Bytes Runtime\u003C\u002Fli>\n\u003Cli>Yul: ~1.200 Bytes Runtime\u003C\u002Fli>\n\u003Cli>Huff: ~600 Bytes Runtime\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Weniger Bytecode bedeutet niedrigere Bereitstellungskosten (200 Gas pro Byte) und potenziell bessere Performance, da weniger Code geladen werden muss.\u003C\u002Fp>\n\u003Ch2 id=\"debugging-von-huff\">Debugging von Huff\u003C\u002Fh2>\n\u003Cp>Huff bietet keine Fehlermeldungen zur Laufzeit. Wenn Ihr Contract revertiert, erhalten Sie nur ein leeres Revert-Payload. Debugging-Strategien:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Stack-Kommentare\u003C\u002Fstrong> — Dokumentieren Sie den Stack-Zustand nach jedem Opcode\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Inkrementelles Testen\u003C\u002Fstrong> — Jedes Makro einzeln mit Foundry testen\u003C\u002Fli>\n\u003Cli>\u003Cstrong>cast run\u003C\u002Fstrong> — Transaktionen auf einer Fork nachspielen und Opcode-Traces analysieren\u003C\u002Fli>\n\u003Cli>\u003Cstrong>forge debug\u003C\u002Fstrong> — Schritt-fuer-Schritt durch den Bytecode navigieren\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"wann-huff-verwenden\">Wann Huff verwenden?\u003C\u002Fh2>\n\u003Ch3>Ja:\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>MEV-Bots, bei denen jede Gas-Einheit zaehlt\u003C\u002Fli>\n\u003Cli>Minimale Proxy-Contracts (EIP-1167)\u003C\u002Fli>\n\u003Cli>Vanity-Contracts mit spezifischen Bytecode-Anforderungen\u003C\u002Fli>\n\u003Cli>Wenn Sie die EVM wirklich verstehen wollen\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Nein:\u003C\u002Fh3>\n\u003Cul>\n\u003Cli>Standard-Geschaeftslogik\u003C\u002Fli>\n\u003Cli>Wenn das Team keine tiefen EVM-Kenntnisse hat\u003C\u002Fli>\n\u003Cli>Wenn Auditierbarkeit prioritaet hat\u003C\u002Fli>\n\u003Cli>Fuer Contracts mit komplexer Logik (die Fehlerquote ist zu hoch)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"fazit\">Fazit\u003C\u002Fh2>\n\u003Cp>Huff ist die ultimative Low-Level-Sprache fuer die EVM. Kein Compiler-Overhead, kein Typ-System, keine Sicherheitsnetze — nur Sie und die Opcodes. Diese Macht hat ihren Preis: hoeheres Fehlerrisiko und schwierigeres Debugging. Aber fuer leistungskritische Anwendungen wie MEV-Bots ist Huff der Goldstandard.\u003C\u002Fp>\n","de","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:30.121602Z","Einfuehrung in Huff, die Low-Level-EVM-Assemblersprache. Makros, Labels, takes\u002Freturns und wie Huff-Bytecode sich von Solidity-Output unterscheidet.","Huff Sprache EVM",null,"index, follow",[21,26,30],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000017","Huff","huff","Blockchain",[36,42,48],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":34,"published_at":41},"d0000000-0000-0000-0000-000000000611","Die Ethereum-Interoperabilitaetsschicht: Wie 55+ L2s zu einer Chain werden","ethereum-interoperabilitaetsschicht-55-l2s-eine-chain","Ethereum hat 55+ Layer-2-Rollups, die Liquiditaet und Nutzererfahrung fragmentieren. Die Ethereum-Interoperabilitaetsschicht — bestehend aus Cross-Rollup-Messaging, Shared Sequencern und Based Rollups — zielt darauf ab, sie zu einem einzigen komponierbaren Netzwerk zu vereinen.","2026-03-28T10:44:45.264352Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":34,"published_at":47},"d0000000-0000-0000-0000-000000000610","ZK-Beweise jenseits von Rollups: Verifizierbare KI-Inferenz auf Ethereum","zk-beweise-jenseits-von-rollups-verifizierbare-ki-inferenz-ethereum","Zero-Knowledge-Beweise sind nicht mehr nur ein Skalierungswerkzeug. Im Jahr 2026 ermoeglicht zkML verifizierbare KI-Inferenz on-chain, ZK-Coprozessoren verlagern schwere Berechnungen off-chain mit On-Chain-Verifizierung, und neue Beweissysteme wie SP1 und Jolt machen es praktikabel.","2026-03-28T10:44:45.257775Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":34,"published_at":53},"d0000000-0000-0000-0000-000000000587","EIP-7702 in der Praxis: Smart-Account-Flows nach Pectra erstellen","eip-7702-in-der-praxis-smart-account-flows-nach-pectra-erstellen","EIP-7702 ermoeglicht jedem Ethereum-EOA, innerhalb einer einzelnen Transaktion voruebergehend als Smart Contract zu agieren. So implementieren Sie Batch-Transaktionen, Gas-Sponsoring und Social Recovery mit dem neuen Account-Abstraction-Primitiv.","2026-03-28T10:44:43.781201Z",{"id":13,"name":55,"slug":56,"bio":57,"photo_url":18,"linkedin":18,"role":58,"created_at":59,"updated_at":59},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]