ورقة مرجعية Solidity
بنية العقد
يبدأ كل ملف بترخيص و pragma؛ والعقد هو وحدة النشر.
| البنية | المعنى |
|---|---|
// SPDX-License-Identifier: MIT | تعليق الترخيص الذي يتوقعه المجمّع في السطر الأول |
pragma solidity ^0.8.0; | إصدار المجمّع الذي كُتب الملف له |
contract Counter { ... } | الإعلان عن عقد (حالة + دوال) |
constructor(uint start) { count = start; } | يُنفَّذ مرة واحدة عند النشر |
import "./Token.sol"; | استيراد ملف آخر |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | استيراد حزمة مكتبة |
interface IToken { function balanceOf(address a) external view returns (uint); } | الإعلان عن واجهة (بلا أجسام للدوال) |
library Math { function min(uint a, uint b) internal pure returns (uint) { ... } } | مكتبة من الدوال القابلة لإعادة الاستخدام |
أنواع القيم
الأعداد الصحيحة ذات أحجام ثابتة وبلا كسور عشرية؛ الإصدار 0.8 يُرجع (revert) عند تجاوز السعة.
| النوع | ما يحمله |
|---|---|
uint256 / uint | عدد صحيح بلا إشارة، من 0 إلى 2^256 - 1 (uint هو uint256) |
uint8, uint16, ... uint128 | أعداد صحيحة بلا إشارة أصغر، بخطوات من 8 بتات |
int256 / int | عدد صحيح بإشارة (يقبل القيم السالبة) |
bool | true أو false |
address | عنوان حساب أو عقد بطول 20 بايت |
address payable | عنوان يمكنه استلام Ether عبر transfer/send |
bytes32, bytes1... | مصفوفات بايتات ثابتة الحجم |
enum Status { Open, Closed } | مجموعة ثوابت مسماة، تُخزَّن كـ uint8 |
1 ether, 1 gwei, 1 wei | وحدات Ether: 1 ether = 10^18 wei |
1 days, 2 hours, 30 minutes | وحدات الوقت، بالثواني |
أنواع المراجع وموقع البيانات
المصفوفات والسلاسل النصية و bytes و struct و mapping تقيم في storage أو memory أو calldata.
| البنية | المعنى |
|---|---|
string memory name | سلسلة UTF-8 ديناميكية (نسخة مؤقتة) |
bytes memory data | مصفوفة بايتات ديناميكية |
uint[] public scores; | مصفوفة ديناميكية في storage |
uint[3] fixed; | مصفوفة ثابتة الحجم من 3 عناصر |
uint[] memory tmp = new uint[](5); | تخصيص مصفوفة في memory |
scores.push(42); | الإضافة إلى نهاية مصفوفة في storage |
scores.pop(); | إزالة العنصر الأخير |
scores.length | عدد العناصر |
storage | دائم، على السلسلة، مكلف في الكتابة |
memory | مؤقت، يعيش لاستدعاء واحد |
calldata | مدخلات دالة external للقراءة فقط، الأقل تكلفة |
mapping و struct
mapping جدول تجزئة بلا طول ولا تكرار؛ و struct يجمع الحقول.
| البنية | المعنى |
|---|---|
mapping(address => uint) public balances; | مخزن مفتاح-قيمة، كل مفتاح موجود (القيمة الافتراضية 0) |
balances[msg.sender] += 1; | القراءة/الكتابة بالمفتاح |
mapping(address => mapping(address => uint)) allowance; | mapping متداخل |
struct User { string name; uint age; bool active; } | تعريف struct |
User memory u = User("Ada", 36, true); | إنشاء struct في memory |
User memory u = User({name: "Ada", age: 36, active: true}); | الإنشاء بحقول مسماة |
users[msg.sender] = u; | تخزين struct في mapping |
users[msg.sender].age = 37; | تحديث حقل واحد في storage |
delete users[msg.sender]; | إعادة التعيين إلى القيم الافتراضية |
الدوال والرؤية
كل دالة تحدد من يمكنه استدعاءها وما إذا كانت تقرأ الحالة أو تكتبها.
| البنية | المعنى |
|---|---|
function add(uint a, uint b) public pure returns (uint) { return a + b; } | دالة بمعاملات وقيمة إرجاع |
public | قابلة للاستدعاء من أي مكان (من الداخل والخارج) |
external | قابلة للاستدعاء من خارج العقد فقط |
internal | هذا العقد والعقود التي ترثه |
private | هذا العقد فقط |
view | تقرأ الحالة ولا تكتبها أبدًا |
pure | لا تقرأ أي حالة على الإطلاق |
payable | يمكنها استلام Ether مع الاستدعاء |
returns (uint sum, bool ok) | قيم إرجاع متعددة مسماة |
(uint s, bool ok) = f(); | تفكيك قيم إرجاع متعددة |
uint public count; | متغير حالة public يحصل على دالة جلب تلقائية count() |
المعدِّلات والثوابت والوراثة
أعد استخدام التحققات بالمعدِّلات؛ وثبّت القيم بـ constant و immutable.
| البنية | المعنى |
|---|---|
modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } | تعريف معدِّل (_ = تنفيذ جسم الدالة) |
function withdraw() public onlyOwner { ... } | تطبيق معدِّل |
uint public constant MAX = 100; | ثابت وقت التجميع |
address public immutable owner; | يُعيَّن مرة واحدة في المُنشئ ثم يثبت |
contract Token is ERC20, Ownable { ... } | الوراثة من عقود أخرى |
function f() public virtual { ... } | السماح بالتجاوز (override) |
function f() public override { ... } | تجاوز دالة من العقد الأب |
super.f(); | استدعاء تنفيذ العقد الأب |
abstract contract Base { function f() public virtual; } | عقد بدوال غير منفَّذة |
التحكم في التدفق
عبارات عائلة C المعتادة؛ لا توجد switch، والحلقات تكلّف غازًا في كل تكرار.
| البنية | المعنى |
|---|---|
if (x > 5) { ... } else if (x > 2) { ... } else { ... } | تفرعات شرطية |
for (uint i = 0; i < n; i++) { ... } | حلقة بعدّاد |
while (x < 10) { x++; } | التكرار ما دام الشرط صحيحًا |
do { ... } while (cond); | يُنفَّذ مرة واحدة على الأقل |
break; / continue; | الخروج من الحلقة / الانتقال إلى التكرار التالي |
x > 0 ? a : b | تعبير ثلاثي |
a / b | قسمة صحيحة (تُسقط الباقي) |
a % b | الباقي |
a ** 2 | الرفع إلى قوة |
unchecked { x++; } | تخطي التحقق من تجاوز السعة (يوفر الغاز، استخدمه بحذر) |
الأخطاء: require و revert و assert
فشل التحقق يُلغي المعاملة بكاملها ويُعيد الغاز غير المستخدم.
| البنية | المعنى |
|---|---|
require(amount > 0, "Amount must be positive"); | التحقق من المدخلات أو الحالة؛ الإرجاع مع رسالة |
revert("Not allowed"); | الإلغاء دون شرط |
error Insufficient(uint available, uint requested); | الإعلان عن خطأ مخصص (أقل تكلفة من السلاسل النصية) |
revert Insufficient(balance, amount); | الإرجاع بخطأ مخصص |
assert(total == a + b); | التحقق من ثابت لا يجب أن يفشل أبدًا |
try token.transfer(to, amt) returns (bool ok) { ... } catch { ... } | معالجة استدعاء خارجي فاشل |
الأحداث
تكتب الأحداث سجلات يمكن للتطبيقات خارج السلسلة الاشتراك فيها؛ ولا يمكن قراءتها من العقود.
| البنية | المعنى |
|---|---|
event Transfer(address indexed from, address indexed to, uint value); | الإعلان عن حدث |
emit Transfer(msg.sender, to, amount); | إصدار الحدث |
indexed | معامل قابل للتصفية (حتى 3 لكل حدث) |
event Log(string message); | يمكن تسجيل أي نوع ABI |
Ether والعناوين والمتغيرات العامة
يأتي سياق المعاملة من msg و block و tx.
| البنية | المعنى |
|---|---|
msg.sender | العنوان الذي استدعى هذه الدالة |
msg.value | الـ wei المُرسَل مع الاستدعاء (يتطلب payable) |
block.timestamp | وقت الكتلة الحالية (بالثواني منذ بداية الحقبة) |
block.number | ارتفاع الكتلة الحالية |
tx.origin | الحساب الخارجي الذي بدأ المعاملة (تجنّبه للمصادقة) |
address(this).balance | رصيد Ether لهذا العقد |
payable(to).transfer(1 ether); | إرسال Ether، يُرجع (revert) عند الفشل |
(bool ok, ) = to.call{value: amt}(""); | إرسال منخفض المستوى، يعيد علامة النجاح |
receive() external payable {} | يُنفَّذ عند تحويل Ether بسيط |
fallback() external payable {} | يُنفَّذ عندما لا تتطابق أي دالة |
keccak256(abi.encodePacked(a, b)) | تجزئة القيم |
abi.encode(x), abi.decode(data, (uint)) | ترميز / فك ترميز بيانات ABI |
كل جزء من بنية Solidity تحتاج إليه، في صفحة واحدة. هذه الورقة المرجعية لـ Solidity مرجع سريع للغة العقود الذكية على Ethereum وكل سلاسل EVM: الإعلان عن عقد، واختيار الأنواع، وتخزين البيانات في mapping و struct، وكتابة الدوال بالرؤية وقابلية التغيير الصحيحتين، وحمايتها بـ require والمعدِّلات والأحداث.
البنية هنا هي Solidity 0.8، التي تتحقق من تجاوز السعة الحسابي افتراضيًا وتعمل مع Remix و Hardhat و Foundry. انسخ ما تحتاجه، أو جرّبه مباشرة في ساحة Solidity التفاعلية: اكتب عقدًا، وجمّعه، ونفّذه على EVM داخل متصفحك.