[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-8-token-swap-yul-murni":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},"d2000000-0000-0000-0000-000000000108","a0000000-0000-0000-0000-000000000022","Deep EVM #8: Membangun Token Swap di Yul Murni","deep-evm-8-token-swap-yul-murni","Implementasi token swap lengkap dalam Yul murni: interaksi dengan Uniswap V2, encoding calldata manual, penanganan return value, dan perbandingan gas dengan Solidity.","## Mengapa Token Swap di Yul?\n\nToken swap adalah operasi paling umum di DeFi — dan salah satu yang paling sensitif terhadap gas. Bot MEV, aggregator DEX, dan protokol DeFi semuanya melakukan ribuan swap per hari. Setiap gas yang dihemat per swap bertambah menjadi keuntungan yang signifikan.\n\nDalam artikel ini, kita membangun token swap lengkap di Yul murni yang berinteraksi dengan Uniswap V2 pair — tanpa Solidity interface, tanpa SafeERC20, murni opcode.\n\n## Arsitektur Uniswap V2 Swap\n\nUniswap V2 swap melibatkan beberapa langkah:\n\n1. **Transfer token input** ke pair contract\n2. **Panggil pair.swap()** — mengirim token output ke penerima\n3. **Pair memverifikasi** invariant K (x * y = k)\n\n```\n\u002F\u002F Urutan panggilan:\ntoken.transfer(pair, amountIn)\npair.swap(amount0Out, amount1Out, to, data)\n```\n\n## Langkah 1: Transfer ERC20 di Yul\n\nUntuk memanggil `transfer(address,uint256)` pada kontrak ERC20:\n\n```solidity\nassembly {\n    \u002F\u002F Encode calldata\n    let ptr := mload(0x40)\n    \n    \u002F\u002F Function selector: transfer(address,uint256)\n    \u002F\u002F keccak256(\"transfer(address,uint256)\") = 0xa9059cbb...\n    mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n    mstore(add(ptr, 0x04), recipient)  \u002F\u002F address to\n    mstore(add(ptr, 0x24), amount)     \u002F\u002F uint256 amount\n    \n    \u002F\u002F Call\n    let success := call(\n        gas(),      \u002F\u002F forward semua gas\n        token,      \u002F\u002F alamat kontrak ERC20\n        0,          \u002F\u002F tanpa ETH\n        ptr,        \u002F\u002F input offset\n        0x44,       \u002F\u002F input size (4 + 32 + 32 = 68 byte)\n        0x00,       \u002F\u002F output offset\n        0x20        \u002F\u002F output size (32 byte untuk bool)\n    )\n    \n    \u002F\u002F Verifikasi sukses\n    \u002F\u002F Beberapa token tidak mengembalikan bool (USDT!)\n    let returnOk := or(\n        and(success, or(\n            iszero(returndatasize()),           \u002F\u002F Tidak ada return data (USDT)\n            and(gt(returndatasize(), 31), eq(mload(0x00), 1)) \u002F\u002F true\n        )),\n        0  \u002F\u002F fallback: gagal\n    )\n    \n    if iszero(returnOk) {\n        revert(0, 0)\n    }\n}\n```\n\n### Menangani Token Non-Standard\n\nBeberapa token ERC20 tidak mengikuti standar:\n- **USDT** — Tidak mengembalikan bool pada transfer\n- **BNB** — Mengembalikan lebih dari 32 byte\n- **Token deflasi** — Membakar persentase pada transfer\n\nKode di atas menangani kasus USDT dengan memeriksa `iszero(returndatasize())`.\n\n## Langkah 2: Panggil Uniswap V2 Pair.swap()\n\n```solidity\nassembly {\n    let ptr := mload(0x40)\n    \n    \u002F\u002F swap(uint256,uint256,address,bytes)\n    \u002F\u002F selector: 0x022c0d9f\n    mstore(ptr, 0x022c0d9f00000000000000000000000000000000000000000000000000000000)\n    mstore(add(ptr, 0x04), amount0Out)  \u002F\u002F uint256\n    mstore(add(ptr, 0x24), amount1Out)  \u002F\u002F uint256\n    mstore(add(ptr, 0x44), to)          \u002F\u002F address\n    mstore(add(ptr, 0x64), 0x80)        \u002F\u002F offset ke bytes data\n    mstore(add(ptr, 0x84), 0)           \u002F\u002F bytes length = 0\n    \n    let success := call(\n        gas(),\n        pair,\n        0,\n        ptr,\n        0xa4,       \u002F\u002F 4 + 32*4 + 32 = 164 byte\n        0x00,\n        0x00        \u002F\u002F Tidak mengharapkan return data\n    )\n    \n    if iszero(success) {\n        \u002F\u002F Bubble up revert reason\n        returndatacopy(0, 0, returndatasize())\n        revert(0, returndatasize())\n    }\n}\n```\n\n## Menghitung Amount Out\n\nFormula Uniswap V2:\n```\namountOut = (amountIn * 997 * reserveOut) \u002F (reserveIn * 1000 + amountIn * 997)\n```\n\nDi Yul:\n```solidity\nassembly {\n    function getAmountOut(amountIn, reserveIn, reserveOut) -> amountOut {\n        let amountInWithFee := mul(amountIn, 997)\n        let numerator := mul(amountInWithFee, reserveOut)\n        let denominator := add(mul(reserveIn, 1000), amountInWithFee)\n        amountOut := div(numerator, denominator)\n    }\n}\n```\n\nPerhatian: untuk jumlah besar, `mul(amountIn, 997)` dan operasi selanjutnya bisa overflow uint256. Dalam praktik, Anda perlu menggunakan aritmatika mulmod atau membagi komputasi.\n\n## Mendapatkan Reserves\n\nPanggil `getReserves()` pada pair contract:\n\n```solidity\nassembly {\n    let ptr := mload(0x40)\n    \n    \u002F\u002F getReserves() selector: 0x0902f1ac\n    mstore(ptr, 0x0902f1ac00000000000000000000000000000000000000000000000000000000)\n    \n    let success := staticcall(\n        gas(),\n        pair,\n        ptr,\n        0x04,       \u002F\u002F Hanya selector, tanpa parameter\n        ptr,        \u002F\u002F Tulis output di tempat yang sama\n        0x60        \u002F\u002F 3 * 32 byte (reserve0, reserve1, blockTimestampLast)\n    )\n    \n    if iszero(success) { revert(0, 0) }\n    \n    let reserve0 := mload(ptr)\n    let reserve1 := mload(add(ptr, 0x20))\n    \u002F\u002F blockTimestampLast di add(ptr, 0x40) — biasanya tidak diperlukan\n}\n```\n\n## Swap Lengkap: Menggabungkan Semuanya\n\n```solidity\nfunction swapExactTokensForTokens(\n    address tokenIn,\n    address tokenOut,\n    address pair,\n    uint256 amountIn,\n    uint256 minAmountOut,\n    address recipient\n) external {\n    assembly {\n        \u002F\u002F 1. Dapatkan reserves\n        let ptr := mload(0x40)\n        mstore(ptr, 0x0902f1ac00000000000000000000000000000000000000000000000000000000)\n        pop(staticcall(gas(), pair, ptr, 0x04, ptr, 0x60))\n        \n        let reserve0 := mload(ptr)\n        let reserve1 := mload(add(ptr, 0x20))\n        \n        \u002F\u002F 2. Tentukan arah swap\n        let zeroForOne := lt(tokenIn, tokenOut)\n        let reserveIn := reserve0\n        let reserveOut := reserve1\n        if iszero(zeroForOne) {\n            reserveIn := reserve1\n            reserveOut := reserve0\n        }\n        \n        \u002F\u002F 3. Hitung amount out\n        let amountInWithFee := mul(amountIn, 997)\n        let num := mul(amountInWithFee, reserveOut)\n        let den := add(mul(reserveIn, 1000), amountInWithFee)\n        let amountOut := div(num, den)\n        \n        \u002F\u002F 4. Slippage check\n        if lt(amountOut, minAmountOut) { revert(0, 0) }\n        \n        \u002F\u002F 5. Transfer token ke pair\n        mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n        mstore(add(ptr, 0x04), pair)\n        mstore(add(ptr, 0x24), amountIn)\n        pop(call(gas(), tokenIn, 0, ptr, 0x44, 0x00, 0x20))\n        \n        \u002F\u002F 6. Execute swap\n        mstore(ptr, 0x022c0d9f00000000000000000000000000000000000000000000000000000000)\n        switch zeroForOne\n        case 1 {\n            mstore(add(ptr, 0x04), 0)\n            mstore(add(ptr, 0x24), amountOut)\n        }\n        default {\n            mstore(add(ptr, 0x04), amountOut)\n            mstore(add(ptr, 0x24), 0)\n        }\n        mstore(add(ptr, 0x44), recipient)\n        mstore(add(ptr, 0x64), 0x80)\n        mstore(add(ptr, 0x84), 0)\n        \n        if iszero(call(gas(), pair, 0, ptr, 0xa4, 0, 0)) {\n            returndatacopy(0, 0, returndatasize())\n            revert(0, returndatasize())\n        }\n    }\n}\n```\n\n## Perbandingan Gas\n\n| Implementasi | Gas (swap) | Overhead |\n|-------------|-----------|----------|\n| Uniswap V2 Router (Solidity) | ~105.000 | Baseline |\n| Custom Solidity (tanpa router) | ~85.000 | -19% |\n| Yul murni (di atas) | ~72.000 | -31% |\n| Huff (artikel berikutnya) | ~65.000 | -38% |\n\nPenghematan 31% datang dari: tanpa pemeriksaan overflow, tanpa SafeERC20 wrapper, encoding calldata manual, dan tanpa penanganan error verbose.\n\n## Risiko dan Pertimbangan\n\n1. **Tidak ada pemeriksaan overflow** — Pastikan input sudah divalidasi\n2. **Tidak ada revert message** — Lebih sulit di-debug\n3. **Token non-standard** — Perlu penanganan khusus per token\n4. **Auditability** — Kode Yul jauh lebih sulit di-audit\n\n## Kesimpulan\n\nMembangun token swap di Yul murni mendemonstrasikan kekuatan kontrol tingkat rendah atas EVM. Anda menghemat ~31% gas dibanding implementasi Solidity dengan router, tetapi dengan biaya readability dan maintainability. Untuk bot MEV dan kontrak frekuensi tinggi, trade-off ini layak dilakukan. Dalam artikel berikutnya, kita akan mendorong lebih jauh lagi dengan Huff — menulis swap di assembly murni.","\u003Ch2 id=\"mengapa-token-swap-di-yul\">Mengapa Token Swap di Yul?\u003C\u002Fh2>\n\u003Cp>Token swap adalah operasi paling umum di DeFi — dan salah satu yang paling sensitif terhadap gas. Bot MEV, aggregator DEX, dan protokol DeFi semuanya melakukan ribuan swap per hari. Setiap gas yang dihemat per swap bertambah menjadi keuntungan yang signifikan.\u003C\u002Fp>\n\u003Cp>Dalam artikel ini, kita membangun token swap lengkap di Yul murni yang berinteraksi dengan Uniswap V2 pair — tanpa Solidity interface, tanpa SafeERC20, murni opcode.\u003C\u002Fp>\n\u003Ch2 id=\"arsitektur-uniswap-v2-swap\">Arsitektur Uniswap V2 Swap\u003C\u002Fh2>\n\u003Cp>Uniswap V2 swap melibatkan beberapa langkah:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Transfer token input\u003C\u002Fstrong> ke pair contract\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Panggil pair.swap()\u003C\u002Fstrong> — mengirim token output ke penerima\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Pair memverifikasi\u003C\u002Fstrong> invariant K (x * y = k)\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cpre>\u003Ccode>\u002F\u002F Urutan panggilan:\ntoken.transfer(pair, amountIn)\npair.swap(amount0Out, amount1Out, to, data)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"langkah-1-transfer-erc20-di-yul\">Langkah 1: Transfer ERC20 di Yul\u003C\u002Fh2>\n\u003Cp>Untuk memanggil \u003Ccode>transfer(address,uint256)\u003C\u002Fcode> pada kontrak ERC20:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">assembly {\n    \u002F\u002F Encode calldata\n    let ptr := mload(0x40)\n    \n    \u002F\u002F Function selector: transfer(address,uint256)\n    \u002F\u002F keccak256(\"transfer(address,uint256)\") = 0xa9059cbb...\n    mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n    mstore(add(ptr, 0x04), recipient)  \u002F\u002F address to\n    mstore(add(ptr, 0x24), amount)     \u002F\u002F uint256 amount\n    \n    \u002F\u002F Call\n    let success := call(\n        gas(),      \u002F\u002F forward semua gas\n        token,      \u002F\u002F alamat kontrak ERC20\n        0,          \u002F\u002F tanpa ETH\n        ptr,        \u002F\u002F input offset\n        0x44,       \u002F\u002F input size (4 + 32 + 32 = 68 byte)\n        0x00,       \u002F\u002F output offset\n        0x20        \u002F\u002F output size (32 byte untuk bool)\n    )\n    \n    \u002F\u002F Verifikasi sukses\n    \u002F\u002F Beberapa token tidak mengembalikan bool (USDT!)\n    let returnOk := or(\n        and(success, or(\n            iszero(returndatasize()),           \u002F\u002F Tidak ada return data (USDT)\n            and(gt(returndatasize(), 31), eq(mload(0x00), 1)) \u002F\u002F true\n        )),\n        0  \u002F\u002F fallback: gagal\n    )\n    \n    if iszero(returnOk) {\n        revert(0, 0)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Menangani Token Non-Standard\u003C\u002Fh3>\n\u003Cp>Beberapa token ERC20 tidak mengikuti standar:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>USDT\u003C\u002Fstrong> — Tidak mengembalikan bool pada transfer\u003C\u002Fli>\n\u003Cli>\u003Cstrong>BNB\u003C\u002Fstrong> — Mengembalikan lebih dari 32 byte\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Token deflasi\u003C\u002Fstrong> — Membakar persentase pada transfer\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Kode di atas menangani kasus USDT dengan memeriksa \u003Ccode>iszero(returndatasize())\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"langkah-2-panggil-uniswap-v2-pair-swap\">Langkah 2: Panggil Uniswap V2 Pair.swap()\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-solidity\">assembly {\n    let ptr := mload(0x40)\n    \n    \u002F\u002F swap(uint256,uint256,address,bytes)\n    \u002F\u002F selector: 0x022c0d9f\n    mstore(ptr, 0x022c0d9f00000000000000000000000000000000000000000000000000000000)\n    mstore(add(ptr, 0x04), amount0Out)  \u002F\u002F uint256\n    mstore(add(ptr, 0x24), amount1Out)  \u002F\u002F uint256\n    mstore(add(ptr, 0x44), to)          \u002F\u002F address\n    mstore(add(ptr, 0x64), 0x80)        \u002F\u002F offset ke bytes data\n    mstore(add(ptr, 0x84), 0)           \u002F\u002F bytes length = 0\n    \n    let success := call(\n        gas(),\n        pair,\n        0,\n        ptr,\n        0xa4,       \u002F\u002F 4 + 32*4 + 32 = 164 byte\n        0x00,\n        0x00        \u002F\u002F Tidak mengharapkan return data\n    )\n    \n    if iszero(success) {\n        \u002F\u002F Bubble up revert reason\n        returndatacopy(0, 0, returndatasize())\n        revert(0, returndatasize())\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"menghitung-amount-out\">Menghitung Amount Out\u003C\u002Fh2>\n\u003Cp>Formula Uniswap V2:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>amountOut = (amountIn * 997 * reserveOut) \u002F (reserveIn * 1000 + amountIn * 997)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Di Yul:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">assembly {\n    function getAmountOut(amountIn, reserveIn, reserveOut) -&gt; amountOut {\n        let amountInWithFee := mul(amountIn, 997)\n        let numerator := mul(amountInWithFee, reserveOut)\n        let denominator := add(mul(reserveIn, 1000), amountInWithFee)\n        amountOut := div(numerator, denominator)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Perhatian: untuk jumlah besar, \u003Ccode>mul(amountIn, 997)\u003C\u002Fcode> dan operasi selanjutnya bisa overflow uint256. Dalam praktik, Anda perlu menggunakan aritmatika mulmod atau membagi komputasi.\u003C\u002Fp>\n\u003Ch2 id=\"mendapatkan-reserves\">Mendapatkan Reserves\u003C\u002Fh2>\n\u003Cp>Panggil \u003Ccode>getReserves()\u003C\u002Fcode> pada pair contract:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">assembly {\n    let ptr := mload(0x40)\n    \n    \u002F\u002F getReserves() selector: 0x0902f1ac\n    mstore(ptr, 0x0902f1ac00000000000000000000000000000000000000000000000000000000)\n    \n    let success := staticcall(\n        gas(),\n        pair,\n        ptr,\n        0x04,       \u002F\u002F Hanya selector, tanpa parameter\n        ptr,        \u002F\u002F Tulis output di tempat yang sama\n        0x60        \u002F\u002F 3 * 32 byte (reserve0, reserve1, blockTimestampLast)\n    )\n    \n    if iszero(success) { revert(0, 0) }\n    \n    let reserve0 := mload(ptr)\n    let reserve1 := mload(add(ptr, 0x20))\n    \u002F\u002F blockTimestampLast di add(ptr, 0x40) — biasanya tidak diperlukan\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"swap-lengkap-menggabungkan-semuanya\">Swap Lengkap: Menggabungkan Semuanya\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-solidity\">function swapExactTokensForTokens(\n    address tokenIn,\n    address tokenOut,\n    address pair,\n    uint256 amountIn,\n    uint256 minAmountOut,\n    address recipient\n) external {\n    assembly {\n        \u002F\u002F 1. Dapatkan reserves\n        let ptr := mload(0x40)\n        mstore(ptr, 0x0902f1ac00000000000000000000000000000000000000000000000000000000)\n        pop(staticcall(gas(), pair, ptr, 0x04, ptr, 0x60))\n        \n        let reserve0 := mload(ptr)\n        let reserve1 := mload(add(ptr, 0x20))\n        \n        \u002F\u002F 2. Tentukan arah swap\n        let zeroForOne := lt(tokenIn, tokenOut)\n        let reserveIn := reserve0\n        let reserveOut := reserve1\n        if iszero(zeroForOne) {\n            reserveIn := reserve1\n            reserveOut := reserve0\n        }\n        \n        \u002F\u002F 3. Hitung amount out\n        let amountInWithFee := mul(amountIn, 997)\n        let num := mul(amountInWithFee, reserveOut)\n        let den := add(mul(reserveIn, 1000), amountInWithFee)\n        let amountOut := div(num, den)\n        \n        \u002F\u002F 4. Slippage check\n        if lt(amountOut, minAmountOut) { revert(0, 0) }\n        \n        \u002F\u002F 5. Transfer token ke pair\n        mstore(ptr, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n        mstore(add(ptr, 0x04), pair)\n        mstore(add(ptr, 0x24), amountIn)\n        pop(call(gas(), tokenIn, 0, ptr, 0x44, 0x00, 0x20))\n        \n        \u002F\u002F 6. Execute swap\n        mstore(ptr, 0x022c0d9f00000000000000000000000000000000000000000000000000000000)\n        switch zeroForOne\n        case 1 {\n            mstore(add(ptr, 0x04), 0)\n            mstore(add(ptr, 0x24), amountOut)\n        }\n        default {\n            mstore(add(ptr, 0x04), amountOut)\n            mstore(add(ptr, 0x24), 0)\n        }\n        mstore(add(ptr, 0x44), recipient)\n        mstore(add(ptr, 0x64), 0x80)\n        mstore(add(ptr, 0x84), 0)\n        \n        if iszero(call(gas(), pair, 0, ptr, 0xa4, 0, 0)) {\n            returndatacopy(0, 0, returndatasize())\n            revert(0, returndatasize())\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"perbandingan-gas\">Perbandingan Gas\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>Implementasi\u003C\u002Fth>\u003Cth>Gas (swap)\u003C\u002Fth>\u003Cth>Overhead\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Uniswap V2 Router (Solidity)\u003C\u002Ftd>\u003Ctd>~105.000\u003C\u002Ftd>\u003Ctd>Baseline\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Custom Solidity (tanpa router)\u003C\u002Ftd>\u003Ctd>~85.000\u003C\u002Ftd>\u003Ctd>-19%\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Yul murni (di atas)\u003C\u002Ftd>\u003Ctd>~72.000\u003C\u002Ftd>\u003Ctd>-31%\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Huff (artikel berikutnya)\u003C\u002Ftd>\u003Ctd>~65.000\u003C\u002Ftd>\u003Ctd>-38%\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>Penghematan 31% datang dari: tanpa pemeriksaan overflow, tanpa SafeERC20 wrapper, encoding calldata manual, dan tanpa penanganan error verbose.\u003C\u002Fp>\n\u003Ch2 id=\"risiko-dan-pertimbangan\">Risiko dan Pertimbangan\u003C\u002Fh2>\n\u003Col>\n\u003Cli>\u003Cstrong>Tidak ada pemeriksaan overflow\u003C\u002Fstrong> — Pastikan input sudah divalidasi\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Tidak ada revert message\u003C\u002Fstrong> — Lebih sulit di-debug\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Token non-standard\u003C\u002Fstrong> — Perlu penanganan khusus per token\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Auditability\u003C\u002Fstrong> — Kode Yul jauh lebih sulit di-audit\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"kesimpulan\">Kesimpulan\u003C\u002Fh2>\n\u003Cp>Membangun token swap di Yul murni mendemonstrasikan kekuatan kontrol tingkat rendah atas EVM. Anda menghemat ~31% gas dibanding implementasi Solidity dengan router, tetapi dengan biaya readability dan maintainability. Untuk bot MEV dan kontrak frekuensi tinggi, trade-off ini layak dilakukan. Dalam artikel berikutnya, kita akan mendorong lebih jauh lagi dengan Huff — menulis swap di assembly murni.\u003C\u002Fp>\n","id","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:24.652891Z","Implementasi token swap di Yul murni: interaksi Uniswap V2, encoding calldata, penanganan return value, dan perbandingan gas.","token swap Yul EVM",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-000000000017","Huff","huff",{"id":35,"name":36,"slug":37,"created_at":25},"c0000000-0000-0000-0000-000000000018","Yul","yul","Blockchain",[40,46,52],{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":38,"published_at":45},"d0000000-0000-0000-0000-000000000596","Lapisan Interoperabilitas Ethereum: Bagaimana 55+ L2 Menjadi Satu Chain","lapisan-interoperabilitas-ethereum-bagaimana-55-l2-menjadi-satu-chain","Ethereum memiliki 55+ rollup Layer 2, memecah likuiditas dan pengalaman pengguna. Lapisan Interoperabilitas Ethereum — menggabungkan pesan lintas-rollup, shared sequencer, dan based rollup — bertujuan menyatukan mereka menjadi satu jaringan yang dapat dikomposisi.","2026-03-28T10:44:44.364342Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":38,"published_at":51},"d0000000-0000-0000-0000-000000000595","ZK Proofs Melampaui Rollups: Inferensi AI Terverifikasi di Ethereum","zk-proofs-melampaui-rollups-inferensi-ai-terverifikasi-ethereum","Zero-knowledge proofs bukan lagi sekadar alat penskalaan. Pada 2026, zkML memungkinkan inferensi AI terverifikasi on-chain, ZK coprocessor memindahkan komputasi berat off-chain dengan verifikasi on-chain, dan sistem pembuktian baru seperti SP1 dan Jolt menjadikannya praktis.","2026-03-28T10:44:44.358370Z",{"id":53,"title":54,"slug":55,"excerpt":56,"locale":12,"category_name":38,"published_at":57},"d0000000-0000-0000-0000-000000000572","EIP-7702 dalam Praktik: Membangun Alur Akun Pintar Setelah Pectra","eip-7702-dalam-praktik-membangun-alur-akun-pintar-setelah-pectra","EIP-7702 memungkinkan EOA Ethereum mana pun untuk sementara bertindak sebagai kontrak pintar dalam satu transaksi. Berikut cara mengimplementasikan transaksi batch, sponsorship gas, dan social recovery menggunakan primitif account abstraction baru.","2026-03-28T10:44:42.816894Z",{"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"]