[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-8-bina-mubadil-rumuz-yul-khalis":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},"d9000000-0000-0000-0000-000000000108","a0000000-0000-0000-0000-000000000092","Deep EVM #8: بناء مبادل رموز في Yul خالص","deep-evm-8-bina-mubadil-rumuz-yul-khalis","بناء عقد مبادل رموز ERC-20 كامل في Yul خالص: التحقق من المعاملات، فك ترميز ABI يدوي، إدارة التخزين، وتحسين كل كود تشغيل.","## لماذا مبادل رموز في Yul؟\n\nبناء مبادل رموز (Token Swap) في Yul خالص هو التمرين الأمثل لإتقان EVM. يتطلب كل مهارة تعلمناها: إدارة الذاكرة، الوصول إلى التخزين، فك ترميز calldata، وترميز ABI يدوي.\n\nعقدنا سيقبل رمز A من المستخدم ويعيد رمز B بناءً على سعر صرف محدد.\n\n## بنية العقد\n\n```yul\nobject \"TokenSwap\" {\n    code {\n        \u002F\u002F كود المُنشئ\n        sstore(0, caller())  \u002F\u002F تخزين المالك\n        datacopy(0, dataoffset(\"runtime\"), datasize(\"runtime\"))\n        return(0, datasize(\"runtime\"))\n    }\n    object \"runtime\" {\n        code {\n            \u002F\u002F منع إرسال ETH\n            if callvalue() { revert(0, 0) }\n            \n            \u002F\u002F استخراج المحدد\n            let selector := shr(224, calldataload(0))\n            \n            switch selector\n            case 0x5f575529 \u002F* swap(address,address,uint256) *\u002F {\n                _swap()\n            }\n            case 0x8da5cb5b \u002F* owner() *\u002F {\n                mstore(0, sload(0))\n                return(0, 32)\n            }\n            default {\n                revert(0, 0)\n            }\n            \n            function _swap() {\n                let tokenIn := calldataload(0x04)\n                let tokenOut := calldataload(0x24)\n                let amountIn := calldataload(0x44)\n                \n                \u002F\u002F التحقق من المبلغ\n                if iszero(amountIn) { revert(0, 0) }\n                \n                \u002F\u002F حساب المبلغ الخارج (سعر صرف ثابت 1:1 للبساطة)\n                let amountOut := amountIn\n                \n                \u002F\u002F نقل tokenIn من المستدعي إلى هذا العقد\n                _transferFrom(tokenIn, caller(), address(), amountIn)\n                \n                \u002F\u002F نقل tokenOut من هذا العقد إلى المستدعي\n                _transfer(tokenOut, caller(), amountOut)\n            }\n            \n            function _transferFrom(token, from, to, amount) {\n                \u002F\u002F ترميز transferFrom(address,address,uint256)\n                mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n                mstore(0x04, from)\n                mstore(0x24, to)\n                mstore(0x44, amount)\n                \n                let success := call(gas(), token, 0, 0, 0x64, 0, 0x20)\n                if iszero(success) { revert(0, 0) }\n                \n                \u002F\u002F التحقق من القيمة المرجعة\n                if returndatasize() {\n                    if iszero(mload(0)) { revert(0, 0) }\n                }\n            }\n            \n            function _transfer(token, to, amount) {\n                \u002F\u002F ترميز transfer(address,uint256)\n                mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n                mstore(0x04, to)\n                mstore(0x24, amount)\n                \n                let success := call(gas(), token, 0, 0, 0x44, 0, 0x20)\n                if iszero(success) { revert(0, 0) }\n                \n                if returndatasize() {\n                    if iszero(mload(0)) { revert(0, 0) }\n                }\n            }\n        }\n    }\n}\n```\n\n## فك ترميز Calldata يدوياً\n\nبدلاً من abi.decode الذي يولده Solidity، نقرأ المعاملات مباشرة:\n\n```yul\n\u002F\u002F calldata layout for swap(address,address,uint256):\n\u002F\u002F [0x00..0x04]: selector (4 بايت)\n\u002F\u002F [0x04..0x24]: tokenIn (address، محشو إلى 32 بايت)\n\u002F\u002F [0x24..0x44]: tokenOut\n\u002F\u002F [0x44..0x64]: amountIn\nlet tokenIn := calldataload(0x04)\nlet tokenOut := calldataload(0x24)\nlet amountIn := calldataload(0x44)\n```\n\nلا حاجة للتحقق من الحجم أو فك الترميز الديناميكي — المعاملات ثابتة الحجم.\n\n## التعامل مع رموز ERC-20 غير المتوافقة\n\nبعض الرموز (مثل USDT) لا تُرجع قيمة بوليانية من transfer. يجب التعامل مع هذه الحالة:\n\n```yul\nlet success := call(gas(), token, 0, ptr, 0x44, 0, 0x20)\nif iszero(success) { revert(0, 0) }\n\n\u002F\u002F التعامل مع الرموز غير المتوافقة\nswitch returndatasize()\ncase 0 {\n    \u002F\u002F لا قيمة مرجعة — نفترض النجاح (مثل USDT)\n}\ncase 32 {\n    \u002F\u002F تحقق من القيمة المرجعة\n    if iszero(mload(0)) { revert(0, 0) }\n}\ndefault {\n    \u002F\u002F حجم غير متوقع\n    revert(0, 0)\n}\n```\n\n## مقارنة حجم البايتكود\n\n| التنفيذ | حجم التشغيل | غاز النشر |\n|---------|-------------|----------|\n| Solidity + SafeERC20 | ~2,400 بايت | ~480,000 غاز |\n| Yul خالص | ~350 بايت | ~70,000 غاز |\n\nتوفير 85% في حجم البايتكود يترجم مباشرة إلى توفير 85% في تكلفة النشر.\n\n## اعتبارات الأمان\n\nحتى في Yul، يجب اتباع أفضل ممارسات الأمان:\n\n1. **التحقق من المدخلات** — تأكد من أن العناوين والمبالغ صالحة\n2. **الحماية من إعادة الدخول** — حدّث الحالة قبل الاستدعاءات الخارجية\n3. **التعامل مع الفشل** — تحقق من قيمة إرجاع call\n4. **التحكم في الوصول** — تأكد من أن الدوال الإدارية محمية\n\n## الخلاصة\n\nبناء مبادل رموز في Yul خالص يوضح القوة والمسؤولية التي تأتي مع البرمجة منخفضة المستوى لـ EVM. حصلنا على عقد أصغر بـ 7 مرات وأرخص بـ 7 مرات في النشر، لكن على حساب قابلية القراءة وسهولة التدقيق. في المقالة التالية ننتقل إلى Huff — لغة أقل تجريداً حتى تسمح بالتحكم في كل بايت من البايتكود.","\u003Ch2 id=\"yul\">لماذا مبادل رموز في Yul؟\u003C\u002Fh2>\n\u003Cp>بناء مبادل رموز (Token Swap) في Yul خالص هو التمرين الأمثل لإتقان EVM. يتطلب كل مهارة تعلمناها: إدارة الذاكرة، الوصول إلى التخزين، فك ترميز calldata، وترميز ABI يدوي.\u003C\u002Fp>\n\u003Cp>عقدنا سيقبل رمز A من المستخدم ويعيد رمز B بناءً على سعر صرف محدد.\u003C\u002Fp>\n\u003Ch2 id=\"\">بنية العقد\u003C\u002Fh2>\n\u003Cpre>\u003Ccode class=\"language-yul\">object \"TokenSwap\" {\n    code {\n        \u002F\u002F كود المُنشئ\n        sstore(0, caller())  \u002F\u002F تخزين المالك\n        datacopy(0, dataoffset(\"runtime\"), datasize(\"runtime\"))\n        return(0, datasize(\"runtime\"))\n    }\n    object \"runtime\" {\n        code {\n            \u002F\u002F منع إرسال ETH\n            if callvalue() { revert(0, 0) }\n            \n            \u002F\u002F استخراج المحدد\n            let selector := shr(224, calldataload(0))\n            \n            switch selector\n            case 0x5f575529 \u002F* swap(address,address,uint256) *\u002F {\n                _swap()\n            }\n            case 0x8da5cb5b \u002F* owner() *\u002F {\n                mstore(0, sload(0))\n                return(0, 32)\n            }\n            default {\n                revert(0, 0)\n            }\n            \n            function _swap() {\n                let tokenIn := calldataload(0x04)\n                let tokenOut := calldataload(0x24)\n                let amountIn := calldataload(0x44)\n                \n                \u002F\u002F التحقق من المبلغ\n                if iszero(amountIn) { revert(0, 0) }\n                \n                \u002F\u002F حساب المبلغ الخارج (سعر صرف ثابت 1:1 للبساطة)\n                let amountOut := amountIn\n                \n                \u002F\u002F نقل tokenIn من المستدعي إلى هذا العقد\n                _transferFrom(tokenIn, caller(), address(), amountIn)\n                \n                \u002F\u002F نقل tokenOut من هذا العقد إلى المستدعي\n                _transfer(tokenOut, caller(), amountOut)\n            }\n            \n            function _transferFrom(token, from, to, amount) {\n                \u002F\u002F ترميز transferFrom(address,address,uint256)\n                mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n                mstore(0x04, from)\n                mstore(0x24, to)\n                mstore(0x44, amount)\n                \n                let success := call(gas(), token, 0, 0, 0x64, 0, 0x20)\n                if iszero(success) { revert(0, 0) }\n                \n                \u002F\u002F التحقق من القيمة المرجعة\n                if returndatasize() {\n                    if iszero(mload(0)) { revert(0, 0) }\n                }\n            }\n            \n            function _transfer(token, to, amount) {\n                \u002F\u002F ترميز transfer(address,uint256)\n                mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n                mstore(0x04, to)\n                mstore(0x24, amount)\n                \n                let success := call(gas(), token, 0, 0, 0x44, 0, 0x20)\n                if iszero(success) { revert(0, 0) }\n                \n                if returndatasize() {\n                    if iszero(mload(0)) { revert(0, 0) }\n                }\n            }\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"calldata\">فك ترميز Calldata يدوياً\u003C\u002Fh2>\n\u003Cp>بدلاً من abi.decode الذي يولده Solidity، نقرأ المعاملات مباشرة:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">\u002F\u002F calldata layout for swap(address,address,uint256):\n\u002F\u002F [0x00..0x04]: selector (4 بايت)\n\u002F\u002F [0x04..0x24]: tokenIn (address، محشو إلى 32 بايت)\n\u002F\u002F [0x24..0x44]: tokenOut\n\u002F\u002F [0x44..0x64]: amountIn\nlet tokenIn := calldataload(0x04)\nlet tokenOut := calldataload(0x24)\nlet amountIn := calldataload(0x44)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>لا حاجة للتحقق من الحجم أو فك الترميز الديناميكي — المعاملات ثابتة الحجم.\u003C\u002Fp>\n\u003Ch2 id=\"erc-20\">التعامل مع رموز ERC-20 غير المتوافقة\u003C\u002Fh2>\n\u003Cp>بعض الرموز (مثل USDT) لا تُرجع قيمة بوليانية من transfer. يجب التعامل مع هذه الحالة:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-yul\">let success := call(gas(), token, 0, ptr, 0x44, 0, 0x20)\nif iszero(success) { revert(0, 0) }\n\n\u002F\u002F التعامل مع الرموز غير المتوافقة\nswitch returndatasize()\ncase 0 {\n    \u002F\u002F لا قيمة مرجعة — نفترض النجاح (مثل USDT)\n}\ncase 32 {\n    \u002F\u002F تحقق من القيمة المرجعة\n    if iszero(mload(0)) { revert(0, 0) }\n}\ndefault {\n    \u002F\u002F حجم غير متوقع\n    revert(0, 0)\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"\">مقارنة حجم البايتكود\u003C\u002Fh2>\n\u003Ctable>\u003Cthead>\u003Ctr>\u003Cth>التنفيذ\u003C\u002Fth>\u003Cth>حجم التشغيل\u003C\u002Fth>\u003Cth>غاز النشر\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\n\u003Ctr>\u003Ctd>Solidity + SafeERC20\u003C\u002Ftd>\u003Ctd>~2,400 بايت\u003C\u002Ftd>\u003Ctd>~480,000 غاز\u003C\u002Ftd>\u003C\u002Ftr>\n\u003Ctr>\u003Ctd>Yul خالص\u003C\u002Ftd>\u003Ctd>~350 بايت\u003C\u002Ftd>\u003Ctd>~70,000 غاز\u003C\u002Ftd>\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp>توفير 85% في حجم البايتكود يترجم مباشرة إلى توفير 85% في تكلفة النشر.\u003C\u002Fp>\n\u003Ch2 id=\"\">اعتبارات الأمان\u003C\u002Fh2>\n\u003Cp>حتى في Yul، يجب اتباع أفضل ممارسات الأمان:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>التحقق من المدخلات\u003C\u002Fstrong> — تأكد من أن العناوين والمبالغ صالحة\u003C\u002Fli>\n\u003Cli>\u003Cstrong>الحماية من إعادة الدخول\u003C\u002Fstrong> — حدّث الحالة قبل الاستدعاءات الخارجية\u003C\u002Fli>\n\u003Cli>\u003Cstrong>التعامل مع الفشل\u003C\u002Fstrong> — تحقق من قيمة إرجاع call\u003C\u002Fli>\n\u003Cli>\u003Cstrong>التحكم في الوصول\u003C\u002Fstrong> — تأكد من أن الدوال الإدارية محمية\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"\">الخلاصة\u003C\u002Fh2>\n\u003Cp>بناء مبادل رموز في Yul خالص يوضح القوة والمسؤولية التي تأتي مع البرمجة منخفضة المستوى لـ EVM. حصلنا على عقد أصغر بـ 7 مرات وأرخص بـ 7 مرات في النشر، لكن على حساب قابلية القراءة وسهولة التدقيق. في المقالة التالية ننتقل إلى Huff — لغة أقل تجريداً حتى تسمح بالتحكم في كل بايت من البايتكود.\u003C\u002Fp>\n","ar","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:32.258689Z","بناء مبادل رموز ERC-20 كامل في Yul خالص: فك ترميز ABI يدوي، إدارة التخزين، وتحسين البايتكود.","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","بلوكتشين",[40,46,52],{"id":41,"title":42,"slug":43,"excerpt":44,"locale":12,"category_name":38,"published_at":45},"d0000000-0000-0000-0000-000000000617","طبقة التشغيل البيني لـ Ethereum: كيف تصبح 55+ سلسلة L2 سلسلة واحدة","tabaqat-altashghil-albaini-ethereum-55-l2-silsila-wahida","يملك Ethereum اكثر من 55 rollup من الطبقة الثانية، مما يجزئ السيولة وتجربة المستخدم. طبقة التشغيل البيني لـ Ethereum — الجمع بين الرسائل عبر الـ rollups والمتسلسلات المشتركة والـ based rollups — تهدف الى توحيدها في شبكة قابلة للتركيب واحدة.","2026-03-28T10:44:45.626845Z",{"id":47,"title":48,"slug":49,"excerpt":50,"locale":12,"category_name":38,"published_at":51},"d0000000-0000-0000-0000-000000000616","اثباتات ZK ما وراء الـ Rollups: استدلال الذكاء الاصطناعي القابل للتحقق على Ethereum","ithbatat-zk-ma-waraa-rollups-istidlal-dhakaa-istinaai-ethereum","اثباتات المعرفة الصفرية لم تعد مجرد اداة للتوسع. في 2026، يتيح zkML استدلال الذكاء الاصطناعي القابل للتحقق على السلسلة، وتنقل معالجات ZK المشتركة الحسابات الثقيلة خارج السلسلة مع التحقق على السلسلة، وانظمة الاثبات الجديدة مثل SP1 وJolt تجعل ذلك عمليا.","2026-03-28T10:44:45.621594Z",{"id":53,"title":54,"slug":55,"excerpt":56,"locale":12,"category_name":38,"published_at":57},"d0000000-0000-0000-0000-000000000593","EIP-7702 في الممارسة العملية: بناء تدفقات الحساب الذكي بعد Pectra","eip-7702-fi-almumaarasa-alamaliyya-binaa-tadaffuqat-alhisab-aldhaki-baad-pectra","يسمح EIP-7702 لأي EOA على Ethereum بالعمل مؤقتاً كعقد ذكي في معاملة واحدة. إليك كيفية تنفيذ المعاملات المجمّعة ورعاية الغاز والاسترداد الاجتماعي باستخدام البدائية الجديدة لتجريد الحساب.","2026-03-28T10:44:44.185251Z",{"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"]