بلوكتشينMar 28, 2026
Deep EVM #5: مقدمة في Yul — لغة التجميع السرية لـ Solidity
OS
Open Soft Team
Engineering Team
ما هي Yul؟
Yul هي لغة وسيطة يمكن تجميعها إلى بايتكود لعدة خلفيات مختلفة، بما في ذلك EVM. يمكنك استخدامها مباشرة داخل Solidity عبر كتل assembly { } أو كلغة مستقلة.
لماذا Yul وليس Solidity العادية؟
- تحسين الغاز — Yul يمنحك تحكماً دقيقاً في الكود المُولد
- عمليات منخفضة المستوى — الوصول المباشر للذاكرة والتخزين وcalldata
- أنماط مستحيلة في Solidity — مثل returndatasize كبديل رخيص لـ push 0
البنية الأساسية
Yul تبدو مثل Solidity مبسطة بدون أنواع (كل شيء uint256):
assembly {
// المتغيرات
let x := 42
let y := add(x, 1) // y = 43
// الشروط
if gt(x, 0) {
y := mul(x, 2)
}
// الحلقات
for { let i := 0 } lt(i, 10) { i := add(i, 1) } {
// جسم الحلقة
}
// الدوال
function double(val) -> result {
result := mul(val, 2)
}
}
الوصول إلى الذاكرة
في Yul، تتعامل مع الذاكرة مباشرة باستخدام mload وmstore:
assembly {
// كتابة 32 بايت في الذاكرة عند الإزاحة 0x00
mstore(0x00, 0x1234)
// قراءة 32 بايت من الذاكرة عند الإزاحة 0x00
let val := mload(0x00)
// مؤشر الذاكرة الحرة
let ptr := mload(0x40)
mstore(ptr, someValue)
mstore(0x40, add(ptr, 0x20)) // تقديم المؤشر
}
الوصول إلى التخزين
assembly {
// قراءة من فتحة التخزين 0
let val := sload(0)
// كتابة إلى فتحة التخزين 0
sstore(0, 42)
// حساب فتحة التعيين
mstore(0x00, key)
mstore(0x20, mappingSlot)
let slot := keccak256(0x00, 0x40)
let mappedValue := sload(slot)
}
التعامل مع Calldata
assembly {
// تحميل أول 4 بايت (محدد الدالة)
let selector := shr(224, calldataload(0))
// تحميل المعامل الأول (بعد المحدد)
let arg1 := calldataload(4)
// حجم calldata
let size := calldatasize()
}
أنماط تحسين الغاز في Yul
بديل PUSH0
assembly {
// بدلاً من PUSH1 0x00 (3 غاز + 1 بايت)
// استخدم returndatasize() قبل أي استدعاء خارجي
let zero := returndatasize() // 2 غاز
}
ترميز ABI يدوي
assembly {
// بدلاً من abi.encode(a, b)
mstore(0x00, a)
mstore(0x20, b)
// البيانات المرمزة الآن في الذاكرة [0x00..0x40]
}
إرجاع مخصص
assembly {
mstore(0x00, value)
return(0x00, 0x20) // إرجاع 32 بايت من الذاكرة
}
Yul كلغة مستقلة
يمكنك كتابة عقود كاملة في Yul:
object "SimpleStore" {
code {
// كود المُنشئ: نسخ كود التشغيل وإعادته
datacopy(0, dataoffset("runtime"), datasize("runtime"))
return(0, datasize("runtime"))
}
object "runtime" {
code {
// محدد الدالة
switch shr(224, calldataload(0))
case 0x6d4ce63c /* get() */ {
mstore(0, sload(0))
return(0, 32)
}
case 0x60fe47b1 /* set(uint256) */ {
sstore(0, calldataload(4))
}
default {
revert(0, 0)
}
}
}
}
متى تستخدم Yul
استخدم Yul عندما:
- تحسين الغاز ضروري — المسارات الساخنة في عقود DeFi
- عمليات منخفضة المستوى مطلوبة — التعامل مع returndata، إنشاء عقود عبر CREATE2
- Solidity لا تستطيع التعبير عما تريد — أنماط ذاكرة مخصصة
لا تستخدم Yul عندما:
- Solidity العادية تكفي — قابلية القراءة أهم
- الفريق لا يعرف EVM جيداً — Yul أسهل لكتابة الأخطاء
- التدقيق مطلوب — كود Yul أصعب في التدقيق
الخلاصة
Yul هي جسر بين Solidity عالية المستوى والبايتكود الخام. تمنحك تحكماً دقيقاً في الكود المُولد مع الحفاظ على قابلية القراءة أفضل من البايتكود المباشر. إتقان Yul هو خطوة أساسية نحو فهم EVM بعمق وكتابة عقود محسنة للغاز.