إعداد واجهة React.js وتثبيت مكتبة Ethers.js للاتصال بالبلوكتشين

دقائق القراءة: 7

إعداد واجهة React.js وتثبيت مكتبة Ethers.js للاتصال بالبلوكتشين

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

إذا كنت قد اطلعت سابقاً على مقال هندسة الويب اللامركزي (Web3.js & Ethers.js): كيف نربط الواجهات بالعقود الذكية؟ فهذه المرحلة تمثل التطبيق العملي المباشر لذلك المفهوم. كما أن نجاح التجربة يعتمد غالباً على ضبط المحفظة مسبقاً، ولهذا يُنصح بالرجوع إلى إعداد بيئة التطوير: تثبيت محفظة MetaMask والاتصال بشبكات الاختبار (Testnets) قبل بدء الربط الفعلي.

لماذا نستخدم React.js مع Ethers.js؟

الدمج بين React.js وEthers.js شائع لأن الأول يدير حالة الواجهة بكفاءة، والثاني يبسّط التفاعل مع بيئة Ethereum وشبكات متوافقة مع EVM. بهذه البنية، يمكن فصل منطق العرض عن منطق الاتصال بالشبكة، وهو أمر مهم جداً عند تطوير DApps احترافية.

وتزداد أهمية هذا الأسلوب عندما تبدأ بقراءة بيانات العقود أو تنفيذ معاملات تتطلب توقيع المستخدم. فبدلاً من الاعتماد على استدعاءات منخفضة المستوى، تقدم Ethers.js واجهات واضحة لإنشاء Provider وSigner وربطهما بالعقد الذكي باستخدام ABI.

المتطلبات الأساسية قبل إنشاء الواجهة

قبل البدء عملياً، تأكد من توفر بيئة تطوير حديثة قائمة على Node.js وnpm. وإذا كنت تتبع مساراً احترافياً في تطوير العقود، فسيكون من المفيد جداً أن تكون قد أعددت مشروعك عبر الانتقال إلى بيئة العمل الاحترافية: تثبيت إطار عمل Hardhat باستخدام Node.js.

إنشاء مشروع React جديد

يمكنك إنشاء الواجهة باستخدام Vite أو Create React App، لكن Vite أسرع في التطوير المحلي وأخف في الإعداد الأولي. الخطوات الأساسية تكون كالتالي:

  1. إنشاء المشروع.
  2. الدخول إلى مجلد العمل.
  3. تثبيت الحزم المطلوبة.
  4. تشغيل خادم التطوير المحلي.
# create project
npm create vite@latest my-web3-app -- --template react

# enter project
cd my-web3-app

# install dependencies
npm install

# install ethers
npm install ethers

# run development server
npm run dev

رغم أن الأوامر السابقة ليست شيفرة Solidity، إلا أن وضعها في كتلة منسقة يفيد في ووردبريس ويحافظ على وضوح تسلسل التنفيذ. بعد ذلك يصبح لديك مشروع واجهة جاهز لتوصيل المحفظة وقراءة بيانات السلسلة.

تثبيت مكتبة Ethers.js وفهم دورها

تثبيت المكتبة يتم عبر npm install ethers، لكن القيمة الحقيقية تبدأ عند فهم مكوّناتها. فمفهوم Provider مسؤول عن قراءة البيانات من الشبكة، مثل رقم الكتلة أو حالة العقد، بينما يمثل Signer الحساب القادر على توقيع المعاملات.

وعند بناء كائن Contract، فأنت فعلياً تترجم واجهة العقد الذكي إلى كائن قابل للاستدعاء من الواجهة. وهنا تظهر أهمية فهم الأحداث (Events): كيف يخبر العقد الذكي واجهة الموقع (React) بأن شيئاً ما قد حدث؟ لأن الواجهة الحديثة لا تكتفي بإرسال معاملة، بل تراقب أيضاً نتائجها وتحديثاتها اللاحقة.

الربط بمحفظة المستخدم داخل الواجهة

أكثر سيناريو استخدام شيوعاً هو الاتصال بالمحفظة عبر الكائن window.ethereum الذي توفره إضافات مثل MetaMask. بعد ذلك يمكن طلب ربط الحساب، جلب العنوان الحالي، ثم إنشاء مزود وموقّع للاستخدام داخل التطبيق.

import { useState } from "react";
import { ethers } from "ethers";

function App() {
  const [account, setAccount] = useState("");

  async function connectWallet() {
    if (!window.ethereum) {
      alert("MetaMask is not installed");
      return;
    }

    const provider = new ethers.BrowserProvider(window.ethereum);
    const accounts = await provider.send("eth_requestAccounts", []);
    setAccount(accounts[0]);
  }

  return (
    <div>
      <button onClick={connectWallet}>Connect Wallet</button>
      <p>Connected Account: {account}</p>
    </div>
  );
}

export default App;

المنطق هنا بسيط لكنه أساسي: أولاً نتحقق من وجود المحفظة، ثم ننشئ BrowserProvider، ثم نطلب من المستخدم الإذن بربط حسابه. عند النجاح يتم تخزين العنوان في حالة الواجهة عبر useState لعرضه فوراً.

قراءة البيانات من عقد ذكي

بعد الاتصال بالمحفظة، تأتي مرحلة القراءة من العقد. إذا كان لديك عقد بسيط يتضمن متغير حالة ودالة قراءة، مثل ما تم شرحه في أساسيات لغة Solidity: أنواع البيانات والمتغيرات (State Variables) والدوال (Functions) في Solidity: من يمكنه قراءة وتعديل بيانات العقد؟، يمكنك استدعاؤه مباشرة من الواجهة باستخدام ABI.

import { ethers } from "ethers";

const contractAddress = "0xYourContractAddress";
const abi = [
  "function getMessage() view returns (string)"
];

async function readMessage() {
  const provider = new ethers.BrowserProvider(window.ethereum);
  const contract = new ethers.Contract(contractAddress, abi, provider);
  const message = await contract.getMessage();
  console.log(message);
}

هذه العملية لا تحتاج إلى توقيع لأن الدالة من نوع view. وإذا أردت فهماً أعمق لكيفية تقليل استهلاك الشبكة والرسوم، فراجع أنواع الدوال : فهم view و pure لتوفير رسوم الـ Gas.

إرسال معاملة لتعديل حالة العقد

عندما تستدعي دالة تغيّر بيانات العقد، مثل تحديث نص أو تخزين قيمة جديدة، فأنت لا تقرأ فقط، بل تنشئ معاملة على الشبكة. هنا يجب استخدام Signer بدلاً من الاكتفاء بـ Provider.

import { ethers } from "ethers";

const contractAddress = "0xYourContractAddress";
const abi = [
  "function setMessage(string memory _message)"
];

async function updateMessage(newMessage) {
  const provider = new ethers.BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();
  const contract = new ethers.Contract(contractAddress, abi, signer);

  const tx = await contract.setMessage(newMessage);
  await tx.wait();

  console.log("Transaction confirmed");
}

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

لا تعتمد على نجاح إرسال المعاملة فقط، بل تعامل دائماً مع حالات الرفض، فشل التوقيع، تغيير الشبكة، أو انقطاع المزود. بناء واجهة Web3 آمنة يعني إدارة أخطاء المستخدم والشبكة بوضوح، وليس مجرد استدعاء الدوال.

تنظيم بنية المشروع بشكل احترافي

في المشاريع الصغيرة يمكن كتابة كل شيء داخل ملف واحد، لكن في التطبيقات الفعلية ستحتاج إلى فصل المنطق إلى طبقات. يفضّل إنشاء مجلدات خاصة بـ components وhooks وservices لحفظ شيفرات الاتصال بالعقد بعيداً عن مكونات العرض.

  • ملف للاتصال بالمحفظة.
  • ملف لتعريف عناوين العقود وواجهات ABI.
  • دوال مستقلة للقراءة والكتابة على الشبكة.
  • مكونات واجهة تعكس الحالة الحالية للمستخدم والمعاملة.

هذا التقسيم يسهل الصيانة، الاختبار، وإضافة أكثر من عقد لاحقاً، خصوصاً إذا كنت تعمل على مشروع مرتبط بـ معيار ERC-20: ما هي الرموز المميزة (Tokens) وكيف يتم إنشاؤها؟ أو معيار ERC-721: ما هي الرموز غير القابلة للاستبدال (NFTs) برمجياً؟.

أفضل الممارسات الأمنية والأدائية في الواجهة

الواجهة الأمامية ليست بديلاً عن أمان العقد، لكنها خط الدفاع الأول من ناحية تجربة المستخدم وتقليل الأخطاء التشغيلية. يجب التحقق من الشبكة الحالية، عرض عنوان العقد بوضوح، وتنبيه المستخدم إذا كانت المعاملة ستستهلك رسوماً مرتفعة، خاصة عند التعامل مع التكاليف (Gas Fees): كيف يحسب البلوكتشين تكلفة تنفيذ الأكواد؟.

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

كذلك، إذا كان العقد يحتوي على تحويلات مالية أو منطق حساس، فربط الواجهة يجب أن يراعي ما تعلمته من مقالات الأمان مثل أمن العقود الذكية (1): ثغرة إعادة الدخول (Reentrancy Attack) الشهيرة وكيفية استغلالها وأمن العقود الذكية (2): الحماية من ثغرة Reentrancy باستخدام ReentrancyGuard، لأن الواجهة قد تشجع على أنماط استخدام خاطئة إذا لم توضح المخاطر والقيود للمستخدم.

الخلاصة

إعداد واجهة React.js وتثبيت مكتبة Ethers.js هو الخطوة العملية التي تنقل مشروعك من عقد ذكي معزول إلى تطبيق DApp متكامل. تبدأ الرحلة من إنشاء مشروع الواجهة، ثم تثبيت المكتبة، وربط المحفظة، وقراءة بيانات العقد، ثم إرسال المعاملات ومراقبة نتائجها.

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

2 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *