إعداد مشروع Hardhat وكتابة أول سكربت JavaScript لترجمة (Compile) العقد الذكي
إعداد مشروع Hardhat وكتابة أول سكربت JavaScript لترجمة Compile العقد الذكي
بعد فهم الأساس النظري في مدخل إلى Web3: ما هو البلوكتشين ولماذا يغير شكل الإنترنت والأنظمة المالية؟، تأتي الخطوة العملية الأهم: بناء بيئة تطوير احترافية يمكنها إدارة العقود الذكية محلياً قبل النشر على أي شبكة. هنا يظهر دور Hardhat كإطار عمل متقدم يسهّل كتابة العقود، ترجمتها، اختبارها، ونشرها داخل بيئة منظمة تشبه ما يستخدمه المطورون في المشاريع الحقيقية.
إذا كنت أنهيت مسبقاً مقال الانتقال إلى بيئة العمل الاحترافية: تثبيت إطار عمل Hardhat باستخدام Node.js، فهذا المقال يكمل المرحلة التالية مباشرة. سنبني مشروعاً جديداً، نضيف عقداً ذكياً بسيطاً، ثم نكتب سكربت JavaScript مخصصاً لتنفيذ عملية Compile وفهم ما الذي يحدث داخلياً عند تحويل كود Solidity إلى Bytecode وملفات تعريف ABI.
لماذا نحتاج إلى Compile قبل تشغيل العقد الذكي؟
العقد الذكي لا يُنفذ على البلوكتشين بصيغته النصية التي يكتبها المطور بلغة Solidity. يجب أولاً تمريره عبر مترجم يحوّله إلى EVM Bytecode يمكن لآلة Ethereum Virtual Machine فهمه وتنفيذه.
في الوقت نفسه، يتم توليد ملف ABI الذي يمثل الواجهة البرمجية للعقد. هذا الملف هو الجسر بين الواجهة الأمامية أو سكربتات Ethers.js وبين الدوال المكتوبة داخل العقد الذكي مثل ما تعلمته في الدوال (Functions) في Solidity: من يمكنه قراءة وتعديل بيانات العقد؟.
بنية مشروع Hardhat الأساسية
عند إنشاء مشروع جديد باستخدام Hardhat ستجد عادة مجلدات رئيسية، ولكل واحد منها دور واضح في دورة تطوير العقد الذكي:
contracts: يحتوي ملفات العقود المكتوبة بلغةSolidity.scripts: يضم سكربتات التشغيل مثل الترجمة والنشر والتفاعل.test: مخصص لاختبارات العقود الذكية.artifacts: يخزن نواتجCompileمثلABIوBytecode.hardhat.config.js: ملف الإعدادات الذي يحدد نسخة المترجم والشبكات والإضافات.
إنشاء عقد ذكي بسيط للتجربة
سنستخدم عقداً تعليمياً بسيطاً اسمه Counter. هذا العقد مناسب لفهم الترجمة لأنه يحتوي متغير حالة ودالتين واضحتين. إذا كنت تريد مراجعة بنية المتغيرات، فمقال أساسيات لغة Solidity: أنواع البيانات والمتغيرات (State Variables) يشرح ذلك بالتفصيل.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Counter {
uint256 public count;
function increment() public {
count += 1;
}
function getCount() public view returns (uint256) {
return count;
}
}
احفظ هذا العقد داخل الملف contracts/Counter.sol. الدالة getCount مصنفة كـ view، وهذا يرتبط مباشرة بما تم شرحه في أنواع الدوال : فهم view و pure لتوفير رسوم الـ Gas.
تجهيز ملف الإعدادات
يجب التأكد أن ملف hardhat.config.js يحدد نسخة مترجم متوافقة مع العقد. مثال بسيط:
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.20",
};
رغم أن هذا الملف مكتوب فعلياً بلغة JavaScript، إلا أن أهميته شبيهة بإعداد بيئة الترجمة نفسها: فهو يحدد المترجم الذي سيحوّل كود العقد إلى صيغة قابلة للتنفيذ على EVM.
كتابة أول سكربت JavaScript لتنفيذ الترجمة
بدلاً من الاعتماد فقط على الأمر المباشر من الطرفية، من المفيد كتابة سكربت مستقل داخل مجلد scripts. هذا الأسلوب يمنحك مرونة لاحقاً لإضافة خطوات تلقائية مثل تنظيف الملفات، فحص المخرجات، أو دمج الترجمة مع النشر.
أنشئ الملف scripts/compile.js ثم أضف الكود التالي:
const hre = require("hardhat");
async function main() {
await hre.run("compile");
console.log("Contracts compiled successfully.");
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
هذا السكربت يستورد كائن hre وهو اختصار لـ Hardhat Runtime Environment. هذا الكائن يوفر وصولاً إلى المهام الداخلية مثل compile، والنشر، والتفاعل مع الشبكات.
كيف نشغّل السكربت؟
من داخل جذر المشروع نفّذ الأمر التالي:
npx hardhat run scripts/compile.js
عند نجاح العملية، سيقوم Hardhat بترجمة العقد وتوليد ملفات جديدة داخل مجلد artifacts. ستجد هناك ملفاً يحمل معلومات العقد كاملة، بما في ذلك ABI اللازمة لاحقاً لربط العقد مع الواجهات أو سكربتات Ethers.js.
ماذا ينتج عن عملية Compile فعلياً؟
النتيجة ليست مجرد “فحص صحة الكود”. بل هناك عدة مخرجات مهمة يعتمد عليها المشروع لاحقاً:
- تحويل كود
SolidityإلىBytecodeقابل للنشر. - إنشاء
ABIلتعريف الدوال والأحداث والمدخلات والمخرجات. - اكتشاف الأخطاء النحوية أو عدم التوافق بين الإصدارات.
- تجهيز بيانات وصفية
Metadataتسهّل التكامل مع أدوات أخرى.
هذا يوضح أن خطوة الترجمة هي قلب سلسلة التطوير كلها، وليست إجراء شكلياً فقط كما يظن بعض المبتدئين القادمين من بيئات مثل محرر Remix IDE: كتابة ونشر أول عقد ذكي (Smart Contract) على المتصفح مباشرة.
احرص دائماً على تثبيت نسخة
Solidityالمناسبة وعدم تغييرها عشوائياً بين الملفات. اختلاف الإصدارات قد يؤدي إلى سلوك غير متوقع، تحذيرات أمنية، أو تغيّر في استهلاكGas Feesعند النشر والتنفيذ. للمراجعة النظرية راجع التكاليف (Gas Fees): كيف يحسب البلوكتشين تكلفة تنفيذ الأكواد؟.
أخطاء شائعة أثناء الترجمة وكيف تتعامل معها
أثناء تشغيل سكربت الترجمة قد تظهر أخطاء متكررة، وغالباً يمكن حلها بسرعة إذا فهمت سببها:
- عدم تثبيت الحزم المطلوبة مثل
@nomicfoundation/hardhat-toolbox. - استخدام نسخة
pragmaلا تتطابق مع الإعدادات. - وجود خطأ في أسماء الدوال أو الأقواس أو أنواع البيانات.
- الخلط بين ملفات العقود وسكربتات التشغيل داخل مجلدات خاطئة.
إذا ظهر لك خطأ مرتبط بالمنطق البرمجي داخل العقد، فغالباً ستحتاج إلى مراجعة مفاهيم أكثر عمقاً مثل التعامل مع الأخطاء وإرجاع الأموال: استخدام require, assert, revert أو تنظيم الصلاحيات باستخدام المعدلات (Modifiers): حماية الدوال برمجياً.
الترجمة الناجحة لا تعني أن العقد آمن. قد يمر العقد من مرحلة
Compileدون أخطاء، لكنه يظل معرضاً لمشكلات منطقية أو ثغرات وصول أو سوء استخدام للذاكرة. لذلك افصل دائماً بين “سلامة الترجمة” و“سلامة الأمان”، واعتمد لاحقاً على الاختبارات والمراجعة وربما مكتبات مثل استخدام مكتبة OpenZeppelin لكتابة عقود ذكية آمنة ومختبرة مسبقاً.
لماذا يعتبر السكربت المخصص أفضل من الأمر المباشر أحياناً؟
يمكنك بالطبع تشغيل npx hardhat compile مباشرة، لكنه أقل مرونة من السكربت المخصص عندما يبدأ المشروع بالنمو. السكربت يسمح بإضافة خطوات مثل تسجيل نتائج العملية، قراءة ملفات بعينها، أو دمج الترجمة مع النشر على شبكات الاختبار بعد إعداد المحافظ عبر إعداد بيئة التطوير: تثبيت محفظة MetaMask والاتصال بشبكات الاختبار (Testnets).
وفي المشاريع الاحترافية، غالباً يتم بناء سلسلة أوامر تبدأ بالترجمة، ثم الاختبار، ثم النشر، ثم التحقق من العقد. لهذا السبب فإن تعلم كتابة سكربت بسيط الآن هو استثمار تقني مهم في فهم بنية أدوات Web3 الحديثة.
الخلاصة
إعداد مشروع Hardhat وكتابة أول سكربت JavaScript للترجمة ليس مجرد تمرين تمهيدي، بل هو الأساس الذي ستُبنى عليه كل المراحل التالية في تطوير العقود الذكية. عندما تفهم كيف ينتقل الكود من ملف .sol إلى Bytecode وABI، تصبح مستعداً للانتقال إلى مراحل أكثر تقدماً مثل الاختبار، النشر، والتفاعل البرمجي مع العقد عبر Ethers.js.
الخطوة التالية الطبيعية بعد هذا المقال هي بناء سكربت نشر إلى شبكة اختبار، ثم ربطه بمحفظة وتغذيته بعملات تجريبية من خلال الحصول على عملات تجريبية مجانية (Faucet) للبدء في نشر واختبار العقود الذكية. بهذه الطريقة تنتقل من مجرد ترجمة الكود إلى دورة تطوير Smart Contracts مكتملة ومهنية.
12 comments