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

تفاعل مع العقود الأخرى من سوليديتي

العقود الذكيه
Solidity
Remix
نشر
قابلية التركيب
إعدادات متقدمة
jdourlens
5 أبريل 2020
4 دقيقة قراءة

في الدروس التعليمية السابقة، تعلمنا الكثير كيفية نشر أول عقد ذكي لك وإضافة بعض الميزات إليه مثل التحكم في الوصول باستخدام المعدِّلات (opens in a new tab) أو معالجة الأخطاء في سوليديتي (opens in a new tab). في هذا الدرس التعليمي، سنتعلم كيفية نشر عقد ذكي من عقد موجود والتفاعل معه.

سننشئ عقدًا يمكّن أي شخص من الحصول على عقد Counter الذكي الخاص به عن طريق إنشاء مصنع له، وسيكون اسمه CounterFactory. أولاً، إليك النص البرمجي لعقد Counter الذكي المبدئي الخاص بنا:

1pragma solidity 0.5.17;
2
3contract Counter {
4
5 uint256 private _count;
6 address private _owner;
7 address private _factory;
8
9 modifier onlyOwner(address caller) {
10 require(caller == _owner, "أنت لست مالك العقد");
11 _;
12 }
13
14 modifier onlyFactory() {
15 require(msg.sender == _factory, "تحتاج إلى استخدام المصنع");
16 _;
17 }
18
19 constructor(address owner) public {
20 _owner = owner;
21 _factory = msg.sender;
22 }
23
24 function getCount() public view returns (uint256) {
25 return _count;
26 }
27
28 function increment(address caller) public onlyFactory onlyOwner(caller) {
29 _count++;
30 }
31
32}

لاحظ أننا عدّلنا النص البرمجي للعقد قليلاً لتتبع عنوان المصنع وعنوان مالك العقد. عند استدعاء نص برمجي لعقد من عقد آخر، سيشير msg.sender إلى عنوان مصنع العقد الخاص بنا. هذه نقطة مهمة جدًا يجب فهمها حيث إن استخدام عقد للتفاعل مع عقود أخرى ممارسة شائعة. لذلك يجب عليك الانتباه إلى من هو المرسل في الحالات المعقدة.

لهذا أضفنا أيضًا معدِّل onlyFactory الذي يضمن أن دالة تغيير الحالة لا يمكن استدعاؤها إلا من قبل المصنع الذي سيمرر المتصل الأصلي كمعامل.

داخل CounterFactory الجديد الخاص بنا الذي سيدير جميع عدادات Counters الأخرى، سنضيف تعيينًا سيربط المالك بعنوان عقد العداد الخاص به:

1mapping(address => Counter) _counters;

في إيثريوم، التعيينات (mappings) تعادل الكائنات (objects) في جافاسكريبت، فهي تتيح تعيين مفتاح من النوع A إلى قيمة من النوع B. في هذه الحالة، نقوم بتعيين عنوان المالك مع نسخة من Counter الخاص به.

إنشاء نسخة جديدة من Counter لشخص ما سيبدو هكذا:

1 function createCounter() public {
2 require (_counters[msg.sender] == Counter(0));
3 _counters[msg.sender] = new Counter(msg.sender);
4 }

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

للحصول على عدد عداد Counter معين، سيبدو الأمر هكذا:

1function getCount(address account) public view returns (uint256) {
2 require (_counters[account] != Counter(0));
3 return (_counters[account].getCount());
4}
5
6function getMyCount() public view returns (uint256) {
7 return (getCount(msg.sender));
8}

تتحقق الدالة الأولى مما إذا كان عقد Counter موجودًا لعنوان معين ثم تستدعي طريقة getCount من النسخة. الدالة الثانية: getMyCount هي مجرد نهاية قصيرة لتمرير msg.sender مباشرة إلى دالة getCount.

دالة increment مماثلة تمامًا لكنها تمرر مرسل المعاملة الأصلي إلى عقد Counter:

1function increment() public {
2 require (_counters[msg.sender] != Counter(0));
3 Counter(_counters[msg.sender]).increment(msg.sender);
4 }

لاحظ أنه إذا تم استدعاؤه مرات عديدة، فقد يكون العداد الخاص بنا ضحية لفيضان (overflow). يجب عليك استخدام مكتبة SafeMath (opens in a new tab) قدر الإمكان للحماية من هذه الحالة المحتملة.

لنشر عقدنا، ستحتاج إلى توفير كل من النص البرمجي لـ CounterFactory و Counter. عند النشر على سبيل المثال في ريميكس، ستحتاج إلى تحديد CounterFactory.

إليك النص البرمجي الكامل:

1pragma solidity 0.5.17;
2
3contract Counter {
4
5 uint256 private _count;
6 address private _owner;
7 address private _factory;
8
9 modifier onlyOwner(address caller) {
10 require(caller == _owner, "أنت لست مالك العقد");
11 _;
12 }
13
14 modifier onlyFactory() {
15 require(msg.sender == _factory, "تحتاج إلى استخدام المصنع");
16 _;
17 }
18
19 constructor(address owner) public {
20 _owner = owner;
21 _factory = msg.sender;
22 }
23
24 function getCount() public view returns (uint256) {
25 return _count;
26 }
27
28 function increment(address caller) public onlyFactory onlyOwner(caller) {
29 _count++;
30 }
31
32}
33
34contract CounterFactory {
35
36 mapping(address => Counter) _counters;
37
38 function createCounter() public {
39 require (_counters[msg.sender] == Counter(0));
40 _counters[msg.sender] = new Counter(msg.sender);
41 }
42
43 function increment() public {
44 require (_counters[msg.sender] != Counter(0));
45 Counter(_counters[msg.sender]).increment(msg.sender);
46 }
47
48 function getCount(address account) public view returns (uint256) {
49 require (_counters[account] != Counter(0));
50 return (_counters[account].getCount());
51 }
52
53 function getMyCount() public view returns (uint256) {
54 return (getCount(msg.sender));
55 }
56
57}

بعد التجميع، في قسم النشر في ريميكس ستحدد المصنع الذي سيتم نشره:

تحديد المصنع الذي سيتم نشره في ريميكس

بعد ذلك يمكنك اللعب بمصنع العقد الخاص بك والتحقق من تغير القيمة. إذا كنت ترغب في استدعاء العقد الذكي من عنوان مختلف، فستحتاج إلى تغيير العنوان في تحديد الحساب في ريميكس.

آخر تحديث للصفحة: 3 مارس 2026

هل كانت تعليمات الاستخدام هذه مفيدة؟