تخطٍ إلى المحتوى الرئيسي
Change page

تشريح العقود الذكية

آخر تحديث للصفحة: 23 فبراير 2026

العقد الذكي هو برنامج يتم تشغيله على عنوان على إيثريوم. إنها تتكون من البيانات والوظائف التي يمكن تنفيذها عند تلقي المعاملة. فيما يلي نظرة عامة على العناصر التي يشكلها العقد الذكي.

المتطلبات الأساسية

تأكد من أنك قرأت عن العقود الذكية أولاً. يفترض هذا المستند أنك على دراية بلغات البرمجة مثل جافا سكريبت أو بايثون.

البيانات

يجب تعيين أي بيانات عقد إلى موقع: إما إلى storage أو memory. يعد تعديل مساحة التخزين في العقد الذكي أمرًا مكلفًا، لذا يتعين عليك التفكير في المكان الذي يجب أن تعيش فيه بياناتك.

التخزين

يشار إلى البيانات الدائمة بالتخزين ويتم تمثيلها بمتغيرات الحالة. يتم تخزين هذه القيم بشكل دائم على blockchain. يتعين عليك الإعلان عن النوع حتى يتمكن العقد من تتبع مقدار التخزين الذي تحتاجه على blockchain عند تجميعه.

1// مثال سوليديتي
2contract SimpleStorage {
3 uint storedData; // متغير الحالة
4 // ...
5}
1# مثال Vyper
2storedData: int128

إذا كنت قد قمت بالفعل ببرمجة لغات موجهة للكائنات، فمن المحتمل أن تكون على دراية بمعظم الأنواع. ومع ذلك، يجب أن يكون address جديدًا عليك إذا كنت جديدًا في تطوير إيثريوم.

يمكن لنوع address أن يحمل عنوان إيثريوم الذي يعادل 20 بايت أو 160 بت. يتم إرجاعه بالتدوين الست عشري مع 0x بادئة.

تشمل الأنواع الأخرى ما يلي:

  • منطقية
  • عدد صحيح
  • أرقام النقطة الثابتة
  • صفائف بايت ذات حجم ثابت
  • مصفوفات البايت ذات الحجم الديناميكي
  • القيم الحرفية النسبية والصحيحة
  • القيم الحرفية النصية
  • القيم الحرفية الست عشرية
  • التعدادات

لمزيد من التوضيح، نلقي نظرة على المستندات:

الذاكرة

تسمى القيم التي يتم تخزينها فقط طوال مدة تنفيذ وظيفة العقد بمتغيرات الذاكرة. وبما أنه لا يتم تخزينها بشكل دائم على blockchain، فهي أرخص بكثير في الاستخدام.

تعرف على المزيد حول كيفية تخزين EVM للبيانات (التخزين، والذاكرة، والمكدس) في وثائق سوليديتي (opens in a new tab).

متغيرات البيئة

بالإضافة إلى المتغيرات التي تحددها في العقد الخاص بك، هناك بعض المتغيرات العالمية الخاصة. يتم استخدامها بشكل أساسي لتوفير معلومات حول blockchain أو المعاملة الحالية.

أمثلة:

الخاصيةمتغيرات الحالةالوصف
block.timestampالوحدة 256الطابع الزمني لعصر الكتلة الحالي
msg.senderالعنوانمرسل الرسالة (المكالمة الحالية)

الدوال

بعبارات أبسط، يمكن للوظائف الحصول على معلومات أو تعيين معلومات استجابةً للمعاملات الواردة.

هناك نوعان من استدعاءات الوظائف:

  • internal – هذه لا تنشئ استدعاءً لـ EVM
    • لا يمكن الوصول إلى الدوال الداخلية ومتغيرات الحالة إلا داخليًا (أي من داخل العقد الحالي أو العقود المشتقة منه)
  • external – هذه تنشئ استدعاءً لـ EVM
    • تعد الوظائف الخارجية جزءًا من واجهة العقد، مما يعني أنه يمكن استدعاؤها من عقود أخرى وعبر المعاملات. لا يمكن استدعاء دالة خارجية f داخليًا (أي أن f() لا تعمل، لكن this.f() تعمل).

يمكن أيضًا أن تكون public أو private

  • يمكن استدعاء دوال public داخليًا من داخل العقد أو خارجيًا عبر الرسائل
  • دوال private مرئية فقط للعقد الذي عُرِّفت فيه وليس في العقود المشتقة

يمكن جعل كل من الوظائف ومتغيرات الحالة عامة أو خاصة

فيما يلي وظيفة لتحديث متغير الحالة في العقد:

1// مثال سوليديتي
2function update_name(string value) public {
3 dapp_name = value;
4}
  • المعلمة value من النوع string تُمرر إلى الدالة: update_name
  • تم إعلانها public، مما يعني أن أي شخص يمكنه الوصول إليها
  • لم يتم إعلانها view، لذا يمكنها تعديل حالة العقد

دوال العرض

تعد هذه الوظائف بعدم تعديل حالة بيانات العقد. الأمثلة الشائعة هي وظائف "الحصول على" - يمكنك استخدام هذا لتلقي رصيد المستخدم على سبيل المثال.

1// مثال سوليديتي
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName

ما يعتبر تعديل الحالة:

  1. الكتابة لمتغيرات الحالة
  2. إصدار الأحداث (opens in a new tab).
  3. إنشاء عقود أخرى (opens in a new tab).
  4. استخدام selfdestruct.
  5. إرسال الأثير عن طريق المكالمات.
  6. استدعاء أي دالة غير معلمة كـ view أو pure.
  7. استخدام المكالمات ذات المستوى المنخفض.
  8. استخدام التجميع المضمن الذي يحتوي على رمز تشغيل معينة.

دوال المُنشِئ

دوال constructor تُنفذ مرة واحدة فقط عند نشر العقد لأول مرة. مثل constructor في العديد من لغات البرمجة القائمة على الأصناف، غالبًا ما تُهيئ هذه الدوال متغيرات الحالة إلى قيمها المحددة.

1// مثال سوليديتي
2// يهيئ بيانات العقد، ويضبط `owner`
3// على عنوان مُنشئ العقد.
4constructor() public {
5 // تعتمد جميع العقود الذكية على المعاملات الخارجية لتشغيل دوالها.
6 // `msg` هو متغير عالمي يتضمن البيانات ذات الصلة بالمعاملة المحددة،
7 // مثل عنوان المرسل وقيمة ETH المضمنة في المعاملة.
8 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
إظهار الكل
1# مثال Vyper
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time

الدوال المدمجة

بالإضافة إلى المتغيرات والوظائف التي تحددها في عقدك، هناك بعض الوظائف الخاصة المضمنة. الأمثلة الأكثر وضوحا هي :

  • address.send() – سوليديتي
  • send(address) – فايبر

تسمح هذه العقود بإرسال ETH إلى حسابات أخرى.

كتابة الدوال

تحتاج وظيفتك إلى:

  • متغير المعلمة ونوعها (إذا كان يقبل المعلمات)
  • إعلان داخلي/خارجي
  • إعلان نقي / عرض / مستحق الدفع
  • نوع الإرجاع (إذا كان يُرجع قيمة)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // متغير الحالة
5
6 // تُستدعى عند نشر العقد وتهيئ القيمة
7 constructor() public {
8 dapp_name = "تطبيقي اللامركزي المثالي";
9 }
10
11 // دالة الجلب
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // دالة الضبط
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
إظهار الكل

قد يبدو العقد الكامل شيئًا كهذا. هنا، توفر دالة constructor قيمة أولية للمتغير dapp_name.

الأحداث والسجلات

تتيح الأحداث لعقدك الذكي التواصل مع الواجهة الأمامية أو تطبيقات الاشتراك الأخرى. بمجرد التحقق من صحة المعاملة وإضافتها إلى الكتلة، يمكن للعقود الذكية إصدار أحداث وتسجيل المعلومات، والتي يمكن للواجهة الأمامية بعد ذلك معالجتها واستخدامها.

أمثلة مشروحة

هذه بعض الأمثلة الصلبة المكتوبة . إذا كنت ترغب في تجربة النص البرمجي، يمكنك التفاعل معه في ريميكس (opens in a new tab).

Hello world

1// يحدد إصدار سوليديتي، باستخدام الإصدار الدلالي.
2// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// يُعرِّف عقدًا باسم `HelloWorld`.
6// العقد هو مجموعة من الدوال والبيانات (حالته).
7// بمجرد نشره، يقيم العقد على عنوان محدد على بلوكتشين إيثريوم.
8// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // يُعلن عن متغير حالة `message` من النوع `string`.
12 // متغيرات الحالة هي متغيرات تُخزن قيمها بشكل دائم في مساحة تخزين العقد.
13 // الكلمة المفتاحية `public` تجعل المتغيرات قابلة للوصول من خارج العقد
14 // وتنشئ دالة يمكن للعقود الأخرى أو العملاء استدعاؤها للوصول إلى القيمة.
15 string public message;
16
17 // على غرار العديد من لغات البرمجة الشيئية القائمة على الأصناف، المُنشئ هو
18 // دالة خاصة لا تُنفذ إلا عند إنشاء العقد.
19 // تُستخدم المُنشِئات لتهيئة بيانات العقد.
20 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // يقبل وسيط سلسلة نصية `initMessage` ويضبط القيمة
23 // في متغير التخزين `message` الخاص بالعقد).
24 message = initMessage;
25 }
26
27 // دالة عامة تقبل وسيط سلسلة نصية
28 // وتُحدِّث متغير التخزين `message`.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
إظهار الكل

الرمز

1pragma solidity ^0.5.10;
2
3contract Token {
4 // يشبه `address` عنوان البريد الإلكتروني - يُستخدم لتعريف حساب على إيثريوم.
5 // يمكن أن تمثل العناوين عقدًا ذكيًا أو حسابات خارجية (للمستخدمين).
6 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // `mapping` هو في الأساس بنية بيانات جدول التجزئة (هاش).
10 // يقوم هذا الـ `mapping` بتعيين عدد صحيح غير مُشار إليه (رصيد الرمز) إلى عنوان (حامل الرمز).
11 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // تسمح الأحداث بتسجيل النشاط على البلوكتشين.
15 // يمكن لعملاء إيثريوم الاستماع إلى الأحداث من أجل التفاعل مع تغييرات حالة العقد.
16 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // يهيئ بيانات العقد، ويضبط `owner`
20 // على عنوان مُنشئ العقد.
21 constructor() public {
22 // تعتمد جميع العقود الذكية على المعاملات الخارجية لتشغيل دوالها.
23 // `msg` هو متغير عالمي يتضمن البيانات ذات الصلة بالمعاملة المحددة،
24 // مثل عنوان المرسل وقيمة ETH المضمنة في المعاملة.
25 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // ينشئ كمية من الرموز الجديدة ويرسلها إلى عنوان.
30 function mint(address receiver, uint amount) public {
31 // `require` هي بنية تحكم تستخدم لفرض شروط معينة.
32 // إذا تم تقييم عبارة `require` إلى `false`، يتم إطلاق استثناء،
33 // والذي يعكس جميع التغييرات التي تم إجراؤها على الحالة أثناء الاستدعاء الحالي.
34 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // يمكن لمالك العقد فقط استدعاء هذه الدالة
37 require(msg.sender == owner, "أنت لست المالك.");
38
39 // يفرض حدًا أقصى لكمية الرموز
40 require(amount < 1e60, "تم تجاوز الحد الأقصى للإصدار");
41
42 // يزيد رصيد `receiver` بمقدار `amount`
43 balances[receiver] += amount;
44 }
45
46 // يرسل كمية من الرموز الموجودة من أي مستدعٍ إلى عنوان.
47 function transfer(address receiver, uint amount) public {
48 // يجب أن يكون لدى المرسل ما يكفي من الرموز لإرسالها
49 require(amount <= balances[msg.sender], "رصيد غير كافٍ.");
50
51 // يعدل أرصدة الرموز للعنوانين
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // يُصدر الحدث المحدد سابقًا
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
إظهار الكل

أصل رقمي فريد

1pragma solidity ^0.5.10;
2
3// يستورد الرموز من ملفات أخرى إلى العقد الحالي.
4// في هذه الحالة، سلسلة من العقود المساعدة من OpenZeppelin.
5// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files
6
7import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";
10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";
11
12// تُستخدم الكلمة المفتاحية `is` لوراثة الدوال والكلمات المفتاحية من العقود الخارجية.
13// في هذه الحالة، يرث `CryptoPizza` من عقود `IERC721` و `ERC165`.
14// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // يستخدم مكتبة SafeMath من OpenZeppelin لإجراء العمليات الحسابية بأمان.
17 // اعرف المزيد: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // متغيرات الحالة الثابتة في سوليديتي تشبه اللغات الأخرى
21 // ولكن يجب عليك التعيين من تعبير ثابت في وقت الترجمة.
22 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // تتيح لك أنواع Struct تحديد النوع الخاص بك
28 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // ينشئ مصفوفة فارغة من هياكل Pizza
35 Pizza[] public pizzas;
36
37 // ربط من معرف البيتزا إلى عنوان مالكها
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // ربط من عنوان المالك إلى عدد الرموز المملوكة
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // ربط من معرف الرمز إلى العنوان المعتمد
44 mapping(uint256 => address) pizzaApprovals;
45
46 // يمكنك تداخل عمليات الربط، هذا المثال يربط المالك بموافقات المشغل
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // دالة داخلية لإنشاء بيتزا عشوائية من سلسلة نصية (الاسم) والحمض النووي (DNA)
50 function _createPizza(string memory _name, uint256 _dna)
51 // الكلمة المفتاحية `internal` تعني أن هذه الدالة مرئية فقط
52 // داخل هذا العقد والعقود التي تشتق من هذا العقد
53 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` هو مُعدِّل دالة يتحقق مما إذا كانت البيتزا موجودة بالفعل
56 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // يضيف البيتزا إلى مصفوفة البيتزا ويحصل على المعرف
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // يتحقق من أن مالك البيتزا هو نفس المستخدم الحالي
63 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // لاحظ أن address(0) هو العنوان الصفري،
66 // مما يشير إلى أن pizza[id] لم يتم تخصيصها بعد لمستخدم معين.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // يربط البيتزا بالمالك
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // ينشئ بيتزا عشوائية من سلسلة نصية (الاسم)
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // يولد حمضًا نوويًا عشوائيًا (DNA) من سلسلة نصية (الاسم) وعنوان المالك (المنشئ)
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // الدوال المعلمة بأنها `pure` تعد بعدم القراءة من الحالة أو تعديلها
88 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // يولد عددًا صحيحًا عشوائيًا غير مُشار إليه من سلسلة نصية (الاسم) + عنوان (المالك)
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // يعيد مصفوفة من البيتزا التي تم العثور عليها حسب المالك
100 function getPizzasByOwner(address _owner)
101 public
102 // الدوال المعلمة بأنها `view` تعد بعدم تعديل الحالة
103 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // يستخدم موقع التخزين `memory` لتخزين القيم فقط لـ
108 // دورة حياة استدعاء هذه الدالة.
109 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
111 uint256 counter = 0;
112 for (uint256 i = 0; i < pizzas.length; i++) {
113 if (pizzaToOwner[i] == _owner) {
114 result[counter] = i;
115 counter++;
116 }
117 }
118 return result;
119 }
120
121 // ينقل البيتزا والملكية إلى عنوان آخر
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "عنوان غير صالح.");
124 require(_exists(_pizzaId), "البيتزا غير موجودة.");
125 require(_from != _to, "لا يمكن النقل إلى نفس العنوان.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "العنوان غير معتمد.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // يُصدر الحدث المحدد في عقد IERC721 المستورد
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /**
138 * ينقل بأمان ملكية معرف رمز معين إلى عنوان آخر
139 * إذا كان العنوان المستهدف عقدًا، فيجب عليه تنفيذ `onERC721Received`،
140 * والذي يتم استدعاؤه عند النقل الآمن، وإرجاع القيمة السحرية
141 * `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`؛
142 * وإلا، يتم التراجع عن النقل.
143 */
144 function safeTransferFrom(address from, address to, uint256 pizzaId)
145 public
146 {
147 // solium-disable-next-line arg-overflow
148 this.safeTransferFrom(from, to, pizzaId, "");
149 }
150
151 /**
152 * ينقل بأمان ملكية معرف رمز معين إلى عنوان آخر
153 * إذا كان العنوان المستهدف عقدًا، فيجب عليه تنفيذ `onERC721Received`،
154 * والذي يتم استدعاؤه عند النقل الآمن، وإرجاع القيمة السحرية
155 * `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`؛
156 * وإلا، يتم التراجع عن النقل.
157 */
158 function safeTransferFrom(
159 address from,
160 address to,
161 uint256 pizzaId,
162 bytes memory _data
163 ) public {
164 this.transferFrom(from, to, pizzaId);
165 require(_checkOnERC721Received(from, to, pizzaId, _data), "يجب تنفيذ onERC721Received.");
166 }
167
168 /**
169 * دالة داخلية لاستدعاء `onERC721Received` على عنوان مستهدف
170 * لا يتم تنفيذ الاستدعاء إذا لم يكن العنوان المستهدف عقدًا
171 */
172 function _checkOnERC721Received(
173 address from,
174 address to,
175 uint256 pizzaId,
176 bytes memory _data
177 ) internal returns (bool) {
178 if (!isContract(to)) {
179 return true;
180 }
181
182 bytes4 retval = IERC721Receiver(to).onERC721Received(
183 msg.sender,
184 from,
185 pizzaId,
186 _data
187 );
188 return (retval == _ERC721_RECEIVED);
189 }
190
191 // حرق بيتزا - يدمر الرمز بالكامل
192 // مُعدِّل الدالة `external` يعني أن هذه الدالة
193 // جزء من واجهة العقد ويمكن للعقود الأخرى استدعاؤها
194 function burn(uint256 _pizzaId) external {
195 require(msg.sender != address(0), "عنوان غير صالح.");
196 require(_exists(_pizzaId), "البيتزا غير موجودة.");
197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "العنوان غير معتمد.");
198
199 ownerPizzaCount[msg.sender] = SafeMath.sub(
200 ownerPizzaCount[msg.sender],
201 1
202 );
203 pizzaToOwner[_pizzaId] = address(0);
204 }
205
206 // يعيد عدد البيتزا حسب العنوان
207 function balanceOf(address _owner) public view returns (uint256 _balance) {
208 return ownerPizzaCount[_owner];
209 }
210
211 // يعيد مالك البيتزا الذي تم العثور عليه بالمعرف
212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
213 address owner = pizzaToOwner[_pizzaId];
214 require(owner != address(0), "معرف بيتزا غير صالح.");
215 return owner;
216 }
217
218 // يوافق لعنوان آخر على نقل ملكية البيتزا
219 function approve(address _to, uint256 _pizzaId) public {
220 require(msg.sender == pizzaToOwner[_pizzaId], "يجب أن يكون مالك البيتزا.");
221 pizzaApprovals[_pizzaId] = _to;
222 emit Approval(msg.sender, _to, _pizzaId);
223 }
224
225 // يعيد العنوان المعتمد لبيتزا معينة
226 function getApproved(uint256 _pizzaId)
227 public
228 view
229 returns (address operator)
230 {
231 require(_exists(_pizzaId), "البيتزا غير موجودة.");
232 return pizzaApprovals[_pizzaId];
233 }
234
235 /**
236 * دالة خاصة لمسح الموافقة الحالية لمعرف رمز معين
237 * يتم التراجع إذا لم يكن العنوان المحدد هو مالك الرمز بالفعل
238 */
239 function _clearApproval(address owner, uint256 _pizzaId) private {
240 require(pizzaToOwner[_pizzaId] == owner, "يجب أن يكون مالك البيتزا.");
241 require(_exists(_pizzaId), "البيتزا غير موجودة.");
242 if (pizzaApprovals[_pizzaId] != address(0)) {
243 pizzaApprovals[_pizzaId] = address(0);
244 }
245 }
246
247 /*
248 * يضبط أو يلغي ضبط موافقة مشغل معين
249 * يُسمح للمشغل بنقل جميع رموز المرسل نيابة عنهم
250 */
251 function setApprovalForAll(address to, bool approved) public {
252 require(to != msg.sender, "لا يمكن الموافقة على العنوان الخاص بك");
253 operatorApprovals[msg.sender][to] = approved;
254 emit ApprovalForAll(msg.sender, to, approved);
255 }
256
257 // يوضح ما إذا كان المشغل معتمدًا من قبل مالك معين
258 function isApprovedForAll(address owner, address operator)
259 public
260 view
261 returns (bool)
262 {
263 return operatorApprovals[owner][operator];
264 }
265
266 // يستحوذ على ملكية البيتزا - للمستخدمين المعتمدين فقط
267 function takeOwnership(uint256 _pizzaId) public {
268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "العنوان غير معتمد.");
269 address owner = this.ownerOf(_pizzaId);
270 this.transferFrom(owner, msg.sender, _pizzaId);
271 }
272
273 // يتحقق مما إذا كانت البيتزا موجودة
274 function _exists(uint256 pizzaId) internal view returns (bool) {
275 address owner = pizzaToOwner[pizzaId];
276 return owner != address(0);
277 }
278
279 // يتحقق مما إذا كان العنوان مالكًا أو معتمدًا لنقل البيتزا
280 function _isApprovedOrOwner(address spender, uint256 pizzaId)
281 internal
282 view
283 returns (bool)
284 {
285 address owner = pizzaToOwner[pizzaId];
286 // Disable solium check because of
287 // https://github.com/duaraghav8/Solium/issues/175
288 // solium-disable-next-line operator-whitespace
289 return (spender == owner ||
290 this.getApproved(pizzaId) == spender ||
291 this.isApprovedForAll(owner, spender));
292 }
293
294 // تحقق مما إذا كانت البيتزا فريدة وغير موجودة بعد
295 modifier isUnique(string memory _name, uint256 _dna) {
296 bool result = true;
297 for (uint256 i = 0; i < pizzas.length; i++) {
298 if (
299 keccak256(abi.encodePacked(pizzas[i].name)) ==
300 keccak256(abi.encodePacked(_name)) &&
301 pizzas[i].dna == _dna
302 ) {
303 result = false;
304 }
305 }
306 require(result, "توجد بالفعل بيتزا بهذا الاسم.");
307 _;
308 }
309
310 // يُرجع ما إذا كان العنوان المستهدف عقدًا
311 function isContract(address account) internal view returns (bool) {
312 uint256 size;
313 // حاليًا لا توجد طريقة أفضل للتحقق مما إذا كان هناك عقد في عنوان ما
314 // من التحقق من حجم النص البرمجي في ذلك العنوان.
315 // انظر https://ethereum.stackexchange.com/a/14016/36603
316 // لمزيد من التفاصيل حول كيفية عمل هذا.
317 // TODO تحقق من هذا مرة أخرى قبل إصدار Serenity، لأن جميع العناوين ستكون
318 // عقودًا في ذلك الحين.
319 // solium-disable-next-line security/no-inline-assembly
320 assembly {
321 size := extcodesize(account)
322 }
323 return size > 0;
324 }
325}
إظهار الكل

قراءة إضافية

تحقق من وثائق سوليديتي وفايبر للحصول على نظرة عامة أكثر شمولاً حول العقود الذكية:

هل كانت هذه المقالة مفيدة؟