تشريح العقود الذكية
آخر تحديث للصفحة: 23 فبراير 2026
العقد الذكي هو برنامج يتم تشغيله على عنوان على إيثريوم. إنها تتكون من البيانات والوظائف التي يمكن تنفيذها عند تلقي المعاملة. فيما يلي نظرة عامة على العناصر التي يشكلها العقد الذكي.
المتطلبات الأساسية
تأكد من أنك قرأت عن العقود الذكية أولاً. يفترض هذا المستند أنك على دراية بلغات البرمجة مثل جافا سكريبت أو بايثون.
البيانات
يجب تعيين أي بيانات عقد إلى موقع: إما إلى storage أو memory. يعد تعديل مساحة التخزين في العقد الذكي أمرًا مكلفًا، لذا يتعين عليك التفكير في المكان الذي يجب أن تعيش فيه بياناتك.
التخزين
يشار إلى البيانات الدائمة بالتخزين ويتم تمثيلها بمتغيرات الحالة. يتم تخزين هذه القيم بشكل دائم على blockchain. يتعين عليك الإعلان عن النوع حتى يتمكن العقد من تتبع مقدار التخزين الذي تحتاجه على blockchain عند تجميعه.
1// مثال سوليديتي2contract SimpleStorage {3 uint storedData; // متغير الحالة4 // ...5}1# مثال Vyper2storedData: 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)23@view4@public5def readName() -> string:6 return dappNameما يعتبر تعديل الحالة:
- الكتابة لمتغيرات الحالة
- إصدار الأحداث (opens in a new tab).
- إنشاء عقود أخرى (opens in a new tab).
- استخدام
selfdestruct. - إرسال الأثير عن طريق المكالمات.
- استدعاء أي دالة غير معلمة كـ
viewأوpure. - استخدام المكالمات ذات المستوى المنخفض.
- استخدام التجميع المضمن الذي يحتوي على رمز تشغيل معينة.
دوال المُنشِئ
دوال 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-properties9 owner = msg.sender;10}إظهار الكل1# مثال Vyper23@external4def __init__(_beneficiary: address, _bidding_time: uint256):5 self.beneficiary = _beneficiary6 self.auctionStart = block.timestamp7 self.auctionEnd = self.auctionStart + _bidding_timeالدوال المدمجة
بالإضافة إلى المتغيرات والوظائف التي تحددها في عقدك، هناك بعض الوظائف الخاصة المضمنة. الأمثلة الأكثر وضوحا هي :
address.send()– سوليديتيsend(address)– فايبر
تسمح هذه العقود بإرسال ETH إلى حسابات أخرى.
كتابة الدوال
تحتاج وظيفتك إلى:
- متغير المعلمة ونوعها (إذا كان يقبل المعلمات)
- إعلان داخلي/خارجي
- إعلان نقي / عرض / مستحق الدفع
- نوع الإرجاع (إذا كان يُرجع قيمة)
1pragma solidity >=0.4.0 <=0.6.0;23contract ExampleDapp {4 string dapp_name; // متغير الحالة56 // تُستدعى عند نشر العقد وتهيئ القيمة7 constructor() public {8 dapp_name = "تطبيقي اللامركزي المثالي";9 }1011 // دالة الجلب12 function read_name() public view returns(string) {13 return dapp_name;14 }1516 // دالة الضبط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#pragma3pragma solidity ^0.5.10;45// يُعرِّف عقدًا باسم `HelloWorld`.6// العقد هو مجموعة من الدوال والبيانات (حالته).7// بمجرد نشره، يقيم العقد على عنوان محدد على بلوكتشين إيثريوم.8// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html9contract HelloWorld {1011 // يُعلن عن متغير حالة `message` من النوع `string`.12 // متغيرات الحالة هي متغيرات تُخزن قيمها بشكل دائم في مساحة تخزين العقد.13 // الكلمة المفتاحية `public` تجعل المتغيرات قابلة للوصول من خارج العقد14 // وتنشئ دالة يمكن للعقود الأخرى أو العملاء استدعاؤها للوصول إلى القيمة.15 string public message;1617 // على غرار العديد من لغات البرمجة الشيئية القائمة على الأصناف، المُنشئ هو18 // دالة خاصة لا تُنفذ إلا عند إنشاء العقد.19 // تُستخدم المُنشِئات لتهيئة بيانات العقد.20 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors21 constructor(string memory initMessage) public {22 // يقبل وسيط سلسلة نصية `initMessage` ويضبط القيمة23 // في متغير التخزين `message` الخاص بالعقد).24 message = initMessage;25 }2627 // دالة عامة تقبل وسيط سلسلة نصية28 // وتُحدِّث متغير التخزين `message`.29 function update(string memory newMessage) public {30 message = newMessage;31 }32}إظهار الكلالرمز
1pragma solidity ^0.5.10;23contract Token {4 // يشبه `address` عنوان البريد الإلكتروني - يُستخدم لتعريف حساب على إيثريوم.5 // يمكن أن تمثل العناوين عقدًا ذكيًا أو حسابات خارجية (للمستخدمين).6 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/types.html#address7 address public owner;89 // `mapping` هو في الأساس بنية بيانات جدول التجزئة (هاش).10 // يقوم هذا الـ `mapping` بتعيين عدد صحيح غير مُشار إليه (رصيد الرمز) إلى عنوان (حامل الرمز).11 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types12 mapping (address => uint) public balances;1314 // تسمح الأحداث بتسجيل النشاط على البلوكتشين.15 // يمكن لعملاء إيثريوم الاستماع إلى الأحداث من أجل التفاعل مع تغييرات حالة العقد.16 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events17 event Transfer(address from, address to, uint amount);1819 // يهيئ بيانات العقد، ويضبط `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-properties26 owner = msg.sender;27 }2829 // ينشئ كمية من الرموز الجديدة ويرسلها إلى عنوان.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-exceptions3536 // يمكن لمالك العقد فقط استدعاء هذه الدالة37 require(msg.sender == owner, "أنت لست المالك.");3839 // يفرض حدًا أقصى لكمية الرموز40 require(amount < 1e60, "تم تجاوز الحد الأقصى للإصدار");4142 // يزيد رصيد `receiver` بمقدار `amount`43 balances[receiver] += amount;44 }4546 // يرسل كمية من الرموز الموجودة من أي مستدعٍ إلى عنوان.47 function transfer(address receiver, uint amount) public {48 // يجب أن يكون لدى المرسل ما يكفي من الرموز لإرسالها49 require(amount <= balances[msg.sender], "رصيد غير كافٍ.");5051 // يعدل أرصدة الرموز للعنوانين52 balances[msg.sender] -= amount;53 balances[receiver] += amount;5455 // يُصدر الحدث المحدد سابقًا56 emit Transfer(msg.sender, receiver, amount);57 }58}إظهار الكلأصل رقمي فريد
1pragma solidity ^0.5.10;23// يستورد الرموز من ملفات أخرى إلى العقد الحالي.4// في هذه الحالة، سلسلة من العقود المساعدة من OpenZeppelin.5// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files67import "../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";1112// تُستخدم الكلمة المفتاحية `is` لوراثة الدوال والكلمات المفتاحية من العقود الخارجية.13// في هذه الحالة، يرث `CryptoPizza` من عقود `IERC721` و `ERC165`.14// اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance15contract CryptoPizza is IERC721, ERC165 {16 // يستخدم مكتبة SafeMath من OpenZeppelin لإجراء العمليات الحسابية بأمان.17 // اعرف المزيد: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath18 using SafeMath for uint256;1920 // متغيرات الحالة الثابتة في سوليديتي تشبه اللغات الأخرى21 // ولكن يجب عليك التعيين من تعبير ثابت في وقت الترجمة.22 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables23 uint256 constant dnaDigits = 10;24 uint256 constant dnaModulus = 10 ** dnaDigits;25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;2627 // تتيح لك أنواع Struct تحديد النوع الخاص بك28 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs29 struct Pizza {30 string name;31 uint256 dna;32 }3334 // ينشئ مصفوفة فارغة من هياكل Pizza35 Pizza[] public pizzas;3637 // ربط من معرف البيتزا إلى عنوان مالكها38 mapping(uint256 => address) public pizzaToOwner;3940 // ربط من عنوان المالك إلى عدد الرموز المملوكة41 mapping(address => uint256) public ownerPizzaCount;4243 // ربط من معرف الرمز إلى العنوان المعتمد44 mapping(uint256 => address) pizzaApprovals;4546 // يمكنك تداخل عمليات الربط، هذا المثال يربط المالك بموافقات المشغل47 mapping(address => mapping(address => bool)) private operatorApprovals;4849 // دالة داخلية لإنشاء بيتزا عشوائية من سلسلة نصية (الاسم) والحمض النووي (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-getters54 internal55 // `isUnique` هو مُعدِّل دالة يتحقق مما إذا كانت البيتزا موجودة بالفعل56 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers57 isUnique(_name, _dna)58 {59 // يضيف البيتزا إلى مصفوفة البيتزا ويحصل على المعرف60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);6162 // يتحقق من أن مالك البيتزا هو نفس المستخدم الحالي63 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions6465 // لاحظ أن address(0) هو العنوان الصفري،66 // مما يشير إلى أن pizza[id] لم يتم تخصيصها بعد لمستخدم معين.6768 assert(pizzaToOwner[id] == address(0));6970 // يربط البيتزا بالمالك71 pizzaToOwner[id] = msg.sender;72 ownerPizzaCount[msg.sender] = SafeMath.add(73 ownerPizzaCount[msg.sender],74 175 );76 }7778 // ينشئ بيتزا عشوائية من سلسلة نصية (الاسم)79 function createRandomPizza(string memory _name) public {80 uint256 randDna = generateRandomDna(_name, msg.sender);81 _createPizza(_name, randDna);82 }8384 // يولد حمضًا نوويًا عشوائيًا (DNA) من سلسلة نصية (الاسم) وعنوان المالك (المنشئ)85 function generateRandomDna(string memory _str, address _owner)86 public87 // الدوال المعلمة بأنها `pure` تعد بعدم القراءة من الحالة أو تعديلها88 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions89 pure90 returns (uint256)91 {92 // يولد عددًا صحيحًا عشوائيًا غير مُشار إليه من سلسلة نصية (الاسم) + عنوان (المالك)93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +94 uint256(_owner);95 rand = rand % dnaModulus;96 return rand;97 }9899 // يعيد مصفوفة من البيتزا التي تم العثور عليها حسب المالك100 function getPizzasByOwner(address _owner)101 public102 // الدوال المعلمة بأنها `view` تعد بعدم تعديل الحالة103 // اعرف المزيد: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions104 view105 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-stack110 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 }120121 // ينقل البيتزا والملكية إلى عنوان آخر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), "العنوان غير معتمد.");127128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);130 pizzaToOwner[_pizzaId] = _to;131132 // يُصدر الحدث المحدد في عقد IERC721 المستورد133 emit Transfer(_from, _to, _pizzaId);134 _clearApproval(_to, _pizzaId);135 }136137 /**138 * ينقل بأمان ملكية معرف رمز معين إلى عنوان آخر139 * إذا كان العنوان المستهدف عقدًا، فيجب عليه تنفيذ `onERC721Received`،140 * والذي يتم استدعاؤه عند النقل الآمن، وإرجاع القيمة السحرية141 * `bytes4(keccak256(\"onERC721Received(address,address,uint256,bytes)\"))`؛142 * وإلا، يتم التراجع عن النقل.143 */144 function safeTransferFrom(address from, address to, uint256 pizzaId)145 public146 {147 // solium-disable-next-line arg-overflow148 this.safeTransferFrom(from, to, pizzaId, "");149 }150151 /**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 _data163 ) public {164 this.transferFrom(from, to, pizzaId);165 require(_checkOnERC721Received(from, to, pizzaId, _data), "يجب تنفيذ onERC721Received.");166 }167168 /**169 * دالة داخلية لاستدعاء `onERC721Received` على عنوان مستهدف170 * لا يتم تنفيذ الاستدعاء إذا لم يكن العنوان المستهدف عقدًا171 */172 function _checkOnERC721Received(173 address from,174 address to,175 uint256 pizzaId,176 bytes memory _data177 ) internal returns (bool) {178 if (!isContract(to)) {179 return true;180 }181182 bytes4 retval = IERC721Receiver(to).onERC721Received(183 msg.sender,184 from,185 pizzaId,186 _data187 );188 return (retval == _ERC721_RECEIVED);189 }190191 // حرق بيتزا - يدمر الرمز بالكامل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), "العنوان غير معتمد.");198199 ownerPizzaCount[msg.sender] = SafeMath.sub(200 ownerPizzaCount[msg.sender],201 1202 );203 pizzaToOwner[_pizzaId] = address(0);204 }205206 // يعيد عدد البيتزا حسب العنوان207 function balanceOf(address _owner) public view returns (uint256 _balance) {208 return ownerPizzaCount[_owner];209 }210211 // يعيد مالك البيتزا الذي تم العثور عليه بالمعرف212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {213 address owner = pizzaToOwner[_pizzaId];214 require(owner != address(0), "معرف بيتزا غير صالح.");215 return owner;216 }217218 // يوافق لعنوان آخر على نقل ملكية البيتزا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 }224225 // يعيد العنوان المعتمد لبيتزا معينة226 function getApproved(uint256 _pizzaId)227 public228 view229 returns (address operator)230 {231 require(_exists(_pizzaId), "البيتزا غير موجودة.");232 return pizzaApprovals[_pizzaId];233 }234235 /**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 }246247 /*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 }256257 // يوضح ما إذا كان المشغل معتمدًا من قبل مالك معين258 function isApprovedForAll(address owner, address operator)259 public260 view261 returns (bool)262 {263 return operatorApprovals[owner][operator];264 }265266 // يستحوذ على ملكية البيتزا - للمستخدمين المعتمدين فقط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 }272273 // يتحقق مما إذا كانت البيتزا موجودة274 function _exists(uint256 pizzaId) internal view returns (bool) {275 address owner = pizzaToOwner[pizzaId];276 return owner != address(0);277 }278279 // يتحقق مما إذا كان العنوان مالكًا أو معتمدًا لنقل البيتزا280 function _isApprovedOrOwner(address spender, uint256 pizzaId)281 internal282 view283 returns (bool)284 {285 address owner = pizzaToOwner[pizzaId];286 // Disable solium check because of287 // https://github.com/duaraghav8/Solium/issues/175288 // solium-disable-next-line operator-whitespace289 return (spender == owner ||290 this.getApproved(pizzaId) == spender ||291 this.isApprovedForAll(owner, spender));292 }293294 // تحقق مما إذا كانت البيتزا فريدة وغير موجودة بعد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 == _dna302 ) {303 result = false;304 }305 }306 require(result, "توجد بالفعل بيتزا بهذا الاسم.");307 _;308 }309310 // يُرجع ما إذا كان العنوان المستهدف عقدًا311 function isContract(address account) internal view returns (bool) {312 uint256 size;313 // حاليًا لا توجد طريقة أفضل للتحقق مما إذا كان هناك عقد في عنوان ما314 // من التحقق من حجم النص البرمجي في ذلك العنوان.315 // انظر https://ethereum.stackexchange.com/a/14016/36603316 // لمزيد من التفاصيل حول كيفية عمل هذا.317 // TODO تحقق من هذا مرة أخرى قبل إصدار Serenity، لأن جميع العناوين ستكون318 // عقودًا في ذلك الحين.319 // solium-disable-next-line security/no-inline-assembly320 assembly {321 size := extcodesize(account)322 }323 return size > 0;324 }325}إظهار الكلقراءة إضافية
تحقق من وثائق سوليديتي وفايبر للحصول على نظرة عامة أكثر شمولاً حول العقود الذكية:
المواضيع ذات الصلة
دروس تعليمية ذات صلة
- تقليص حجم العقود لمواجهة حد حجم العقد - بعض النصائح العملية لتقليل حجم عقدك الذكي.
- تسجيل البيانات من العقود الذكية باستخدام الأحداث - مقدمة إلى أحداث العقود الذكية وكيفية استخدامها لتسجيل البيانات.
- التفاعل مع العقود الأخرى من سوليديتي - كيفية نشر عقد ذكي من عقد موجود والتفاعل معه.