[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-5-vvedenie-v-yul-sekretnyj-assembler-solidity":3},{"article":4,"author":58},{"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":38,"related_articles":39},"d0000000-0000-0000-0000-000000000205","a0000000-0000-0000-0000-000000000012","Deep EVM #5: Введение в Yul — секретный ассемблер Solidity","deep-evm-5-vvedenie-v-yul-sekretnyj-assembler-solidity","Полное руководство по Yul — промежуточному языку Solidity, обеспечивающему прямой доступ к опкодам EVM. Синтаксис, типы, управление потоком и первые шаги к газоэффективному коду.","## Что такое Yul\n\nYul — это промежуточный язык, встроенный в Solidity. Он обеспечивает прямой доступ к опкодам EVM через чистый и читаемый синтаксис. В отличие от чистого ассемблера (где вы работаете со стеком напрямую), Yul предоставляет переменные, функции и управляющие конструкции — при этом компилируя в практически оптимальный байткод.\n\nYul используется в двух контекстах:\n1. **Inline assembly** — блоки `assembly { ... }` внутри Solidity-функций.\n2. **Standalone Yul** — полноценные контракты, написанные целиком на Yul.\n\nБольшинство высокооптимизированных DeFi-протоколов используют inline assembly для критических путей. Uniswap V4, Seaport, Solady — все они широко применяют Yul.\n\n## Синтаксис Yul\n\n### Переменные и присваивание\n\nВ Yul существует единственный тип данных — 256-битное беззнаковое целое (u256), эквивалентное одному слову стека EVM:\n\n```yul\nassembly {\n    \u002F\u002F Объявление переменной (инициализируется нулём)\n    let x\n\n    \u002F\u002F Объявление с присваиванием\n    let y := 42\n\n    \u002F\u002F Присваивание существующей переменной\n    x := add(y, 1)\n\n    \u002F\u002F Множественное присваивание (от функции)\n    let a, b := myFunction()\n}\n```\n\nВсе значения — 256-битные слова. Адреса, булевы значения, байты — всё хранится как u256. Yul не имеет системы типов и не проверяет переполнение.\n\n### Встроенные функции (опкоды)\n\nКаждый опкод EVM доступен как встроенная функция Yul:\n\n```yul\nassembly {\n    \u002F\u002F Арифметика\n    let sum := add(1, 2)           \u002F\u002F 1 + 2 = 3\n    let diff := sub(10, 3)         \u002F\u002F 10 - 3 = 7\n    let prod := mul(4, 5)          \u002F\u002F 4 * 5 = 20\n    let quot := div(20, 4)         \u002F\u002F 20 \u002F 4 = 5\n    let rem := mod(17, 5)          \u002F\u002F 17 % 5 = 2\n    let power := exp(2, 10)        \u002F\u002F 2^10 = 1024\n\n    \u002F\u002F Сравнение (возвращает 0 или 1)\n    let isLess := lt(3, 5)         \u002F\u002F 3 \u003C 5 = 1\n    let isEqual := eq(42, 42)      \u002F\u002F 42 == 42 = 1\n    let isZero := iszero(0)        \u002F\u002F 0 == 0 = 1\n\n    \u002F\u002F Побитовые операции\n    let masked := and(0xff, 0x1234) \u002F\u002F 0x34\n    let shifted := shr(8, 0x1234)   \u002F\u002F 0x12\n\n    \u002F\u002F Память\n    mstore(0x00, 42)               \u002F\u002F Записать 42 по адресу 0x00\n    let val := mload(0x00)         \u002F\u002F Прочитать из адреса 0x00\n\n    \u002F\u002F Хранилище\n    sstore(0, 100)                 \u002F\u002F Записать 100 в слот 0\n    let stored := sload(0)         \u002F\u002F Прочитать из слота 0\n\n    \u002F\u002F Контекст\n    let sender := caller()         \u002F\u002F msg.sender\n    let value := callvalue()       \u002F\u002F msg.value\n    let size := calldatasize()     \u002F\u002F размер calldata\n}\n```\n\n### Управление потоком\n\nYul предоставляет три управляющие конструкции:\n\n```yul\nassembly {\n    \u002F\u002F if (без else!)\n    if gt(x, 10) {\n        \u002F\u002F выполняется если x > 10\n        y := 1\n    }\n\n    \u002F\u002F switch (аналог switch\u002Fcase)\n    switch x\n    case 0 {\n        y := 100\n    }\n    case 1 {\n        y := 200\n    }\n    default {\n        y := 300\n    }\n\n    \u002F\u002F for (цикл)\n    for { let i := 0 } lt(i, 10) { i := add(i, 1) } {\n        \u002F\u002F тело цикла\n        sum := add(sum, i)\n    }\n}\n```\n\nОбратите внимание: в Yul нет `else`. Для условий с двумя ветвями используйте `switch`.\n\n### Функции\n\nYul поддерживает пользовательские функции:\n\n```yul\nassembly {\n    function safeAdd(a, b) -> result {\n        result := add(a, b)\n        if lt(result, a) {\n            revert(0, 0) \u002F\u002F переполнение\n        }\n    }\n\n    function max(a, b) -> result {\n        result := a\n        if gt(b, a) {\n            result := b\n        }\n    }\n\n    function swap(a, b) -> x, y {\n        x := b\n        y := a\n    }\n\n    let sum := safeAdd(100, 200)\n    let maximum := max(42, 17)\n    let a, b := swap(1, 2)\n}\n```\n\nФункции Yul компилируются в JUMP\u002FJUMPDEST пары — никакого ABI-кодирования, никаких внешних вызовов. Это чисто внутренние функции.\n\n## Практические примеры\n\n### Эффективное ABI-декодирование\n\nSolidity генерирует безопасное, но объёмное ABI-декодирование. В Yul вы можете декодировать calldata напрямую:\n\n```solidity\nfunction transfer(address to, uint256 amount) external {\n    assembly {\n        \u002F\u002F Первые 4 байта — селектор функции, пропускаем\n        \u002F\u002F Следующие 32 байта — адрес (правые 20 байт)\n        let to := calldataload(4)\n        \u002F\u002F Следующие 32 байта — сумма\n        let amount := calldataload(36)\n\n        \u002F\u002F Маскируем адрес (оставляем только 20 байт)\n        to := and(to, 0xffffffffffffffffffffffffffffffffffffffff)\n\n        \u002F\u002F ... логика трансфера ...\n    }\n}\n```\n\n### Эффективное хеширование\n\nKeccak256 — часто используемая операция, особенно для маппингов:\n\n```solidity\nfunction getSlot(address user, uint256 baseSlot) internal pure returns (bytes32 slot) {\n    assembly {\n        \u002F\u002F Записываем адрес в рабочее пространство\n        mstore(0x00, user)\n        \u002F\u002F Записываем базовый слот\n        mstore(0x20, baseSlot)\n        \u002F\u002F Хешируем 64 байта\n        slot := keccak256(0x00, 0x40)\n    }\n}\n```\n\nЭто экономит газ по сравнению с `abi.encodePacked(user, baseSlot)` в Solidity, который аллоцирует память и обновляет свободный указатель.\n\n### Эффективная проверка возвращаемого значения\n\n```solidity\nfunction safeTransfer(address token, address to, uint256 amount) internal {\n    assembly {\n        \u002F\u002F Кодируем calldata для transfer(address,uint256)\n        let ptr := mload(0x40)\n        mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n        mstore(add(ptr, 4), to)\n        mstore(add(ptr, 36), amount)\n\n        \u002F\u002F Вызываем\n        let success := call(gas(), token, 0, ptr, 68, 0x00, 32)\n\n        \u002F\u002F Проверяем: вызов успешен И (нет returndata ИЛИ returndata == true)\n        if iszero(and(\n            success,\n            or(\n                iszero(returndatasize()),\n                and(gt(returndatasize(), 31), eq(mload(0x00), 1))\n            )\n        )) {\n            revert(0, 0)\n        }\n    }\n}\n```\n\nЭтот паттерн — основа библиотеки SafeTransferLib от Solady. Он обрабатывает токены, которые не возвращают значение (USDT), и токены, которые возвращают bool (стандартные ERC-20).\n\n## Когда использовать Yul\n\nYul стоит использовать, когда:\n\n1. **Горячие пути** — функции, вызываемые миллионы раз (DEX swap, ордер-бук).\n2. **Битовые манипуляции** — упаковка\u002Fраспаковка данных в 256-битные слова.\n3. **Кастомное управление памятью** — избежание накладных расходов свободного указателя Solidity.\n4. **Низкоуровневые вызовы** — оптимизированные CALL\u002FDELEGATECALL без оверхеда Solidity.\n5. **MEV-боты** — каждый газ на счету.\n\nYul НЕ стоит использовать, когда:\n- Код читают другие разработчики, не знающие ассемблера.\n- Безопасность важнее оптимизации (пользовательские контракты).\n- Разница в газе незначительна (\u003C 1000 газа).\n\n## Отладка Yul\n\nОтладка Yul затруднена отсутствием привычных инструментов:\n\n```yul\n\u002F\u002F Нет console.log, но можно эмитировать события\nassembly {\n    \u002F\u002F Эмитируем анонимное событие для отладки\n    mstore(0x00, value)\n    log0(0x00, 0x20)\n}\n\n\u002F\u002F Или использовать revert с данными\nassembly {\n    mstore(0x00, value)\n    revert(0x00, 0x20) \u002F\u002F Отладка через revert reason\n}\n```\n\nНа практике используйте Foundry debugger (`forge debug`) для пошаговой отладки байткода.\n\n## Подводные камни Yul\n\n1. **Нет проверки переполнения** — все операции в Yul работают по модулю 2^256.\n2. **Нет проверки типов** — адрес, число, байты — всё u256.\n3. **Повреждение памяти** — если вы случайно перезапишете свободный указатель (0x40), Solidity будет аллоцировать память по неправильному адресу.\n4. **Stack too deep** — Yul ограничен глубиной стека в 16 элементов для DUP\u002FSWAP.\n5. **Нет returndata** по умолчанию — нужно вручную вызывать `return(offset, size)`.\n\n## Заключение\n\nYul — это мост между высокоуровневым Solidity и низкоуровневым байткодом EVM. Он предоставляет контроль над каждым аспектом выполнения — памятью, хранилищем, потоком управления — при этом сохраняя читаемый синтаксис. Освоение Yul — ключевой навык для любого серьёзного разработчика смарт-контрактов.\n\nВ следующей статье мы углубимся в управление памятью в Yul: mstore, mload, свободный указатель и паттерны эффективной аллокации.","\u003Ch2 id=\"yul\">Что такое Yul\u003C\u002Fh2>\n\u003Cp>Yul — это промежуточный язык, встроенный в Solidity. Он обеспечивает прямой доступ к опкодам EVM через чистый и читаемый синтаксис. В отличие от чистого ассемблера (где вы работаете со стеком напрямую), Yul предоставляет переменные, функции и управляющие конструкции — при этом компилируя в практически оптимальный байткод.\u003C\u002Fp>\n\u003Cp>Yul используется в двух контекстах:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Inline assembly\u003C\u002Fstrong> — блоки \u003Ccode>assembly { ... }\u003C\u002Fcode> внутри Solidity-функций.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Standalone Yul\u003C\u002Fstrong> — полноценные контракты, написанные целиком на Yul.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Большинство высокооптимизированных DeFi-протоколов используют inline assembly для критических путей. Uniswap V4, Seaport, Solady — все они широко применяют Yul.\u003C\u002Fp>\n\u003Ch2 id=\"yul\">Синтаксис Yul\u003C\u002Fh2>\n\u003Ch3>Переменные и присваивание\u003C\u002Fh3>\n\u003Cp>В Yul существует единственный тип данных — 256-битное беззнаковое целое (u256), эквивалентное одному слову стека EVM:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">assembly {\n    \u002F\u002F Объявление переменной (инициализируется нулём)\n    let x\n\n    \u002F\u002F Объявление с присваиванием\n    let y := 42\n\n    \u002F\u002F Присваивание существующей переменной\n    x := add(y, 1)\n\n    \u002F\u002F Множественное присваивание (от функции)\n    let a, b := myFunction()\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Все значения — 256-битные слова. Адреса, булевы значения, байты — всё хранится как u256. Yul не имеет системы типов и не проверяет переполнение.\u003C\u002Fp>\n\u003Ch3>Встроенные функции (опкоды)\u003C\u002Fh3>\n\u003Cp>Каждый опкод EVM доступен как встроенная функция Yul:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">assembly {\n    \u002F\u002F Арифметика\n    let sum := add(1, 2)           \u002F\u002F 1 + 2 = 3\n    let diff := sub(10, 3)         \u002F\u002F 10 - 3 = 7\n    let prod := mul(4, 5)          \u002F\u002F 4 * 5 = 20\n    let quot := div(20, 4)         \u002F\u002F 20 \u002F 4 = 5\n    let rem := mod(17, 5)          \u002F\u002F 17 % 5 = 2\n    let power := exp(2, 10)        \u002F\u002F 2^10 = 1024\n\n    \u002F\u002F Сравнение (возвращает 0 или 1)\n    let isLess := lt(3, 5)         \u002F\u002F 3 &lt; 5 = 1\n    let isEqual := eq(42, 42)      \u002F\u002F 42 == 42 = 1\n    let isZero := iszero(0)        \u002F\u002F 0 == 0 = 1\n\n    \u002F\u002F Побитовые операции\n    let masked := and(0xff, 0x1234) \u002F\u002F 0x34\n    let shifted := shr(8, 0x1234)   \u002F\u002F 0x12\n\n    \u002F\u002F Память\n    mstore(0x00, 42)               \u002F\u002F Записать 42 по адресу 0x00\n    let val := mload(0x00)         \u002F\u002F Прочитать из адреса 0x00\n\n    \u002F\u002F Хранилище\n    sstore(0, 100)                 \u002F\u002F Записать 100 в слот 0\n    let stored := sload(0)         \u002F\u002F Прочитать из слота 0\n\n    \u002F\u002F Контекст\n    let sender := caller()         \u002F\u002F msg.sender\n    let value := callvalue()       \u002F\u002F msg.value\n    let size := calldatasize()     \u002F\u002F размер calldata\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Управление потоком\u003C\u002Fh3>\n\u003Cp>Yul предоставляет три управляющие конструкции:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">assembly {\n    \u002F\u002F if (без else!)\n    if gt(x, 10) {\n        \u002F\u002F выполняется если x &gt; 10\n        y := 1\n    }\n\n    \u002F\u002F switch (аналог switch\u002Fcase)\n    switch x\n    case 0 {\n        y := 100\n    }\n    case 1 {\n        y := 200\n    }\n    default {\n        y := 300\n    }\n\n    \u002F\u002F for (цикл)\n    for { let i := 0 } lt(i, 10) { i := add(i, 1) } {\n        \u002F\u002F тело цикла\n        sum := add(sum, i)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Обратите внимание: в Yul нет \u003Ccode>else\u003C\u002Fcode>. Для условий с двумя ветвями используйте \u003Ccode>switch\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch3>Функции\u003C\u002Fh3>\n\u003Cp>Yul поддерживает пользовательские функции:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">assembly {\n    function safeAdd(a, b) -&gt; result {\n        result := add(a, b)\n        if lt(result, a) {\n            revert(0, 0) \u002F\u002F переполнение\n        }\n    }\n\n    function max(a, b) -&gt; result {\n        result := a\n        if gt(b, a) {\n            result := b\n        }\n    }\n\n    function swap(a, b) -&gt; x, y {\n        x := b\n        y := a\n    }\n\n    let sum := safeAdd(100, 200)\n    let maximum := max(42, 17)\n    let a, b := swap(1, 2)\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Функции Yul компилируются в JUMP\u002FJUMPDEST пары — никакого ABI-кодирования, никаких внешних вызовов. Это чисто внутренние функции.\u003C\u002Fp>\n\u003Ch2 id=\"\">Практические примеры\u003C\u002Fh2>\n\u003Ch3>Эффективное ABI-декодирование\u003C\u002Fh3>\n\u003Cp>Solidity генерирует безопасное, но объёмное ABI-декодирование. В Yul вы можете декодировать calldata напрямую:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function transfer(address to, uint256 amount) external {\n    assembly {\n        \u002F\u002F Первые 4 байта — селектор функции, пропускаем\n        \u002F\u002F Следующие 32 байта — адрес (правые 20 байт)\n        let to := calldataload(4)\n        \u002F\u002F Следующие 32 байта — сумма\n        let amount := calldataload(36)\n\n        \u002F\u002F Маскируем адрес (оставляем только 20 байт)\n        to := and(to, 0xffffffffffffffffffffffffffffffffffffffff)\n\n        \u002F\u002F ... логика трансфера ...\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Эффективное хеширование\u003C\u002Fh3>\n\u003Cp>Keccak256 — часто используемая операция, особенно для маппингов:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function getSlot(address user, uint256 baseSlot) internal pure returns (bytes32 slot) {\n    assembly {\n        \u002F\u002F Записываем адрес в рабочее пространство\n        mstore(0x00, user)\n        \u002F\u002F Записываем базовый слот\n        mstore(0x20, baseSlot)\n        \u002F\u002F Хешируем 64 байта\n        slot := keccak256(0x00, 0x40)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Это экономит газ по сравнению с \u003Ccode>abi.encodePacked(user, baseSlot)\u003C\u002Fcode> в Solidity, который аллоцирует память и обновляет свободный указатель.\u003C\u002Fp>\n\u003Ch3>Эффективная проверка возвращаемого значения\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function safeTransfer(address token, address to, uint256 amount) internal {\n    assembly {\n        \u002F\u002F Кодируем calldata для transfer(address,uint256)\n        let ptr := mload(0x40)\n        mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n        mstore(add(ptr, 4), to)\n        mstore(add(ptr, 36), amount)\n\n        \u002F\u002F Вызываем\n        let success := call(gas(), token, 0, ptr, 68, 0x00, 32)\n\n        \u002F\u002F Проверяем: вызов успешен И (нет returndata ИЛИ returndata == true)\n        if iszero(and(\n            success,\n            or(\n                iszero(returndatasize()),\n                and(gt(returndatasize(), 31), eq(mload(0x00), 1))\n            )\n        )) {\n            revert(0, 0)\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Этот паттерн — основа библиотеки SafeTransferLib от Solady. Он обрабатывает токены, которые не возвращают значение (USDT), и токены, которые возвращают bool (стандартные ERC-20).\u003C\u002Fp>\n\u003Ch2 id=\"yul\">Когда использовать Yul\u003C\u002Fh2>\n\u003Cp>Yul стоит использовать, когда:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Горячие пути\u003C\u002Fstrong> — функции, вызываемые миллионы раз (DEX swap, ордер-бук).\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Битовые манипуляции\u003C\u002Fstrong> — упаковка\u002Fраспаковка данных в 256-битные слова.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Кастомное управление памятью\u003C\u002Fstrong> — избежание накладных расходов свободного указателя Solidity.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Низкоуровневые вызовы\u003C\u002Fstrong> — оптимизированные CALL\u002FDELEGATECALL без оверхеда Solidity.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>MEV-боты\u003C\u002Fstrong> — каждый газ на счету.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Yul НЕ стоит использовать, когда:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Код читают другие разработчики, не знающие ассемблера.\u003C\u002Fli>\n\u003Cli>Безопасность важнее оптимизации (пользовательские контракты).\u003C\u002Fli>\n\u003Cli>Разница в газе незначительна (&lt; 1000 газа).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"yul\">Отладка Yul\u003C\u002Fh2>\n\u003Cp>Отладка Yul затруднена отсутствием привычных инструментов:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F Нет console.log, но можно эмитировать события\nassembly {\n    \u002F\u002F Эмитируем анонимное событие для отладки\n    mstore(0x00, value)\n    log0(0x00, 0x20)\n}\n\n\u002F\u002F Или использовать revert с данными\nassembly {\n    mstore(0x00, value)\n    revert(0x00, 0x20) \u002F\u002F Отладка через revert reason\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>На практике используйте Foundry debugger (\u003Ccode>forge debug\u003C\u002Fcode>) для пошаговой отладки байткода.\u003C\u002Fp>\n\u003Ch2 id=\"yul\">Подводные камни Yul\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Нет проверки переполнения\u003C\u002Fstrong> — все операции в Yul работают по модулю 2^256.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Нет проверки типов\u003C\u002Fstrong> — адрес, число, байты — всё u256.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Повреждение памяти\u003C\u002Fstrong> — если вы случайно перезапишете свободный указатель (0x40), Solidity будет аллоцировать память по неправильному адресу.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Stack too deep\u003C\u002Fstrong> — Yul ограничен глубиной стека в 16 элементов для DUP\u002FSWAP.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Нет returndata\u003C\u002Fstrong> по умолчанию — нужно вручную вызывать \u003Ccode>return(offset, size)\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"\">Заключение\u003C\u002Fh2>\n\u003Cp>Yul — это мост между высокоуровневым Solidity и низкоуровневым байткодом EVM. Он предоставляет контроль над каждым аспектом выполнения — памятью, хранилищем, потоком управления — при этом сохраняя читаемый синтаксис. Освоение Yul — ключевой навык для любого серьёзного разработчика смарт-контрактов.\u003C\u002Fp>\n\u003Cp>В следующей статье мы углубимся в управление памятью в Yul: mstore, mload, свободный указатель и паттерны эффективной аллокации.\u003C\u002Fp>\n","ru","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:23.412187Z","Полное руководство по Yul: синтаксис, встроенные функции, управление потоком и практические примеры газоэффективного кода.","Yul ассемблер Solidity",null,"index, follow",[21,26,30,34],{"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-000000000014","Solidity","solidity",{"id":35,"name":36,"slug":37,"created_at":25},"c0000000-0000-0000-0000-000000000018","Yul","yul","Блокчейн",[40,46,52],{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":38,"published_at":45},"de000000-0000-0000-0000-000000000013","Уровень интероперабельности Ethereum: как 55+ L2 становятся одной сетью","uroven-interoperabelnosti-ethereum-kak-55-l2-stanovyatsya-odnoj-setyu","У Ethereum 55+ роллапов Layer 2, фрагментирующих ликвидность и пользовательский опыт. Уровень интероперабельности Ethereum — объединяющий кросс-роллап-мессаджинг, общие секвенсоры и based-роллапы — призван объединить их в единую компонуемую сеть.","2026-03-28T10:44:36.068675Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":38,"published_at":51},"de000000-0000-0000-0000-000000000012","ZK-доказательства за пределами роллапов: верифицируемый AI-инференс на Ethereum","zk-dokazatelstva-za-predelami-rollapov-verificiruemyj-ai-inferens-ethereum","Доказательства с нулевым разглашением — это уже не только инструмент масштабирования. В 2026 году zkML обеспечивает верифицируемый AI-инференс в блокчейне, ZK-копроцессоры переносят тяжёлые вычисления оффчейн с ончейн-верификацией, а новые системы доказательств SP1 и Jolt делают это практичным.","2026-03-28T10:44:36.026310Z",{"id":53,"title":54,"slug":55,"excerpt":56,"locale":12,"category_name":38,"published_at":57},"dd000000-0000-0000-0000-000000000013","EIP-7702 на практике: создание потоков смарт-аккаунтов после Pectra","eip-7702-na-praktike-sozdanie-potokov-smart-akkauntov-posle-pectra","EIP-7702 позволяет любому EOA Ethereum временно действовать как смарт-контракт в рамках одной транзакции. Вот как реализовать пакетные транзакции, спонсирование газа и социальное восстановление с помощью нового примитива абстракции аккаунтов.","2026-03-28T10:44:35.357227Z",{"id":13,"name":59,"slug":60,"bio":61,"photo_url":18,"linkedin":18,"role":62,"created_at":63,"updated_at":63},"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"]