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

عقد ذكي ⁦Hello World⁩ للمبتدئين - ⁦Fullstack⁩

Solidity
Hardhat
Alchemy
العقود الذكية
النشر
مستكشف الكتل
الواجهة الأمامية
المعاملات
إطار العمل
مبتدئ
nstrike2
25 أكتوبر 2021
41 دقيقة للقراءة

هذا الدليل مخصص لك إذا كنت جديدًا في مجال تطوير سلسلة الكتل ولا تعرف من أين تبدأ أو كيف تقوم بنشر العقود الذكية والتفاعل معها. سنستعرض معًا كيفية إنشاء ونشر عقد ذكي بسيط على شبكة اختبار غويرلي باستخدام ميتاماسك (opens in a new tab)، وSolidity (opens in a new tab)، وHardhat (opens in a new tab)، وAlchemy (opens in a new tab).

ستحتاج إلى حساب Alchemy لإكمال هذا البرنامج التعليمي. سجل للحصول على حساب مجاني (opens in a new tab).

إذا كانت لديك أسئلة في أي وقت، فلا تتردد في التواصل معنا في ديسكورد Alchemy (opens in a new tab)!

الجزء الأول - إنشاء ونشر عقدك الذكي باستخدام Hardhat

الاتصال بشبكة إيثيريوم

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

إنشاء تطبيقك ومفتاح API

بمجرد إنشاء حساب Alchemy، يمكنك إنشاء مفتاح API عن طريق إنشاء تطبيق. سيسمح لك هذا بإجراء طلبات إلى شبكة اختبار غويرلي. إذا لم تكن على دراية بشبكات الاختبار، يمكنك قراءة دليل Alchemy لاختيار شبكة (opens in a new tab).

في لوحة تحكم Alchemy، ابحث عن القائمة المنسدلة Apps (التطبيقات) في شريط التنقل وانقر على Create App (إنشاء تطبيق).

Hello world create app

امنح تطبيقك الاسم 'Hello World' واكتب وصفًا قصيرًا. حدد Staging كبيئتك وغويرلي كشبكتك.

create app view hello world

ملاحظة: تأكد من تحديد غويرلي، وإلا فلن ينجح هذا البرنامج التعليمي.

انقر على Create app (إنشاء تطبيق). سيظهر تطبيقك في الجدول أدناه.

إنشاء حساب إيثيريوم

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

يمكنك تنزيل وإنشاء حساب ميتاماسك مجانًا هنا (opens in a new tab). عند إنشاء حساب، أو إذا كان لديك حساب بالفعل، تأكد من التبديل إلى "Goerli Test Network" (شبكة اختبار غويرلي) في الجزء العلوي الأيمن (حتى لا نتعامل بأموال حقيقية).

الخطوة 4: إضافة إيثر من صنبور

لنشر عقدك الذكي على شبكة الاختبار، ستحتاج إلى بعض ETH الوهمي. للحصول على ETH على شبكة غويرلي، انتقل إلى صنبور غويرلي وأدخل عنوان حساب غويرلي الخاص بك. لاحظ أن صنابير غويرلي قد تكون غير موثوقة بعض الشيء مؤخرًا - راجع صفحة شبكات الاختبار للحصول على قائمة بالخيارات التي يمكنك تجربتها:

ملاحظة: بسبب ازدحام الشبكة، قد يستغرق هذا بعض الوقت. ``

الخطوة 5: التحقق من رصيدك

للتحقق مرة أخرى من وجود ETH في محفظتك، دعنا نُجري طلب eth_getBalance (opens in a new tab) باستخدام أداة وضع الحماية (sandbox) الخاصة بـ Alchemy (opens in a new tab). سيؤدي هذا إلى إرجاع مقدار ETH الموجود في محفظتنا. لمعرفة المزيد، تحقق من البرنامج التعليمي القصير لـ Alchemy حول كيفية استخدام أداة الإنشاء (composer) (opens in a new tab).

أدخل عنوان حساب ميتاماسك الخاص بك وانقر على Send Request (إرسال طلب). سترى استجابة تبدو مثل مقتطف الكود أدناه.

{ "jsonrpc": "2.0", "id": 0, "result": "0x2B5E3AF16B1880000" }

ملاحظة: هذه النتيجة بوحدة wei، وليس ETH. تُستخدم wei كأصغر فئة من الإيثر.

يا للراحة! أموالنا الوهمية كلها موجودة.

الخطوة 6: تهيئة مشروعنا

أولاً، سنحتاج إلى إنشاء مجلد لمشروعنا. انتقل إلى سطر الأوامر الخاص بك وأدخل ما يلي.

mkdir hello-world
cd hello-world

الآن بعد أن أصبحنا داخل مجلد مشروعنا، سنستخدم npm init لتهيئة المشروع.

إذا لم يكن لديك npm مثبتًا بعد، فاتبع تعليمات تثبيت Node.js (opens in a new tab) لتثبيت Node.js وnpm.

لأغراض هذا البرنامج التعليمي، لا يهم كيف تجيب على أسئلة التهيئة. إليك كيف قمنا بذلك كمرجع:

وافق على ملف package.json ونحن جاهزون للبدء!

الخطوة 7: تنزيل Hardhat

Hardhat هي بيئة تطوير لتجميع برمجيات إيثيريوم الخاصة بك ونشرها واختبارها وتصحيح أخطائها. إنها تساعد المطورين عند بناء العقود الذكية والتطبيقات اللامركزية (dapps) محليًا قبل النشر على السلسلة الحية.

داخل مشروع hello-world الخاص بنا، قم بتشغيل:

npm install --save-dev hardhat

تحقق من هذه الصفحة لمزيد من التفاصيل حول تعليمات التثبيت (opens in a new tab).

الخطوة 8: إنشاء مشروع Hardhat

داخل مجلد مشروع hello-world الخاص بنا، قم بتشغيل:

npx hardhat

يجب أن ترى بعد ذلك رسالة ترحيب وخيارًا لتحديد ما تريد القيام به. حدد "create an empty hardhat.config.js":

سيؤدي هذا إلى إنشاء ملف hardhat.config.js في المشروع. سنستخدم هذا لاحقًا في البرنامج التعليمي لتحديد إعداد مشروعنا.

الخطوة 9: إضافة مجلدات المشروع

للحفاظ على تنظيم المشروع، دعنا ننشئ مجلدين جديدين. في سطر الأوامر، انتقل إلى الدليل الجذر لمشروع hello-world الخاص بك واكتب:

mkdir contracts
mkdir scripts
  • contracts/ هو المكان الذي سنحتفظ فيه بملف كود العقد الذكي hello world الخاص بنا
  • scripts/ هو المكان الذي سنحتفظ فيه بالبرامج النصية لنشر عقدنا والتفاعل معه

الخطوة 10: كتابة عقدنا

ربما تسأل نفسك، متى سنكتب الكود؟ لقد حان الوقت!

افتح مشروع hello-world في محرر الأكواد المفضل لديك. تُكتب العقود الذكية في الغالب بلغة Solidity، والتي سنستخدمها لكتابة عقدنا الذكي.‌

  1. انتقل إلى مجلد contracts وأنشئ ملفًا جديدًا يسمى HelloWorld.sol
  2. يوجد أدناه نموذج لعقد ذكي Hello World سنستخدمه في هذا البرنامج التعليمي. انسخ المحتويات أدناه إلى ملف HelloWorld.sol.

ملاحظة: تأكد من قراءة التعليقات لفهم ما يفعله هذا العقد.

هذا عقد ذكي أساسي يخزن رسالة عند إنشائه. يمكن تحديثه عن طريق استدعاء دالة update.

الخطوة 11: ربط ميتاماسك وAlchemy بمشروعك

لقد أنشأنا محفظة ميتاماسك، وحساب Alchemy، وكتبنا عقدنا الذكي، والآن حان الوقت لربط الثلاثة معًا.

تتطلب كل معاملة يتم إرسالها من محفظتك توقيعًا باستخدام مفتاحك الخاص الفريد. لتزويد برنامجنا بهذا الإذن، يمكننا تخزين مفتاحنا الخاص بأمان في ملف بيئة. سنقوم أيضًا بتخزين مفتاح API لـ Alchemy هنا.

لمعرفة المزيد حول إرسال المعاملات، تحقق من هذا البرنامج التعليمي حول إرسال المعاملات باستخدام Web3.

أولاً، قم بتثبيت حزمة dotenv في دليل مشروعك:

npm install dotenv --save

ثم، أنشئ ملف .env في الدليل الجذر للمشروع. أضف مفتاح ميتاماسك الخاص بك وعنوان URL الخاص بـ HTTP Alchemy API إليه.

يجب أن يُسمى ملف البيئة الخاص بك .env وإلا فلن يتم التعرف عليه كملف بيئة.

لا تسمه process.env أو .env-custom أو أي شيء آخر.

Animated walkthrough of getting an Alchemy API key

يجب أن يبدو ملف .env الخاص بك هكذا:

API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key"
PRIVATE_KEY = "your-metamask-private-key"

لربط هذه المتغيرات فعليًا بالكود الخاص بنا، سنشير إليها في ملف hardhat.config.js الخاص بنا في الخطوة 13.

الخطوة 12: تثبيت Ethers.js

Ethers.js هي مكتبة تسهل التفاعل وإجراء الطلبات إلى إيثيريوم عن طريق تغليف طرق JSON-RPC القياسية بطرق أكثر سهولة في الاستخدام.

يسمح لنا Hardhat بدمج المكونات الإضافية (opens in a new tab) للحصول على أدوات إضافية ووظائف موسعة. سنستفيد من مكون Ethers الإضافي (opens in a new tab) لنشر العقد.

في دليل مشروعك اكتب:

npm install --save-dev @nomiclabs/hardhat-ethers "ethers@^5.0.0"

الخطوة 13: تحديث hardhat.config.js

لقد أضفنا العديد من التبعيات والمكونات الإضافية حتى الآن، والآن نحتاج إلى تحديث hardhat.config.js حتى يتعرف مشروعنا عليها جميعًا.

قم بتحديث hardhat.config.js الخاص بك ليبدو هكذا:

الخطوة 14: تجميع عقدنا

للتأكد من أن كل شيء يعمل حتى الآن، دعنا نجمع عقدنا. مهمة compile هي إحدى مهام Hardhat المدمجة.

من سطر الأوامر قم بتشغيل:

npx hardhat compile

قد تتلقى تحذيرًا بشأن SPDX license identifier not provided in source file، ولكن لا داعي للقلق حيال ذلك — نأمل أن يبدو كل شيء آخر جيدًا! إذا لم يكن الأمر كذلك، يمكنك دائمًا إرسال رسالة في ديسكورد Alchemy (opens in a new tab).

الخطوة 15: كتابة البرنامج النصي للنشر

الآن بعد أن تمت كتابة عقدنا وملف التكوين الخاص بنا جاهز للعمل، حان الوقت لكتابة البرنامج النصي لنشر العقد.

انتقل إلى مجلد scripts/ وأنشئ ملفًا جديدًا يسمى deploy.js ، مع إضافة المحتويات التالية إليه:

يقوم Hardhat بعمل رائع في شرح ما يفعله كل سطر من أسطر الكود هذه في البرنامج التعليمي للعقود (opens in a new tab) الخاص بهم، وقد اعتمدنا شروحاتهم هنا.

const HelloWorld = await ethers.getContractFactory("HelloWorld")

إن ContractFactory في ethers.js هو تجريد يُستخدم لنشر عقود ذكية جديدة، لذا فإن HelloWorld هنا هو مصنع (factory) (opens in a new tab) لمثيلات عقد hello world الخاص بنا. عند استخدام المكون الإضافي hardhat-ethers مع ContractFactory وContract، يتم توصيل المثيلات بالمُوقّع الأول (المالك) افتراضيًا.

const hello_world = await HelloWorld.deploy()

سيؤدي استدعاء deploy() على ContractFactory إلى بدء النشر، وإرجاع Promise الذي يُحل إلى كائن Contract. هذا هو الكائن الذي يحتوي على طريقة (method) لكل دالة من دوال عقدنا الذكي.

الخطوة 16: نشر عقدنا

نحن مستعدون أخيرًا لنشر عقدنا الذكي! انتقل إلى سطر الأوامر وقم بتشغيل:

npx hardhat run scripts/deploy.js --network goerli

يجب أن ترى بعد ذلك شيئًا مثل:

Contract deployed to address: 0x6cd7d44516a20882cEa2DE9f205bF401c0d23570

يرجى حفظ هذا العنوان. سنستخدمه لاحقًا في البرنامج التعليمي.

إذا ذهبنا إلى Etherscan غويرلي (opens in a new tab) وبحثنا عن عنوان عقدنا، يجب أن نتمكن من رؤية أنه قد تم نشره بنجاح. ستبدو المعاملة كالتالي:

يجب أن يتطابق عنوان From مع عنوان حساب ميتاماسك الخاص بك وسيشير عنوان To إلى Contract Creation (إنشاء عقد). إذا نقرنا على المعاملة، فسنرى عنوان عقدنا في حقل To.

تهانينا! لقد قمت للتو بنشر عقد ذكي على شبكة اختبار إيثيريوم.

لفهم ما يحدث داخليًا، دعنا ننتقل إلى علامة التبويب Explorer (المستكشف) في لوحة تحكم Alchemy (opens in a new tab) الخاصة بنا. إذا كان لديك تطبيقات Alchemy متعددة، فتأكد من التصفية حسب التطبيق وحدد Hello World.

هنا سترى مجموعة من طرق JSON-RPC التي قام بها Hardhat/Ethers داخليًا من أجلنا عندما استدعينا دالة .deploy(). هناك طريقتان مهمتان هنا هما eth_sendRawTransaction (opens in a new tab)، وهو طلب كتابة عقدنا على سلسلة غويرلي، وeth_getTransactionByHash (opens in a new tab)، وهو طلب لقراءة معلومات حول معاملتنا بناءً على التجزئة (hash). لمعرفة المزيد حول إرسال المعاملات، تحقق من برنامجنا التعليمي حول إرسال المعاملات باستخدام Web3.

الجزء 2: التفاعل مع عقدك الذكي

الآن بعد أن نجحنا في نشر عقد ذكي على شبكة غويرلي، دعونا نتعلم كيفية التفاعل معه.

إنشاء ملف interact.js

هذا هو الملف الذي سنكتب فيه نص التفاعل الخاص بنا. سنستخدم مكتبة Ethers.js التي قمت بتثبيتها مسبقًا في الجزء 1.

داخل مجلد scripts/، قم بإنشاء ملف جديد باسم interact.js وأضف الكود التالي:

// interact.js

const API_KEY = process.env.API_KEY
const PRIVATE_KEY = process.env.PRIVATE_KEY
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS

تحديث ملف .env الخاص بك

سنستخدم متغيرات بيئة جديدة، لذا نحتاج إلى تعريفها في ملف .env الذي أنشأناه سابقًا.

سنحتاج إلى إضافة تعريف لـ API_KEY الخاص بـ Alchemy و CONTRACT_ADDRESS حيث تم نشر عقدك الذكي.

يجب أن يبدو ملف .env الخاص بك هكذا:

# .env

API_URL = "https://eth-goerli.alchemyapi.io/v2/<your-api-key>"
API_KEY = "<your-api-key>"
PRIVATE_KEY = "<your-metamask-private-key>"
CONTRACT_ADDRESS = "0x<your contract address>"

الحصول على ABI الخاص بعقدك

إن لعقدنا هي الواجهة للتفاعل مع عقدنا الذكي. يقوم Hardhat تلقائيًا بإنشاء ABI ويحفظه في HelloWorld.json. لاستخدام ABI، سنحتاج إلى تحليل المحتويات عن طريق إضافة أسطر الكود التالية إلى ملف interact.js الخاص بنا:

// interact.js
const contract = require("../artifacts/contracts/HelloWorld.sol/HelloWorld.json")

إذا كنت ترغب في رؤية ABI، يمكنك طباعته في وحدة التحكم الخاصة بك:

console.log(JSON.stringify(contract.abi))

لرؤية ABI الخاص بك مطبوعًا في وحدة التحكم، انتقل إلى الطرفية (terminal) وقم بتشغيل:

npx hardhat run scripts/interact.js

إنشاء نسخة من عقدك

للتفاعل مع عقدنا، نحتاج إلى إنشاء نسخة من العقد في الكود الخاص بنا. للقيام بذلك باستخدام Ethers.js، سنحتاج إلى العمل مع ثلاثة مفاهيم:

  1. المزود (مزود) - مزود عقدة يمنحك حق الوصول للقراءة والكتابة على سلسلة الكتل
  2. المُوقّع (موقع) - يمثل حساب إيثيريوم يمكنه توقيع المعاملات
  3. العقد (Contract) - كائن Ethers.js يمثل عقدًا محددًا تم نشره على السلسلة

سنستخدم ABI الخاص بالعقد من الخطوة السابقة لإنشاء نسختنا من العقد:

تعرف على المزيد حول المزودين (Providers) والمُوقّعين (Signers) والعقود (Contracts) في وثائق ethers.js (opens in a new tab).

قراءة رسالة التهيئة (init)

هل تتذكر عندما قمنا بنشر عقدنا باستخدام initMessage = "Hello world!"؟ سنقوم الآن بقراءة تلك الرسالة المخزنة في عقدنا الذكي وطباعتها في وحدة التحكم.

في JavaScript، يتم استخدام الدوال غير المتزامنة (asynchronous functions) عند التفاعل مع الشبكات. لمعرفة المزيد حول الدوال غير المتزامنة، اقرأ هذا المقال على Medium (opens in a new tab).

استخدم الكود أدناه لاستدعاء دالة message في عقدنا الذكي وقراءة رسالة التهيئة:

بعد تشغيل الملف باستخدام npx hardhat run scripts/interact.js في الطرفية، يجب أن نرى هذه الاستجابة:

The message is: Hello world!

تهانينا! لقد نجحت للتو في قراءة بيانات العقد الذكي من سلسلة كتل إيثيريوم، عمل رائع!

تحديث الرسالة

بدلاً من مجرد قراءة الرسالة، يمكننا أيضًا تحديث الرسالة المحفوظة في عقدنا الذكي باستخدام دالة update! رائع جدًا، أليس كذلك؟

لتحديث الرسالة، يمكننا استدعاء دالة update مباشرة على كائن العقد (Contract) الذي أنشأناه:

لاحظ أنه في السطر 11، نقوم باستدعاء .wait() على كائن المعاملة المُرجع. يضمن هذا أن البرنامج النصي الخاص بنا ينتظر حتى يتم تعدين المعاملة على سلسلة الكتل قبل الخروج من الدالة. إذا لم يتم تضمين استدعاء .wait()، فقد لا يرى البرنامج النصي قيمة message المحدثة في العقد.

قراءة الرسالة الجديدة

يجب أن تكون قادرًا على تكرار الخطوة السابقة لقراءة قيمة message المحدثة. خذ لحظة وانظر ما إذا كان يمكنك إجراء التغييرات اللازمة لطباعة تلك القيمة الجديدة!

إذا كنت بحاجة إلى تلميح، فإليك كيف يجب أن يبدو ملف interact.js الخاص بك في هذه المرحلة:

الآن فقط قم بتشغيل البرنامج النصي ويجب أن تكون قادرًا على رؤية الرسالة القديمة، وحالة التحديث، والرسالة الجديدة مطبوعة في الطرفية الخاصة بك!

npx hardhat run scripts/interact.js --network goerli

The message is: Hello World!
Updating the message...
The new message is: This is the new message.

أثناء تشغيل هذا البرنامج النصي، قد تلاحظ أن خطوة Updating the message... تستغرق بعض الوقت للتحميل قبل تحميل الرسالة الجديدة. ويرجع ذلك إلى عملية التعدين؛ إذا كنت مهتمًا بتتبع المعاملات أثناء تعدينها، فقم بزيارة مجمع ذاكرة Alchemy (mempool) (opens in a new tab) لمعرفة حالة المعاملة. إذا تم إسقاط المعاملة، فمن المفيد أيضًا التحقق من Etherscan لشبكة غويرلي (opens in a new tab) والبحث عن تجزئة المعاملة الخاصة بك.

الجزء 3: نشر عقدك الذكي على Etherscan

لقد قمت بكل العمل الشاق لإحياء عقدك الذكي؛ حان الوقت الآن لمشاركته مع العالم!

من خلال التحقق من عقدك الذكي على Etherscan، يمكن لأي شخص عرض الكود المصدري الخاص بك والتفاعل مع عقدك الذكي. لنبدأ!

الخطوة 1: إنشاء مفتاح API على حساب Etherscan الخاص بك

يعد مفتاح API الخاص بـ Etherscan ضروريًا للتحقق من أنك تمتلك العقد الذكي الذي تحاول نشره.

إذا لم يكن لديك حساب Etherscan بالفعل، قم بالتسجيل للحصول على حساب (opens in a new tab).

بمجرد تسجيل الدخول، ابحث عن اسم المستخدم الخاص بك في شريط التنقل، ومرر الماوس فوقه وحدد زر My profile.

في صفحة ملفك الشخصي، يجب أن ترى شريط تنقل جانبي. من شريط التنقل الجانبي، حدد API Keys. بعد ذلك، اضغط على زر "Add" لإنشاء مفتاح API جديد، وقم بتسمية تطبيقك hello-world واضغط على زر Create New API Key.

يجب أن يظهر مفتاح API الجديد الخاص بك في جدول مفاتيح API. انسخ مفتاح API إلى الحافظة الخاصة بك.

بعد ذلك، نحتاج إلى إضافة مفتاح API الخاص بـ Etherscan إلى ملف .env الخاص بنا.

بعد إضافته، يجب أن يبدو ملف .env الخاص بك هكذا:

API_URL = "https://eth-goerli.alchemyapi.io/v2/your-api-key"
PUBLIC_KEY = "your-public-account-address"
PRIVATE_KEY = "your-private-account-address"
CONTRACT_ADDRESS = "your-contract-address"
ETHERSCAN_API_KEY = "your-etherscan-key"

العقود الذكية المنشورة باستخدام Hardhat

تثبيت hardhat-etherscan

يعد نشر عقدك على Etherscan باستخدام Hardhat أمرًا بسيطًا. ستحتاج أولاً إلى تثبيت المكون الإضافي hardhat-etherscan للبدء. سيقوم hardhat-etherscan تلقائيًا بالتحقق من الكود المصدري للعقد الذكي و ABI على Etherscan. لإضافة هذا، قم بتشغيل ما يلي في دليل hello-world:

npm install --save-dev @nomiclabs/hardhat-etherscan

بمجرد التثبيت، قم بتضمين العبارة التالية في الجزء العلوي من hardhat.config.js الخاص بك، وأضف خيارات تكوين Etherscan:

التحقق من عقدك الذكي على Etherscan

تأكد من حفظ جميع الملفات وتكوين جميع متغيرات .env بشكل صحيح.

قم بتشغيل مهمة verify، مع تمرير عنوان العقد، والشبكة التي تم نشره عليها:

npx hardhat verify --network goerli DEPLOYED_CONTRACT_ADDRESS 'Hello World!'

تأكد من أن DEPLOYED_CONTRACT_ADDRESS هو عنوان عقدك الذكي المنشور على شبكة اختبار غويرلي. أيضًا، يجب أن تكون الوسيطة الأخيرة ('Hello World!') هي نفس القيمة النصية المستخدمة أثناء خطوة النشر في الجزء 1.

إذا سارت الأمور على ما يرام، فسترى الرسالة التالية في الطرفية الخاصة بك:

Successfully submitted source code for contract
contracts/HelloWorld.sol:HelloWorld at 0xdeployed-contract-address
for verification on Etherscan. Waiting for verification result...


Successfully verified contract HelloWorld on Etherscan.
https://goerli.etherscan.io/address/<contract-address>#contracts

تهانينا! كود عقدك الذكي موجود الآن على Etherscan!

تحقق من عقدك الذكي على Etherscan!

عند الانتقال إلى الرابط المقدم في الطرفية الخاصة بك، يجب أن تكون قادرًا على رؤية كود عقدك الذكي و ABI المنشورين على Etherscan!

مرحى - لقد فعلتها يا بطل! الآن يمكن لأي شخص استدعاء عقدك الذكي أو الكتابة إليه! لا يسعنا الانتظار لرؤية ما ستبنيه بعد ذلك!

الجزء الرابع - دمج عقدك الذكي مع الواجهة الأمامية

بحلول نهاية هذا البرنامج التعليمي، ستعرف كيفية:

  • ربط محفظة ميتاماسك بتطبيقك اللامركزي (dapp)
  • قراءة البيانات من عقدك الذكي باستخدام API الخاص بـ Alchemy Web3 (opens in a new tab)
  • توقيع معاملات إيثيريوم باستخدام ميتاماسك

بالنسبة لهذا التطبيق اللامركزي (dapp)، سنستخدم React (opens in a new tab) كإطار عمل للواجهة الأمامية؛ ومع ذلك، من المهم ملاحظة أننا لن نقضي الكثير من الوقت في تفصيل أساسياته، حيث سنركز في الغالب على جلب وظائف Web3 إلى مشروعنا.

كمتطلب أساسي، يجب أن يكون لديك فهم بمستوى المبتدئين لـ React. إذا لم يكن الأمر كذلك، نوصي بإكمال البرنامج التعليمي الرسمي لمقدمة React (opens in a new tab).

استنساخ ملفات البداية

أولاً، انتقل إلى مستودع GitHub الخاص بـ hello-world-part-four (opens in a new tab) للحصول على ملفات البداية لهذا المشروع واستنساخ هذا المستودع إلى جهازك المحلي.

افتح المستودع المستنسخ محليًا. لاحظ أنه يحتوي على مجلدين: starter-files و completed.

  • starter-files- سنعمل في هذا الدليل، وسنقوم بربط واجهة المستخدم بمحفظة إيثيريوم الخاصة بك والعقد الذكي الذي نشرناه على Etherscan في الجزء الثالث.
  • completed يحتوي على البرنامج التعليمي المكتمل بالكامل ويجب استخدامه كمرجع فقط إذا واجهت صعوبة.

بعد ذلك، افتح نسختك من starter-files في محرر التعليمات البرمجية المفضل لديك، ثم انتقل إلى مجلد src.

ستكون جميع التعليمات البرمجية التي سنكتبها موجودة ضمن مجلد src. سنقوم بتعديل مكون HelloWorld.js وملفات JavaScript util/interact.js لمنح مشروعنا وظائف Web3.

التحقق من ملفات البداية

قبل أن نبدأ في كتابة التعليمات البرمجية، دعنا نستكشف ما تم توفيره لنا في ملفات البداية.

تشغيل مشروع React الخاص بك

دعنا نبدأ بتشغيل مشروع React في متصفحنا. جمال React هو أنه بمجرد تشغيل مشروعنا في متصفحنا، سيتم تحديث أي تغييرات نحفظها مباشرة في متصفحنا.

لتشغيل المشروع، انتقل إلى الدليل الجذر لمجلد starter-files، وقم بتشغيل npm install في جهازك الطرفي لتثبيت تبعيات المشروع:

cd starter-files
npm install

بمجرد الانتهاء من التثبيت، قم بتشغيل npm start في جهازك الطرفي:

npm start

القيام بذلك يجب أن يفتح http://localhost:3000/ (opens in a new tab) في متصفحك، حيث سترى الواجهة الأمامية لمشروعنا. يجب أن تتكون من حقل واحد (مكان لتحديث الرسالة المخزنة في عقدك الذكي)، وزر "Connect Wallet" (ربط المحفظة)، وزر "Update" (تحديث).

إذا حاولت النقر على أي من الزرين، ستلاحظ أنهما لا يعملان—وذلك لأننا لا نزال بحاجة إلى برمجة وظائفهما.

مكون HelloWorld.js

دعنا نعود إلى مجلد src في محررنا ونفتح ملف HelloWorld.js. من المهم جدًا أن نفهم كل شيء في هذا الملف، لأنه مكون React الأساسي الذي سنعمل عليه.

في الجزء العلوي من هذا الملف، ستلاحظ أن لدينا العديد من عبارات الاستيراد الضرورية لتشغيل مشروعنا، بما في ذلك مكتبة React، وخطافات useEffect و useState، وبعض العناصر من ./util/interact.js (سنصفها بمزيد من التفصيل قريبًا!)، وشعار Alchemy.

بعد ذلك، لدينا متغيرات الحالة الخاصة بنا والتي سنقوم بتحديثها بعد أحداث معينة.

// HelloWorld.js

//متغيرات الحالة
const [walletAddress, setWallet] = useState("")
const [status, setStatus] = useState("")
const [message, setMessage] = useState("No connection to the network.")
const [newMessage, setNewMessage] = useState("")

إليك ما يمثله كل من المتغيرات:

  • walletAddress - سلسلة نصية تخزن عنوان محفظة المستخدم
  • status- سلسلة نصية تخزن رسالة مفيدة ترشد المستخدم حول كيفية التفاعل مع التطبيق اللامركزي (dapp)
  • message - سلسلة نصية تخزن الرسالة الحالية في العقد الذكي
  • newMessage - سلسلة نصية تخزن الرسالة الجديدة التي ستتم كتابتها في العقد الذكي

بعد متغيرات الحالة، سترى خمس دوال غير منفذة: useEffect، و addSmartContractListener، و addWalletListener، و connectWalletPressed، و onUpdatePressed. سنشرح ما تفعله أدناه:

  • useEffect (opens in a new tab)- هذا خطاف React يتم استدعاؤه بعد تصيير المكون الخاص بك. نظرًا لأنه يحتوي على مصفوفة فارغة [] تم تمريرها إليه (انظر السطر 4)، فسيتم استدعاؤه فقط في التصيير الأول للمكون. هنا سنقوم بتحميل الرسالة الحالية المخزنة في عقدنا الذكي، واستدعاء مستمعي العقد الذكي والمحفظة، وتحديث واجهة المستخدم الخاصة بنا لتعكس ما إذا كانت المحفظة متصلة بالفعل.
  • addSmartContractListener- تقوم هذه الدالة بإعداد مستمع سيراقب حدث UpdatedMessages الخاص بعقد HelloWorld وتحديث واجهة المستخدم الخاصة بنا عند تغيير الرسالة في عقدنا الذكي.
  • addWalletListener- تقوم هذه الدالة بإعداد مستمع يكتشف التغييرات في حالة محفظة ميتاماسك الخاصة بالمستخدم، مثل عندما يقوم المستخدم بقطع اتصال محفظته أو تبديل العناوين.
  • connectWalletPressed- سيتم استدعاء هذه الدالة لربط محفظة ميتاماسك الخاصة بالمستخدم بتطبيقنا اللامركزي (dapp).
  • onUpdatePressed - سيتم استدعاء هذه الدالة عندما يريد المستخدم تحديث الرسالة المخزنة في العقد الذكي.

بالقرب من نهاية هذا الملف، لدينا واجهة المستخدم الخاصة بمكوننا.

إذا قمت بفحص هذه التعليمات البرمجية بعناية، ستلاحظ أين نستخدم متغيرات الحالة المختلفة في واجهة المستخدم الخاصة بنا:

  • في الأسطر 6-12، إذا كانت محفظة المستخدم متصلة (أي walletAddress.length > 0)، فإننا نعرض نسخة مقتطعة من walletAddress الخاص بالمستخدم في الزر الذي يحمل المعرف "walletButton"؛ وإلا فإنه يقول ببساطة "Connect Wallet".
  • في السطر 17، نعرض الرسالة الحالية المخزنة في العقد الذكي، والتي يتم التقاطها في السلسلة النصية message.
  • في الأسطر 23-26، نستخدم مكونًا متحكمًا به (opens in a new tab) لتحديث متغير الحالة newMessage الخاص بنا عندما يتغير الإدخال في حقل النص.

بالإضافة إلى متغيرات الحالة الخاصة بنا، سترى أيضًا أنه يتم استدعاء دالتي connectWalletPressed و onUpdatePressed عند النقر فوق الأزرار التي تحمل المعرفات publishButton و walletButton على التوالي.

أخيرًا، دعنا نتناول أين تمت إضافة مكون HelloWorld.js هذا.

إذا ذهبت إلى ملف App.js، وهو المكون الرئيسي في React الذي يعمل كحاوية لجميع المكونات الأخرى، سترى أن مكون HelloWorld.js الخاص بنا يتم حقنه في السطر 7.

أخيرًا وليس آخرًا، دعنا نتحقق من ملف آخر تم توفيره لك، وهو ملف interact.js.

ملف interact.js

نظرًا لأننا نريد الالتزام بنموذج M-V-C (opens in a new tab)، سنحتاج إلى ملف منفصل يحتوي على جميع دوالنا لإدارة المنطق والبيانات والقواعد الخاصة بتطبيقنا اللامركزي (dapp)، ثم نتمكن من تصدير تلك الدوال إلى واجهتنا الأمامية (مكون HelloWorld.js الخاص بنا).

👆🏽هذا هو الغرض الدقيق لملف interact.js الخاص بنا!

انتقل إلى مجلد util في دليل src الخاص بك، وستلاحظ أننا قمنا بتضمين ملف يسمى interact.js والذي سيحتوي على جميع دوال ومتغيرات التفاعل مع العقد الذكي والمحفظة.

ستلاحظ في الجزء العلوي من الملف أننا قمنا بتعليق كائن helloWorldContract. لاحقًا في هذا البرنامج التعليمي، سنقوم بإلغاء تعليق هذا الكائن وإنشاء مثيل لعقدنا الذكي في هذا المتغير، والذي سنقوم بعد ذلك بتصديره إلى مكون HelloWorld.js الخاص بنا.

تقوم الدوال الأربع غير المنفذة بعد كائن helloWorldContract الخاص بنا بما يلي:

  • loadCurrentMessage - تتعامل هذه الدالة مع منطق تحميل الرسالة الحالية المخزنة في العقد الذكي. ستقوم بإجراء استدعاء قراءة لعقد Hello World الذكي باستخدام API الخاص بـ Alchemy Web3 (opens in a new tab).
  • connectWallet - ستقوم هذه الدالة بربط ميتاماسك الخاص بالمستخدم بتطبيقنا اللامركزي (dapp).
  • getCurrentWalletConnected - ستقوم هذه الدالة بالتحقق مما إذا كان حساب إيثيريوم متصلاً بالفعل بتطبيقنا اللامركزي (dapp) عند تحميل الصفحة وتحديث واجهة المستخدم الخاصة بنا وفقًا لذلك.
  • updateMessage - ستقوم هذه الدالة بتحديث الرسالة المخزنة في العقد الذكي. ستقوم بإجراء استدعاء كتابة لعقد Hello World الذكي، لذلك سيتعين على محفظة ميتاماسك الخاصة بالمستخدم توقيع معاملة إيثيريوم لتحديث الرسالة.

الآن بعد أن فهمنا ما نعمل عليه، دعنا نكتشف كيفية القراءة من عقدنا الذكي!

الخطوة 3: القراءة من عقدك الذكي

للقراءة من عقدك الذكي، ستحتاج إلى إعداد ما يلي بنجاح:

  • اتصال API بسلسلة إيثيريوم
  • مثيل محمل لعقدك الذكي
  • دالة لاستدعاء دالة عقدك الذكي
  • مستمع لمراقبة التحديثات عندما تتغير البيانات التي تقرأها من العقد الذكي

قد يبدو هذا كالكثير من الخطوات، لكن لا تقلق! سنرشدك خلال كيفية القيام بكل منها خطوة بخطوة! :)

إنشاء اتصال API بسلسلة إيثيريوم

هل تتذكر كيف استخدمنا في الجزء الثاني من هذا البرنامج التعليمي مفتاح Alchemy Web3 الخاص بنا للقراءة من عقدنا الذكي؟ ستحتاج أيضًا إلى مفتاح Alchemy Web3 في تطبيقك اللامركزي (dapp) للقراءة من السلسلة.

إذا لم يكن لديك بالفعل، فقم أولاً بتثبيت Alchemy Web3 (opens in a new tab) عن طريق الانتقال إلى الدليل الجذر لـ starter-files وتشغيل ما يلي في الطرفية الخاصة بك:

npm install @alch/alchemy-web3

إن Alchemy Web3 (opens in a new tab) هو غلاف حول Web3.js (opens in a new tab)، يوفر طرق API محسنة وفوائد حاسمة أخرى لجعل حياتك كمطور Web3 أسهل. تم تصميمه ليتطلب الحد الأدنى من التكوين حتى تتمكن من البدء في استخدامه في تطبيقك على الفور!

بعد ذلك، قم بتثبيت حزمة dotenv (opens in a new tab) في دليل مشروعك، حتى يكون لدينا مكان آمن لتخزين مفتاح API الخاص بنا بعد جلبه.

npm install dotenv --save

بالنسبة لتطبيقنا اللامركزي (dapp)، سنستخدم مفتاح Websockets API الخاص بنا بدلاً من مفتاح HTTP API الخاص بنا، حيث سيسمح لنا بإعداد مستمع يكتشف متى تتغير الرسالة المخزنة في العقد الذكي.

بمجرد حصولك على مفتاح API الخاص بك، أنشئ ملف .env في الدليل الجذر الخاص بك وأضف عنوان URL الخاص بـ Alchemy Websockets إليه. بعد ذلك، يجب أن يبدو ملف .env الخاص بك هكذا:

REACT_APP_ALCHEMY_KEY = wss://eth-goerli.ws.alchemyapi.io/v2/<key>

الآن، نحن مستعدون لإعداد نقطة نهاية Alchemy Web3 في تطبيقنا اللامركزي (dapp)! دعنا نعود إلى interact.js الخاص بنا، والموجود داخل مجلد util ونضيف الكود التالي في أعلى الملف:

// interact.js

require("dotenv").config()
const alchemyKey = process.env.REACT_APP_ALCHEMY_KEY
const { createAlchemyWeb3 } = require("@alch/alchemy-web3")
const web3 = createAlchemyWeb3(alchemyKey)

//export const helloWorldContract;

أعلاه، قمنا أولاً باستيراد مفتاح Alchemy من ملف .env الخاص بنا ثم مررنا alchemyKey الخاص بنا إلى createAlchemyWeb3 لإنشاء نقطة نهاية Alchemy Web3 الخاصة بنا.

مع جاهزية نقطة النهاية هذه، حان الوقت لتحميل عقدنا الذكي!

تحميل عقد Hello World الذكي الخاص بك

لتحميل عقد Hello World الذكي الخاص بك، ستحتاج إلى عنوان العقد و ABI الخاص به، وكلاهما يمكن العثور عليهما على Etherscan إذا أكملت الجزء الثالث من هذا البرنامج التعليمي.

كيفية الحصول على ABI الخاص بعقدك من Etherscan

إذا تخطيت الجزء الثالث من هذا البرنامج التعليمي، يمكنك استخدام عقد HelloWorld بالعنوان 0x6f3f635A9762B47954229Ea479b4541eAF402A6A (opens in a new tab). يمكن العثور على ABI الخاص به هنا (opens in a new tab).

يعد ABI الخاص بالعقد ضروريًا لتحديد الدالة التي سيستدعيها العقد بالإضافة إلى ضمان أن الدالة ستعيد البيانات بالتنسيق الذي تتوقعه. بمجرد نسخ ABI الخاص بعقدنا، دعنا نحفظه كملف JSON يسمى contract-abi.json في دليل src الخاص بك.

يجب تخزين contract-abi.json الخاص بك في مجلد src الخاص بك.

مسلحين بعنوان عقدنا، و ABI، ونقطة نهاية Alchemy Web3، يمكننا استخدام طريقة العقد (opens in a new tab) لتحميل مثيل لعقدنا الذكي. قم باستيراد ABI الخاص بعقدك إلى ملف interact.js وأضف عنوان عقدك.

// interact.js

const contractABI = require("../contract-abi.json")
const contractAddress = "0x6f3f635A9762B47954229Ea479b4541eAF402A6A"

يمكننا الآن أخيرًا إلغاء تعليق متغير helloWorldContract الخاص بنا، وتحميل العقد الذكي باستخدام نقطة نهاية AlchemyWeb3 الخاصة بنا:

// interact.js
export const helloWorldContract = new web3.eth.Contract(
  contractABI,
  contractAddress
)

للتلخيص، يجب أن تبدو الأسطر الـ 12 الأولى من interact.js الخاص بك الآن هكذا:

الآن بعد أن قمنا بتحميل عقدنا، يمكننا تنفيذ دالة loadCurrentMessage الخاصة بنا!

تنفيذ loadCurrentMessage في ملف interact.js الخاص بك

هذه الدالة بسيطة للغاية. سنقوم بإجراء استدعاء web3 غير متزامن بسيط للقراءة من عقدنا. ستعيد دالتنا الرسالة المخزنة في العقد الذكي:

قم بتحديث loadCurrentMessage في ملف interact.js الخاص بك إلى ما يلي:

// interact.js

export const loadCurrentMessage = async () => {
  const message = await helloWorldContract.methods.message().call()
  return message
}

نظرًا لأننا نريد عرض هذا العقد الذكي في واجهة المستخدم الخاصة بنا، دعنا نحدث دالة useEffect في مكون HelloWorld.js الخاص بنا إلى ما يلي:

// HelloWorld.js

//يُستدعى مرة واحدة فقط
useEffect(async () => {
  const message = await loadCurrentMessage()
  setMessage(message)
}, [])

ملاحظة، نريد فقط استدعاء loadCurrentMessage الخاص بنا مرة واحدة أثناء التصيير الأول للمكون. سنقوم قريبًا بتنفيذ addSmartContractListener لتحديث واجهة المستخدم تلقائيًا بعد تغير الرسالة في العقد الذكي.

قبل أن نتعمق في المستمع الخاص بنا، دعنا نتحقق مما لدينا حتى الآن! احفظ ملفي HelloWorld.js و interact.js، ثم انتقل إلى http://localhost:3000/ (opens in a new tab)

ستلاحظ أن الرسالة الحالية لم تعد تقول "لا يوجد اتصال بالشبكة". بدلاً من ذلك، تعكس الرسالة المخزنة في العقد الذكي. رائع!

يجب أن تعكس واجهة المستخدم الخاصة بك الآن الرسالة المخزنة في العقد الذكي

الآن بالحديث عن ذلك المستمع...

تنفيذ addSmartContractListener

إذا تذكرت ملف HelloWorld.sol الذي كتبناه في الجزء الأول من سلسلة البرامج التعليمية هذه، ستتذكر أن هناك حدث عقد ذكي يسمى UpdatedMessages يتم إصداره بعد استدعاء دالة update الخاصة بعقدنا الذكي (انظر الأسطر 9 و 27):

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

ستستمع دالة addSmartContractListener بشكل خاص لحدث UpdatedMessages الخاص بعقد Hello World الذكي، وتحدث واجهة المستخدم الخاصة بنا لعرض الرسالة الجديدة.

قم بتعديل addSmartContractListener إلى ما يلي:

دعنا نفصل ما يحدث عندما يكتشف المستمع حدثًا:

  • إذا حدث خطأ عند إصدار الحدث، فسينعكس ذلك في واجهة المستخدم عبر متغير الحالة status الخاص بنا.
  • بخلاف ذلك، سنستخدم كائن data المُعاد. data.returnValues عبارة عن مصفوفة مفهرسة عند الصفر حيث يخزن العنصر الأول في المصفوفة الرسالة السابقة ويخزن العنصر الثاني الرسالة المحدثة. إجمالاً، عند نجاح الحدث، سنقوم بتعيين السلسلة النصية message الخاصة بنا إلى الرسالة المحدثة، ومسح السلسلة النصية newMessage، وتحديث متغير الحالة status الخاص بنا ليعكس أنه تم نشر رسالة جديدة على عقدنا الذكي.

أخيرًا، دعنا نستدعي المستمع الخاص بنا في دالة useEffect الخاصة بنا بحيث يتم تهيئته في التصيير الأول لمكون HelloWorld.js. إجمالاً، يجب أن تبدو دالة useEffect الخاصة بك هكذا:

// HelloWorld.js

useEffect(async () => {
  const message = await loadCurrentMessage()
  setMessage(message)
  addSmartContractListener()
}, [])

الآن بعد أن أصبحنا قادرين على القراءة من عقدنا الذكي، سيكون من الرائع معرفة كيفية الكتابة إليه أيضًا! ومع ذلك، للكتابة إلى تطبيقنا اللامركزي (dapp)، يجب أن يكون لدينا أولاً محفظة إيثيريوم متصلة به.

لذا، سنتناول بعد ذلك إعداد محفظة إيثيريوم الخاصة بنا (ميتاماسك) ثم ربطها بتطبيقنا اللامركزي (dapp)!

الخطوة 4: إعداد محفظة إيثيريوم الخاصة بك

لكتابة أي شيء إلى سلسلة إيثيريوم، يجب على المستخدمين توقيع المعاملات باستخدام المفاتيح الخاصة لمحفظتهم الافتراضية. في هذا البرنامج التعليمي، سنستخدم ميتاماسك (opens in a new tab)، وهي محفظة افتراضية في المتصفح تُستخدم لإدارة عنوان حساب إيثيريوم الخاص بك، حيث تجعل توقيع المعاملة هذا سهلاً للغاية للمستخدم النهائي.

إذا كنت ترغب في فهم المزيد حول كيفية عمل المعاملات على إيثيريوم، فتحقق من هذه الصفحة من مؤسسة إيثيريوم.

تنزيل ميتاماسك

يمكنك تنزيل وإنشاء حساب ميتاماسك مجانًا هنا (opens in a new tab). عند إنشاء حساب، أو إذا كان لديك حساب بالفعل، تأكد من التبديل إلى "شبكة اختبار غويرلي" في أعلى اليمين (حتى لا نتعامل بأموال حقيقية).

إضافة إيثر من صنبور

لتوقيع معاملة على سلسلة كتل إيثيريوم، سنحتاج إلى بعض ETH الوهمي. للحصول على ETH، يمكنك الذهاب إلى FaucETH (opens in a new tab) وإدخال عنوان حساب غويرلي الخاص بك، والنقر على "Request funds" (طلب أموال)، ثم تحديد "Ethereum Testnet Goerli" في القائمة المنسدلة وأخيرًا النقر على زر "Request funds" مرة أخرى. يجب أن ترى ETH في حساب ميتاماسك الخاص بك بعد فترة وجيزة!

التحقق من رصيدك

للتأكد من وجود رصيدنا، دعنا نُجري طلب eth_getBalance (opens in a new tab) باستخدام أداة وضع الحماية الخاصة بـ Alchemy (opens in a new tab). سيؤدي هذا إلى إرجاع مقدار ETH في محفظتنا. بعد إدخال عنوان حساب ميتاماسك الخاص بك والنقر على "Send Request" (إرسال الطلب)، يجب أن ترى استجابة مثل هذه:

{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}

ملاحظة: هذه النتيجة بوحدة wei وليس ETH. تُستخدم wei كأصغر فئة من إيثر. التحويل من wei إلى ETH هو: 1 ETH = 10¹⁸ wei. لذا إذا قمنا بتحويل 0xde0b6b3a7640000 إلى النظام العشري، فسنحصل على 1*10¹⁸ والذي يساوي 1 ETH.

رائع! أموالنا الوهمية كلها موجودة! 🤑

الخطوة 5: ربط ميتاماسك بواجهة المستخدم الخاصة بك

الآن بعد إعداد محفظة ميتاماسك الخاصة بنا، دعنا نربط تطبيقنا اللامركزي (dapp) بها!

دالة connectWallet

في ملف interact.js الخاص بنا، دعنا ننفذ دالة connectWallet، والتي يمكننا بعد ذلك استدعاؤها في مكون HelloWorld.js الخاص بنا.

دعنا نعدل connectWallet إلى ما يلي:

إذن ماذا تفعل هذه الكتلة العملاقة من التعليمات البرمجية بالضبط؟

حسنًا، أولاً، تتحقق مما إذا كان window.ethereum ممكّنًا في متصفحك.

window.ethereum هو API عالمي يتم حقنه بواسطة ميتاماسك وموفري المحافظ الآخرين والذي يسمح لمواقع الويب بطلب حسابات إيثيريوم الخاصة بالمستخدمين. إذا تمت الموافقة عليه، يمكنه قراءة البيانات من سلاسل الكتل التي يتصل بها المستخدم، واقتراح أن يقوم المستخدم بتوقيع الرسائل والمعاملات. تحقق من مستندات ميتاماسك (opens in a new tab) لمزيد من المعلومات!

إذا كان window.ethereum غير موجود، فهذا يعني أن ميتاماسك غير مثبت. ينتج عن هذا إرجاع كائن JSON، حيث يكون address المُعاد عبارة عن سلسلة نصية فارغة، وينقل كائن JSX status أنه يجب على المستخدم تثبيت ميتاماسك.

الآن إذا كان window.ethereum موجودًا، فهذا هو الوقت الذي تصبح فيه الأمور مثيرة للاهتمام.

باستخدام حلقة try/catch، سنحاول الاتصال بميتاماسك عن طريق استدعاء window.ethereum.request({ method: "eth_requestAccounts" }); (opens in a new tab). سيؤدي استدعاء هذه الدالة إلى فتح ميتاماسك في المتصفح، حيث سيُطلب من المستخدم ربط محفظته بتطبيقك اللامركزي (dapp).

  • إذا اختار المستخدم الاتصال، سيعيد method: "eth_requestAccounts" مصفوفة تحتوي على جميع عناوين حساب المستخدم التي اتصلت بالتطبيق اللامركزي (dapp). إجمالاً، ستعيد دالة connectWallet الخاصة بنا كائن JSON يحتوي على أول address في هذه المصفوفة (انظر السطر 9) ورسالة status تطالب المستخدم بكتابة رسالة إلى العقد الذكي.
  • إذا رفض المستخدم الاتصال، فسيحتوي كائن JSON على سلسلة نصية فارغة لـ address المُعاد ورسالة status تعكس أن المستخدم رفض الاتصال.

الآن بعد أن كتبنا دالة connectWallet هذه، الخطوة التالية هي استدعاؤها في مكون HelloWorld.js الخاص بنا.

إضافة دالة connectWallet إلى مكون واجهة المستخدم HelloWorld.js الخاص بك

انتقل إلى دالة connectWalletPressed في HelloWorld.js، وقم بتحديثها إلى ما يلي:

// HelloWorld.js

const connectWalletPressed = async () => {
  const walletResponse = await connectWallet()
  setStatus(walletResponse.status)
  setWallet(walletResponse.address)
}

هل تلاحظ كيف يتم تجريد معظم وظائفنا بعيدًا عن مكون HelloWorld.js الخاص بنا من ملف interact.js؟ هذا لكي نمتثل لنموذج M-V-C!

في connectWalletPressed، نقوم ببساطة بإجراء استدعاء await لدالة connectWallet المستوردة الخاصة بنا، وباستخدام استجابتها، نقوم بتحديث متغيري status و walletAddress عبر خطافات الحالة الخاصة بهما.

الآن، دعنا نحفظ كلا الملفين (HelloWorld.js و interact.js) ونختبر واجهة المستخدم الخاصة بنا حتى الآن.

افتح متصفحك على صفحة http://localhost:3000/ (opens in a new tab)، واضغط على زر "Connect Wallet" (ربط المحفظة) في أعلى يمين الصفحة.

إذا كان لديك ميتاماسك مثبتًا، فسيُطلب منك ربط محفظتك بتطبيقك اللامركزي (dapp). اقبل الدعوة للاتصال.

يجب أن ترى أن زر المحفظة يعكس الآن أن عنوانك متصل! نعم 🔥

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

ومع ذلك، لا تخف! يمكننا بسهولة معالجة ذلك من خلال تنفيذ getCurrentWalletConnected، والذي سيتحقق مما إذا كان العنوان متصلاً بالفعل بتطبيقنا اللامركزي (dapp) وتحديث واجهة المستخدم الخاصة بنا وفقًا لذلك!

دالة getCurrentWalletConnected

قم بتحديث دالة getCurrentWalletConnected الخاصة بك في ملف interact.js إلى ما يلي:

هذه التعليمات البرمجية مشابهة جدًا لدالة connectWallet التي كتبناها للتو في الخطوة السابقة.

الفرق الرئيسي هو أنه بدلاً من استدعاء طريقة eth_requestAccounts، والتي تفتح ميتاماسك للمستخدم لربط محفظته، هنا نستدعي طريقة eth_accounts، والتي تعيد ببساطة مصفوفة تحتوي على عناوين ميتاماسك المتصلة حاليًا بتطبيقنا اللامركزي (dapp).

لرؤية هذه الدالة قيد العمل، دعنا نستدعيها في دالة useEffect الخاصة بمكون HelloWorld.js الخاص بنا:

لاحظ، نستخدم استجابة استدعائنا لـ getCurrentWalletConnected لتحديث متغيري الحالة walletAddress و status الخاصين بنا.

الآن بعد أن أضفت هذه التعليمات البرمجية، دعنا نحاول تحديث نافذة المتصفح الخاصة بنا.

رائع! يجب أن يقول الزر أنك متصل، ويعرض معاينة لعنوان محفظتك المتصلة - حتى بعد التحديث!

تنفيذ addWalletListener

الخطوة الأخيرة في إعداد محفظة التطبيق اللامركزي (dapp) الخاص بنا هي تنفيذ مستمع المحفظة بحيث يتم تحديث واجهة المستخدم الخاصة بنا عندما تتغير حالة محفظتنا، مثل عندما يقوم المستخدم بقطع الاتصال أو تبديل الحسابات.

في ملف HelloWorld.js الخاص بك، قم بتعديل دالة addWalletListener الخاصة بك على النحو التالي:

أراهن أنك لا تحتاج حتى إلى مساعدتنا لفهم ما يجري هنا في هذه المرحلة، ولكن لأغراض الشمولية، دعنا نفصله بسرعة:

  • أولاً، تتحقق دالتنا مما إذا كان window.ethereum ممكّنًا (أي أن ميتاماسك مثبت).
    • إذا لم يكن كذلك، فإننا ببساطة نعيّن متغير الحالة status الخاص بنا إلى سلسلة JSX تطالب المستخدم بتثبيت ميتاماسك.
    • إذا كان ممكّنًا، فإننا نعد المستمع window.ethereum.on("accountsChanged") في السطر 3 والذي يستمع لتغييرات الحالة في محفظة ميتاماسك، والتي تشمل عندما يقوم المستخدم بربط حساب إضافي بالتطبيق اللامركزي (dapp)، أو تبديل الحسابات، أو قطع اتصال حساب. إذا كان هناك حساب واحد على الأقل متصلاً، يتم تحديث متغير الحالة walletAddress كأول حساب في مصفوفة accounts المعادة بواسطة المستمع. بخلاف ذلك، يتم تعيين walletAddress كسلسلة نصية فارغة.

أخيرًا وليس آخرًا، يجب أن نستدعيها في دالة useEffect الخاصة بنا:

وهذا كل شيء! لقد أكملنا بنجاح برمجة جميع وظائف محفظتنا! الآن إلى مهمتنا الأخيرة: تحديث الرسالة المخزنة في عقدنا الذكي!

الخطوة 6: تنفيذ دالة updateMessage

حسنًا يا رفاق، لقد وصلنا إلى المرحلة الأخيرة! في updateMessage من ملف interact.js الخاص بك، سنقوم بما يلي:

  1. التأكد من أن الرسالة التي نرغب في نشرها في عقدنا الذكي صالحة
  2. توقيع معاملتنا باستخدام ميتاماسك
  3. استدعاء هذه الدالة من مكون الواجهة الأمامية HelloWorld.js الخاص بنا

لن يستغرق هذا وقتًا طويلاً؛ دعنا ننهي هذا التطبيق اللامركزي (dapp)!

معالجة أخطاء الإدخال

بطبيعة الحال، من المنطقي أن يكون هناك نوع من معالجة أخطاء الإدخال في بداية الدالة.

سنريد أن تعود دالتنا مبكرًا إذا لم يكن هناك امتداد ميتاماسك مثبتًا، أو لم تكن هناك محفظة متصلة (أي أن address الممرر عبارة عن سلسلة نصية فارغة)، أو أن message عبارة عن سلسلة نصية فارغة. دعنا نضيف معالجة الأخطاء التالية إلى updateMessage:

الآن بعد أن أصبح لديها معالجة مناسبة لأخطاء الإدخال، حان الوقت لتوقيع المعاملة عبر ميتاماسك!

توقيع معاملتنا

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

دعنا نفصل ما يحدث. أولاً، نقوم بإعداد معلمات معاملاتنا، حيث:

  • يحدد to عنوان المستلم (عقدنا الذكي)
  • يحدد from موقع المعاملة، وهو متغير address الذي مررناه إلى دالتنا
  • يحتوي data على استدعاء لطريقة update الخاصة بعقد Hello World الذكي، ويتلقى متغير السلسلة النصية message الخاص بنا كإدخال

بعد ذلك، نقوم بإجراء استدعاء await، window.ethereum.request، حيث نطلب من ميتاماسك توقيع المعاملة. لاحظ، في الأسطر 11 و 12، أننا نحدد طريقة eth الخاصة بنا، eth_sendTransaction ونمرر transactionParameters الخاص بنا.

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

  • إذا نجحت المعاملة، ستعيد الدالة كائن JSON حيث تطالب سلسلة JSX status المستخدم بالتحقق من Etherscan لمزيد من المعلومات حول معاملته.
  • إذا فشلت المعاملة، ستعيد الدالة كائن JSON حيث تنقل السلسلة النصية status رسالة الخطأ.

إجمالاً، يجب أن تبدو دالة updateMessage الخاصة بنا هكذا:

أخيرًا وليس آخرًا، نحتاج إلى ربط دالة updateMessage الخاصة بنا بمكون HelloWorld.js الخاص بنا.

ربط updateMessage بالواجهة الأمامية HelloWorld.js

يجب أن تقوم دالة onUpdatePressed الخاصة بنا بإجراء استدعاء await لدالة updateMessage المستوردة وتعديل متغير الحالة status ليعكس ما إذا كانت معاملتنا قد نجحت أم فشلت:

// HelloWorld.js

const onUpdatePressed = async () => {
  const { status } = await updateMessage(walletAddress, newMessage)
  setStatus(status)
}

إنها نظيفة وبسيطة للغاية. وخمن ماذا... تطبيقك اللامركزي (dapp) مكتمل!!!

انطلق واختبر زر Update (تحديث)!

اصنع تطبيقك اللامركزي (dapp) المخصص

رائع، لقد وصلت إلى نهاية البرنامج التعليمي! للتلخيص، لقد تعلمت كيفية:

  • ربط محفظة ميتاماسك بمشروع تطبيقك اللامركزي (dapp)
  • قراءة البيانات من عقدك الذكي باستخدام API الخاص بـ Alchemy Web3 (opens in a new tab)
  • توقيع معاملات إيثيريوم باستخدام ميتاماسك

الآن أنت مجهز بالكامل لتطبيق المهارات من هذا البرنامج التعليمي لبناء مشروع تطبيقك اللامركزي (dapp) المخصص! كما هو الحال دائمًا، إذا كان لديك أي أسئلة، فلا تتردد في التواصل معنا للحصول على المساعدة في ديسكورد Alchemy (opens in a new tab). 🧙‍♂️

بمجرد إكمال هذا البرنامج التعليمي، أخبرنا كيف كانت تجربتك أو إذا كان لديك أي ملاحظات عن طريق الإشارة إلينا على تويتر @alchemyplatform (opens in a new tab)!