يجب أن تكون التكنولوجيا في خدمة البشرية. يمكن لتكنولوجيا Blockchain، التي أحدثت ثورة في العديد من القطاعات، أن تحول أيضًا مجال الزراعة. ولجعل هذه التكنولوجيا اللامركزية اتجاهًا سائدًا للتبني، يجب علينا تبسيطها للوصول إلى عامة الناس حتى نتمكن من الوصول إلى المستخدمين الأوسع، مما يؤدي في النهاية إلى زيادة حالات الاستخدام.
في هذا البرنامج التعليمي، سنقوم ببناء تطبيق لامركزي (dApp) يسمح للمستخدمين بشراء وبيع المنتجات الزراعية على شبكة بلوكتشين Rootstock (RSK). الهدف الرئيسي هو بناء تطبيق لامركزي يعمل على شبكة بلوكتشين. يمكن لأي نوع من المستخدمين إضافة المنتجات بسهولة لكسب المال عن طريق بيع منتجاتهم الزراعية دون تدخل بشري مفرط.
في البداية، تم اختبار التطبيق على شبكة اختبار Rootstock، وهو الآن في حالة جاهزة للإنتاج تقريبًا (كان يحتاج فقط إلى تعديلات بسيطة للتبديل إلى الشبكة الرئيسية لـ Rootstock). تم تحميل المشروع بالفعل على GitHub، لذا يمكنك استنساخ المستودع لاختباره بنفسك.
لهذا، أفضل Readme.md
على GitHub . ولكن في هذا البرنامج التعليمي، نحاول تقديم إرشادات متعمقة حتى يتمكن أي نوع من المستخدمين من بناء تطبيقهم اللامركزي بسهولة فهم البرنامج التعليمي خطوة بخطوة. قد نقترح عليك تنزيل كود الواجهة الأمامية من مستودع GitHub وإضافته إلى الدليل المناسب. سنغطي كل شيء من إعداد المشروع إلى نشر العقود الذكية وإنشاء واجهة أمامية تفاعلية بميزات في الوقت الفعلي.
قبل البدء، نهدف إلى بناء تطبيق لامركزي يسمى AgriMarket والذي من المتوقع أن يتمتع بالميزات التالية:
👉إنشاء دليل المشروع
يرجى التأكد من تفضيلك لدليل المشروع الرئيسي هذا طوال عملية التطوير والاختبار بأكملها.
👉تهيئة دليل المشروع
قم بإنشاء دليل جديد لمشروعك عن طريق تشغيل الأوامر التالية في المحطة الطرفية:
mkdir rsk-agri-marketplace cd rsk-agri-marketplace
👉 قم بتهيئة مشروع npm جديد:
npm init -y
👉بدء مشروع الكمأة
نحن نستخدم Truffle لتجميع وتطوير العقد الذكي، لذا قم بتهيئته من خلال الدليل الجذر:
truffle init
يؤدي هذا إلى إنشاء البنية الأساسية: • contracts/
- تحتوي على عقود Solidity • migrations/
- نصوص النشر • test/
- اختبارات لعقودك • truffle-config.js
- ملف تكوين Truffle
يجب تخزين المعلومات الحساسة مثل المفاتيح الخاصة ومفتاح API الخاص بـ Pimata وما إلى ذلك في ملف .env.
👉 قم بتثبيت dotenv
npm install dotenv
👉إنشاء ملف .env
في الدليل الجذر، قم بإنشاء ملف .env بالهيكل التالي:
REACT_APP_PINATA_API_KEY=Your API Key REACT_APP_PINATA_SECRET_API_KEY=Secret API Key MNEMONIC=12 words mnemonic key RSK_TESTNET_URL=https://public-node.testnet.rsk.co REACT_APP_CONTRACT_ADDRESS=Contract Address
يرجى إنشاء ملف .env
بدون مسافات إضافية أو عدم تطابق الأحرف وإلا ستواجه صعوبات لاحقًا. يرجى تذكر هذه الخطوة لأنك تقوم بتحديث العقد الذكي لاحقًا. احصل على واجهة برمجة تطبيقات Pinata من هنا .
👉تحديث truffle-config.js
يمكنك رؤية ملف truffle-config.js الذي تم إنشاؤه بالفعل في دليل مشروعك. ما عليك سوى تحديث الكود حتى نتمكن من التفاعل مع شبكة اختبار RSK من خلاله.
require('dotenv').config(); const HDWalletProvider = require('@truffle/hdwallet-provider'); module.exports = { networks: { development: { host: "127.0.0.1", port: 8545, network_id: "*", }, rskTestnet: { provider: () => new HDWalletProvider({ mnemonic: { phrase: process.env.MNEMONIC, }, providerOrUrl: `https://public-node.testnet.rsk.co`, chainId: 31, // RSK Testnet ID pollingInterval: 15000, }), network_id: 31, gas: 2500000, gasPrice: 60000000, confirmations: 2, timeoutBlocks: 60000, skipDryRun: true, }, }, compilers: { solc: { version: "0.8.20", }, }, db: { enabled: false, }, };
👉قم بتثبيت HDWalletProvider
npm install @truffle/hdwallet-provider
سوف نقوم بإنشاء عقد السوق.
👉 قم بتثبيت عقود OpenZeppelin
نحن نستخدم عقود OpenZeppelin لتحسين الأمان والتشغيل السلس لعقدنا الذكي، لذا قم بتثبيته عن طريق تشغيل الأمر التالي في المحطة الطرفية:
npm install @openzeppelin/contracts
👉 قم بإنشاء Marketplace.sol
في دليل contracts/
:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; contract Marketplace is ReentrancyGuard, Pausable { uint public productCount = 0; struct Product { uint id; address payable seller; string name; string description; string imageHash; // IPFS hash uint price; // Price in tRBTC bool active; } mapping(uint => Product) public products; event ProductCreated( uint id, address seller, string name, string description, string imageHash, uint price, bool active ); event ProductPurchased( uint id, address seller, address buyer, uint price ); event ProductRemoved(uint id, address seller); function createProduct( string memory _name, string memory _description, string memory _imageHash, uint _price ) public whenNotPaused { require(bytes(_name).length > 0, "Name is required"); require(_price > 0, "Price must be positive"); // Price is expected in tRBTC productCount++; products[productCount] = Product( productCount, payable(msg.sender), _name, _description, _imageHash, _price, true ); emit ProductCreated( productCount, msg.sender, _name, _description, _imageHash, _price, true ); } function purchaseProducts(uint[] memory _ids) public payable nonReentrant whenNotPaused { uint totalCost = 0; for (uint i = 0; i < _ids.length; i++) { Product storage _product = products[_ids[i]]; require(_product.id > 0 && _product.id <= productCount, "Invalid product ID"); require(_product.active, "Product is not active"); require(_product.seller != msg.sender, "Seller cannot buy their own product"); totalCost += _product.price; } require(msg.value >= totalCost, "Insufficient funds"); for (uint i = 0; i < _ids.length; i++) { Product storage _product = products[_ids[i]]; (bool success, ) = _product.seller.call{value: _product.price}(""); require(success, "Transfer failed to the seller"); // Emit purchase event (product can be bought again) emit ProductPurchased( _product.id, _product.seller, msg.sender, _product.price ); } } function removeProduct(uint _id) public { Product storage _product = products[_id]; require(_product.id > 0 && _product.id <= productCount, "Invalid product ID"); require(_product.seller == msg.sender, "Only the seller can remove the product"); _product.active = false; // Mark the product as inactive emit ProductRemoved(_id, msg.sender); } function getProduct(uint _id) public view returns (Product memory) { require(_id > 0 && _id <= productCount, "Invalid product ID"); Product memory product = products[_id]; require(product.active, "Product is not available"); return product; } function pause() public { _pause(); } function unpause() public { _unpause(); } }
👉اكتب نص الهجرة في migrations/2_deploy_contracts.js
const Marketplace = artifacts.require("Marketplace"); module.exports = function (deployer) { deployer.deploy(Marketplace); };
👉تجميع العقود ونشرها
قم بتشغيل الكود التالي لتجميع العقد من خلال المحطة الطرفية:
truffle compile
إذا سارت الأمور على ما يرام، فيمكنك رؤية شيء مثل هذا في المحطة الطرفية:
قم بتشغيل الأمر التالي في المحطة الطرفية لنشر Marketplace.sol
على شبكة اختبار Rootstock.
truffle migrate --network rskTestnet
تحتاج إلى بعض المبالغ من tRBTC في المحفظة قبل نشر العقد الخاص بك. احصل عليه من صنبور RSK هنا .
بعد نجاح العملية، ستظهر لك الرسالة التالية في المحطة الطرفية:
ستجد ملف Marketplace.json
في \build\contracts\Marketplace.json
تذكره، وسوف تقوم بنسخ هذا الملف إلى دليل آخر.
تطوير واجهة المستخدم لتطبيق Marketplace dApp
الآن بعد أن قمنا بنشر العقود الذكية، سنبني واجهة أمامية جذابة للسوق تسمح للمستخدمين بالتفاعل معها. ستحتوي الواجهة الأمامية على ميزات مثل قوائم المنتجات، وإضافة المنتجات، والشراء، وإضافة/إزالة المنتجات من عربة التسوق، وتتبع المعاملات، وتوفير ملاحظات في الوقت الفعلي مثل الإشعارات وشريط التقدم.
👉تهيئة تطبيق React
سنستخدم React للواجهة الأمامية.
قم بتشغيل تطبيق React جديد في دليل المشروع.
npx create-react-app client
انتقل إلى دليل العميل.
cd client
تثبيت Web3 وBootstrap لواجهة المستخدم
npm install web3 bootstrap
👉هيكل المشروع
ستحتاج إلى الهيكل الخاص بالواجهة الأمامية كما هو موضح في الشكل 1.
👉إعداد Web3 في src/utils/Marketplace.json
للتفاعل مع العقد الذكي، سنقوم باستيراد ABI (واجهة التطبيق الثنائية).
Marketplace.json
ABI من دليل Truffle build/contracts
إلى المجلد client/src/utils/
كما هو مذكور في الخطوة .
App.js
قم بتنزيله من GitHub وضعه في الدليل المناسب كما هو موضح في الشكل 1.
👉 إشعارات في الوقت الفعلي وأشرطة التقدم
بالنسبة للإشعارات في الوقت الفعلي، سندمج مكتبة مثل react-toastify
. يمكنك أيضًا استخدام react-bootstrap
لأشرطة التقدم.
تثبيت React Toastify في دليل client
npm install react-toastify
👉قم بتثبيت Axios لطلبات HTTP (إلى واجهة برمجة تطبيقات Pinata):
npm install axios
حسنًا، يُرجى الآن تنزيل كافة مكونات الواجهة الأمامية من مجلد العميل (بما في ذلك المجلد والملفات) في مستودع GitHub . ووضعها في الدليل المناسب.
👉الآن، يمكنك التفاعل مع تطبيقك اللامركزي. يمكنك تشغيل تطبيق React الخاص بك باستخدام الأمر التالي في المحطة الطرفية:
npm start
سيتم فتح المتصفح الافتراضي تلقائيًا. يرجى التأكد من تثبيت ملحق متصفح MetMask وتكوين شبكة اختبار RSK بشكل صحيح (يمكنك اتباع دليل المشروع لاختيار الشبكة الصحيحة هنا ).
الآن، يستدعي تطبيق React ملحق محفظة MetaMask، يرجى تأكيد المكالمة. ثم سيعرض المحفظة المتصلة في الواجهة الرئيسية كما هو موضح في الشكل التالي.
توفر لك الواجهة الأمامية العديد من الميزات. يمكنك إضافة/إزالة المنتجات. في كل مرة، سيُطلب منك تأكيد المكالمة في ملحق محفظة MetaMask. تحقق من ملف GIF التالي:
حسنًا، يمكنك الآن اختبار ما إذا كان التطبيق اللامركزي يعالج المعاملات المضافة إلى عربة التسوق بشكل صحيح أم لا. يمكنك الاطلاع على سجل المعاملات التفصيلي ضمن قسم "سجل المعاملات" مع جميع التفاصيل الفنية. بمجرد اكتمال عملية الشراء، يتم إرسال الأموال إلى المالك الذي أضاف المنتجات إلى التطبيق اللامركزي.
دعونا نختبر التطبيق معًا:
مبروك! لقد نجحنا في تطوير واختبار التطبيق اللامركزي في شبكة اختبار RSK. يمكنك تحويله إلى شبكة RSK الرئيسية عن طريق إضافة الميزات التي تريدها. ما عليك سوى تعديل التعليمات البرمجية أينما ورد ذكر شبكة الاختبار والتحقق أيضًا من وثائق المشروع هنا إذا كنت تتعجل في بناء التطبيق الجاهز للإنتاج.
سيكون النهج الجديد لبدء السوق الزراعية هو الذي يتضمن العديد من العمليات مثل تسليم المنتج واستلامه وما إلى ذلك. وبدون معرفة المشترين والبائعين بالتفصيل، فقد يؤدي ذلك إلى خلق مشكلات تتعلق بالثقة. والتحدي الآخر هو أنه لا يزال في مرحلة تجريبية، ولا نعرف كيف يتصرف المستهلكون مع هذه التكنولوجيا المتطورة.
لذا، فإن التعليم والتدريب ضروريان لتمكين المزارعين والمستهلكين على حد سواء من تبني التقنيات الجديدة. كما أن التعاون الكافي يشكل العامل الرئيسي في تطوير سوق لامركزية مستدامة للمنتجات الزراعية.
لقد نجحنا في بناء سوق زراعي لامركزي على شبكة اختبار Rootstock (RSK). لقد تم اعتبار الأمان أولوية، ولهذا السبب تم اتخاذ العديد من التدابير لحماية كود العقد الذكي باستخدام عقود OpenZeppelin. يتكون التطبيق اللامركزي الذي تم اختباره من جميع الميزات الضرورية تقريبًا التي يجب أن يتمتع بها السوق اللامركزي البسيط، ولكن يمكنك تحسينه بمزيد من الميزات إذا كنت تخطط لإطلاق التطبيق على الشبكة الرئيسية لـ Rootstock. أيضًا، ضع الأمان في الاعتبار للتأكد من أن كل شيء يعمل كما هو مقصود وبسلاسة.
لقد حاولنا الاستفادة من ميزات معالجة المعاملات السريعة التي تقدمها Rootstock مع رسوم المعاملات المنخفضة للمضي قدمًا في جميع المعاملات التي ستحل مشكلة الازدحام الشهيرة في Bitcoin. بالطبع، تواجه هذه الأنواع من الأسواق اللامركزية العديد من المشكلات، ولكن بما أننا نسعى بشكل طبيعي إلى الحرية، فيمكننا أن نأمل في العثور على سوق أكثر لامركزية في المستقبل.