[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-9-introduccion-huff-macros-etiquetas-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},"d8000000-0000-0000-0000-000000000109","a0000000-0000-0000-0000-000000000082","Deep EVM #9: Introducción a Huff — Macros, Etiquetas y Opcodes Crudos","deep-evm-9-introduccion-huff-macros-etiquetas-opcodes","Una introducción práctica a Huff, el lenguaje de ensamblador EVM de bajo nivel que te da control directo sobre cada opcode, cada byte de bytecode y cada unidad de gas.","## ¿Qué es Huff?\n\nHuff es un lenguaje de ensamblador de bajo nivel para la EVM que te da control total sobre el bytecode generado. A diferencia de Yul, que proporciona variables con nombre y funciones, Huff opera directamente sobre el stack — escribes opcodes crudos organizados en macros reutilizables.\n\nHuff fue creado por Aztec Protocol para escribir contratos extremadamente optimizados en gas. Hoy es la herramienta preferida para desarrolladores de MEV, puentes cross-chain y cualquier aplicación donde cada unidad de gas cuenta.\n\n## ¿Por qué Huff en lugar de Yul?\n\nYul es excelente, pero tiene limitaciones:\n\n- El compilador de Yul inserta su propia gestión de memoria\n- Las variables locales de Yul a veces generan SWAP\u002FDUP innecesarios\n- No puedes controlar el layout exacto del bytecode\n- No puedes crear jump tables O(1)\n\nHuff elimina todas estas capas de abstracción. Lo que escribes es (casi) exactamente lo que se despliega.\n\n## Estructura de un contrato Huff\n\n```huff\n\u002F\u002F Definir la interfaz\n#define function balanceOf(address) view returns (uint256)\n#define function transfer(address, uint256) nonpayable returns (bool)\n\n\u002F\u002F Constantes\n#define constant OWNER_SLOT = FREE_STORAGE_POINTER()\n\n\u002F\u002F Macro principal: punto de entrada\n#define macro MAIN() = takes(0) returns(0) {\n    \u002F\u002F Leer el selector de función (primeros 4 bytes)\n    0x00 calldataload 0xe0 shr\n    \n    \u002F\u002F Despacho de funciones\n    dup1 __FUNC_SIG(balanceOf)  eq balanceOf  jumpi\n    dup1 __FUNC_SIG(transfer)   eq transfer   jumpi\n    \n    \u002F\u002F Fallback: revert\n    0x00 0x00 revert\n    \n    balanceOf:\n        BALANCE_OF()\n    transfer:\n        TRANSFER()\n}\n\n\u002F\u002F Macro para balanceOf\n#define macro BALANCE_OF() = takes(0) returns(0) {\n    0x04 calldataload           \u002F\u002F [account]\n    0x00 mstore                 \u002F\u002F [] (account en mem[0x00])\n    [OWNER_SLOT] 0x20 mstore   \u002F\u002F [] (slot en mem[0x20])\n    0x40 0x00 sha3              \u002F\u002F [hash]\n    sload                       \u002F\u002F [balance]\n    0x00 mstore                 \u002F\u002F []\n    0x20 0x00 return            \u002F\u002F retorna 32 bytes\n}\n```\n\n## Macros: la unidad fundamental\n\nLas macros en Huff son bloques de código reutilizables. A diferencia de las funciones, las macros se expanden inline — no hay overhead de JUMP.\n\n```huff\n\u002F\u002F takes(N) returns(M) documenta el efecto en el stack\n#define macro REQUIRE_NOT_ZERO() = takes(1) returns(1) {\n    \u002F\u002F Stack de entrada: [value]\n    dup1                \u002F\u002F [value, value]\n    continue jumpi      \u002F\u002F [value] (salta si value != 0)\n    0x00 0x00 revert    \u002F\u002F nunca alcanzado si value != 0\n    continue:\n}\n\n\u002F\u002F Uso:\n#define macro SAFE_TRANSFER() = takes(3) returns(0) {\n    \u002F\u002F Stack: [to, amount, from]\n    dup2                \u002F\u002F [amount, to, amount, from]\n    REQUIRE_NOT_ZERO()  \u002F\u002F [amount, to, amount, from]\n    \u002F\u002F ... lógica de transferencia ...\n}\n```\n\n## Etiquetas y saltos\n\nEn Huff, las etiquetas definen destinos de salto dentro de una macro:\n\n```huff\n#define macro MAX() = takes(2) returns(1) {\n    \u002F\u002F Stack: [a, b]\n    dup2 dup2       \u002F\u002F [a, b, a, b]\n    gt              \u002F\u002F [a>b, a, b]\n    max_a jumpi     \u002F\u002F [a, b]\n    \n    \u002F\u002F b >= a: retornar b\n    swap1 pop       \u002F\u002F [b]\n    fin jump\n    \n    max_a:\n    \u002F\u002F a > b: retornar a\n    pop             \u002F\u002F [a]\n    \n    fin:\n}\n```\n\nCada etiqueta compila a un JUMPDEST en el bytecode. Los saltos son directos — no hay resolución en tiempo de ejecución como en lenguajes de alto nivel.\n\n## Constantes y almacenamiento\n\n```huff\n\u002F\u002F FREE_STORAGE_POINTER() asigna slots secuencialmente\n#define constant TOTAL_SUPPLY = FREE_STORAGE_POINTER() \u002F\u002F slot 0\n#define constant BALANCES     = FREE_STORAGE_POINTER() \u002F\u002F slot 1\n#define constant ALLOWANCES   = FREE_STORAGE_POINTER() \u002F\u002F slot 2\n\n\u002F\u002F Constantes literales\n#define constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n#define constant TRANSFER_SIG = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n```\n\n## Compilación y testing\n\nHuff se compila con el compilador `huffc`:\n\n```bash\nhuffc src\u002FMiContrato.huff -b  # Obtener bytecode\nhuffc src\u002FMiContrato.huff -r  # Obtener bytecode de runtime\n```\n\nPara testing, Huff se integra con Foundry:\n\n```solidity\nimport {HuffDeployer} from \"foundry-huff\u002FHuffDeployer.sol\";\n\ncontract MiContratoTest is Test {\n    address contrato;\n    \n    function setUp() public {\n        contrato = HuffDeployer.deploy(\"MiContrato\");\n    }\n    \n    function testBalanceOf() public {\n        \u002F\u002F Interactuar con el contrato desplegado\n        (bool ok, bytes memory data) = contrato.staticcall(\n            abi.encodeWithSignature(\"balanceOf(address)\", address(this))\n        );\n        assertTrue(ok);\n    }\n}\n```\n\n## Comparación de tamaño de bytecode\n\nPara un token ERC-20 básico:\n\n| Lenguaje | Bytecode runtime | Gas de despliegue |\n|----------|-----------------|-------------------|\n| Solidity (optimizado) | ~2,400 bytes | ~480,000 gas |\n| Yul | ~800 bytes | ~160,000 gas |\n| Huff | ~350 bytes | ~70,000 gas |\n\nHuff produce bytecode 7x más compacto que Solidity. En despliegue, esto se traduce en ahorros masivos.\n\n## Conclusión\n\nHuff es el lenguaje más cercano al metal que puedes usar para la EVM. Las macros proporcionan reutilización sin overhead, las etiquetas dan control preciso sobre el flujo, y la ausencia de abstracciones garantiza que lo que escribes es lo que se despliega. En los próximos artículos exploraremos gestión avanzada del stack, jump tables O(1) y patrones de ejecución adaptativa.","\u003Ch2 id=\"qu-es-huff\">¿Qué es Huff?\u003C\u002Fh2>\n\u003Cp>Huff es un lenguaje de ensamblador de bajo nivel para la EVM que te da control total sobre el bytecode generado. A diferencia de Yul, que proporciona variables con nombre y funciones, Huff opera directamente sobre el stack — escribes opcodes crudos organizados en macros reutilizables.\u003C\u002Fp>\n\u003Cp>Huff fue creado por Aztec Protocol para escribir contratos extremadamente optimizados en gas. Hoy es la herramienta preferida para desarrolladores de MEV, puentes cross-chain y cualquier aplicación donde cada unidad de gas cuenta.\u003C\u002Fp>\n\u003Ch2 id=\"por-qu-huff-en-lugar-de-yul\">¿Por qué Huff en lugar de Yul?\u003C\u002Fh2>\n\u003Cp>Yul es excelente, pero tiene limitaciones:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>El compilador de Yul inserta su propia gestión de memoria\u003C\u002Fli>\n\u003Cli>Las variables locales de Yul a veces generan SWAP\u002FDUP innecesarios\u003C\u002Fli>\n\u003Cli>No puedes controlar el layout exacto del bytecode\u003C\u002Fli>\n\u003Cli>No puedes crear jump tables O(1)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Huff elimina todas estas capas de abstracción. Lo que escribes es (casi) exactamente lo que se despliega.\u003C\u002Fp>\n\u003Ch2 id=\"estructura-de-un-contrato-huff\">Estructura de un contrato Huff\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F Definir la interfaz\n#define function balanceOf(address) view returns (uint256)\n#define function transfer(address, uint256) nonpayable returns (bool)\n\n\u002F\u002F Constantes\n#define constant OWNER_SLOT = FREE_STORAGE_POINTER()\n\n\u002F\u002F Macro principal: punto de entrada\n#define macro MAIN() = takes(0) returns(0) {\n    \u002F\u002F Leer el selector de función (primeros 4 bytes)\n    0x00 calldataload 0xe0 shr\n    \n    \u002F\u002F Despacho de funciones\n    dup1 __FUNC_SIG(balanceOf)  eq balanceOf  jumpi\n    dup1 __FUNC_SIG(transfer)   eq transfer   jumpi\n    \n    \u002F\u002F Fallback: revert\n    0x00 0x00 revert\n    \n    balanceOf:\n        BALANCE_OF()\n    transfer:\n        TRANSFER()\n}\n\n\u002F\u002F Macro para balanceOf\n#define macro BALANCE_OF() = takes(0) returns(0) {\n    0x04 calldataload           \u002F\u002F [account]\n    0x00 mstore                 \u002F\u002F [] (account en mem[0x00])\n    [OWNER_SLOT] 0x20 mstore   \u002F\u002F [] (slot en mem[0x20])\n    0x40 0x00 sha3              \u002F\u002F [hash]\n    sload                       \u002F\u002F [balance]\n    0x00 mstore                 \u002F\u002F []\n    0x20 0x00 return            \u002F\u002F retorna 32 bytes\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"macros-la-unidad-fundamental\">Macros: la unidad fundamental\u003C\u002Fh2>\n\u003Cp>Las macros en Huff son bloques de código reutilizables. A diferencia de las funciones, las macros se expanden inline — no hay overhead de JUMP.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F takes(N) returns(M) documenta el efecto en el stack\n#define macro REQUIRE_NOT_ZERO() = takes(1) returns(1) {\n    \u002F\u002F Stack de entrada: [value]\n    dup1                \u002F\u002F [value, value]\n    continue jumpi      \u002F\u002F [value] (salta si value != 0)\n    0x00 0x00 revert    \u002F\u002F nunca alcanzado si value != 0\n    continue:\n}\n\n\u002F\u002F Uso:\n#define macro SAFE_TRANSFER() = takes(3) returns(0) {\n    \u002F\u002F Stack: [to, amount, from]\n    dup2                \u002F\u002F [amount, to, amount, from]\n    REQUIRE_NOT_ZERO()  \u002F\u002F [amount, to, amount, from]\n    \u002F\u002F ... lógica de transferencia ...\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"etiquetas-y-saltos\">Etiquetas y saltos\u003C\u002Fh2>\n\u003Cp>En Huff, las etiquetas definen destinos de salto dentro de una macro:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-huff\">#define macro MAX() = takes(2) returns(1) {\n    \u002F\u002F Stack: [a, b]\n    dup2 dup2       \u002F\u002F [a, b, a, b]\n    gt              \u002F\u002F [a&gt;b, a, b]\n    max_a jumpi     \u002F\u002F [a, b]\n    \n    \u002F\u002F b &gt;= a: retornar b\n    swap1 pop       \u002F\u002F [b]\n    fin jump\n    \n    max_a:\n    \u002F\u002F a &gt; b: retornar a\n    pop             \u002F\u002F [a]\n    \n    fin:\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Cada etiqueta compila a un JUMPDEST en el bytecode. Los saltos son directos — no hay resolución en tiempo de ejecución como en lenguajes de alto nivel.\u003C\u002Fp>\n\u003Ch2 id=\"constantes-y-almacenamiento\">Constantes y almacenamiento\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-huff\">\u002F\u002F FREE_STORAGE_POINTER() asigna slots secuencialmente\n#define constant TOTAL_SUPPLY = FREE_STORAGE_POINTER() \u002F\u002F slot 0\n#define constant BALANCES     = FREE_STORAGE_POINTER() \u002F\u002F slot 1\n#define constant ALLOWANCES   = FREE_STORAGE_POINTER() \u002F\u002F slot 2\n\n\u002F\u002F Constantes literales\n#define constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n#define constant TRANSFER_SIG = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"compilaci-n-y-testing\">Compilación y testing\u003C\u002Fh2>\n\u003Cp>Huff se compila con el compilador \u003Ccode>huffc\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">huffc src\u002FMiContrato.huff -b  # Obtener bytecode\nhuffc src\u002FMiContrato.huff -r  # Obtener bytecode de runtime\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Para testing, Huff se integra con Foundry:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">import {HuffDeployer} from \"foundry-huff\u002FHuffDeployer.sol\";\n\ncontract MiContratoTest is Test {\n    address contrato;\n    \n    function setUp() public {\n        contrato = HuffDeployer.deploy(\"MiContrato\");\n    }\n    \n    function testBalanceOf() public {\n        \u002F\u002F Interactuar con el contrato desplegado\n        (bool ok, bytes memory data) = contrato.staticcall(\n            abi.encodeWithSignature(\"balanceOf(address)\", address(this))\n        );\n        assertTrue(ok);\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"comparaci-n-de-tama-o-de-bytecode\">Comparación de tamaño de bytecode\u003C\u002Fh2>\n\u003Cp>Para un token ERC-20 básico:\u003C\u002Fp>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Lenguaje\u003C\u002Fth>\u003Cth>Bytecode runtime\u003C\u002Fth>\u003Cth>Gas de despliegue\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Solidity (optimizado)\u003C\u002Ftd>\u003Ctd>~2,400 bytes\u003C\u002Ftd>\u003Ctd>~480,000 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Yul\u003C\u002Ftd>\u003Ctd>~800 bytes\u003C\u002Ftd>\u003Ctd>~160,000 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Huff\u003C\u002Ftd>\u003Ctd>~350 bytes\u003C\u002Ftd>\u003Ctd>~70,000 gas\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Huff produce bytecode 7x más compacto que Solidity. En despliegue, esto se traduce en ahorros masivos.\u003C\u002Fp>\n\u003Ch2 id=\"conclusi-n\">Conclusión\u003C\u002Fh2>\n\u003Cp>Huff es el lenguaje más cercano al metal que puedes usar para la EVM. Las macros proporcionan reutilización sin overhead, las etiquetas dan control preciso sobre el flujo, y la ausencia de abstracciones garantiza que lo que escribes es lo que se despliega. En los próximos artículos exploraremos gestión avanzada del stack, jump tables O(1) y patrones de ejecución adaptativa.\u003C\u002Fp>\n","es","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:31.347689Z","Introducción práctica a Huff: macros, etiquetas, opcodes crudos y control directo del bytecode EVM para contratos ultra-optimizados.","huff lenguaje 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-000000000614","La capa de interoperabilidad de Ethereum: Como 55+ L2s se convierten en una sola cadena","capa-interoperabilidad-ethereum-55-l2s-una-sola-cadena","Ethereum tiene 55+ rollups Layer 2, fragmentando la liquidez y la experiencia del usuario. La capa de interoperabilidad de Ethereum — combinando mensajeria cross-rollup, secuenciadores compartidos y based rollups — busca unificarlos en una red componible unica.","2026-03-28T10:44:45.451917Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":34,"published_at":47},"d0000000-0000-0000-0000-000000000613","Pruebas ZK mas alla de los rollups: Inferencia de IA verificable en Ethereum","pruebas-zk-mas-alla-rollups-inferencia-ia-verificable-ethereum","Las pruebas de conocimiento cero ya no son solo una herramienta de escalabilidad. En 2026, zkML permite la inferencia de IA verificable on-chain, los coprocesadores ZK mueven el calculo pesado off-chain con verificacion on-chain, y nuevos sistemas de prueba como SP1 y Jolt lo hacen practico.","2026-03-28T10:44:45.446211Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":34,"published_at":53},"d0000000-0000-0000-0000-000000000590","EIP-7702 en la practica: construir flujos de cuenta inteligente despues de Pectra","eip-7702-en-la-practica-construir-flujos-cuenta-inteligente-despues-pectra","EIP-7702 permite a cualquier EOA de Ethereum actuar temporalmente como contrato inteligente en una sola transaccion. Asi se implementan transacciones por lotes, patrocinio de gas y recuperacion social con la nueva primitiva de account abstraction.","2026-03-28T10:44:43.986612Z",{"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"]