paint-brush
RSK テストネット上で農産物の分散型マーケットプレイスを構築する方法@induction
545 測定値
545 測定値

RSK テストネット上で農産物の分散型マーケットプレイスを構築する方法

Vision NP13m2024/09/30
Read on Terminal Reader

長すぎる; 読むには

テクノロジーは人類に奉仕するものでなければなりません。すでに多くの分野に革命を起こしているブロックチェーン技術は、農業分野にも変革をもたらす可能性があります。この分散型テクノロジーを主流の採用トレンドにするには、一般大衆に届くように簡素化し、より幅広いユーザーに浸透させて、最終的に使用例を増やす必要があります。
featured image - RSK テストネット上で農産物の分散型マーケットプレイスを構築する方法
Vision NP HackerNoon profile picture
0-item
1-item
2-item

テクノロジーは人類に奉仕するものでなければなりません。すでに多くの分野に革命を起こしているブロックチェーン技術は、農業分野にも変革をもたらす可能性があります。この分散型テクノロジーを主流の採用トレンドにするには、一般大衆に届くように簡素化し、より幅広いユーザーに浸透させて、最終的に使用例を増やす必要があります。


このチュートリアルでは、ユーザーが Rootstock (RSK) ブロックチェーン ネットワーク上で農産物を売買できる分散型アプリケーション (dApp) を構築します。主な目的は、ブロックチェーン ネットワーク上で実行される dApp を構築することです。あらゆる種類のユーザーが、過度の人的介入なしに農産物を販売して収益を得るために、簡単に製品を追加できます。


当初、アプリは Rootstock のテストネットでテストされており、ほぼ本番環境対応の状態です (Rootstock のメインネットに切り替えるために若干の調整が必要でした)。プロジェクトはすでに GitHub にアップロードされているため、リポジトリをクローンして自分でテストすることができます。


このため、私はGitHubReadme.md好みます。ただし、このチュートリアルでは、あらゆる種類のユーザーがチュートリアルを段階的に理解しながら簡単に dApp を構築できるように、詳細にガイドします。GitHub リポジトリからフロントエンド コードをダウンロードし、適切なディレクトリに追加することをお勧めします。プロジェクトのセットアップからスマート コントラクトのデプロイ、リアルタイム機能を備えたインタラクティブなフロントエンドの作成まで、すべてをカバーします。


始める前に、私たちは以下の機能を持つと予想される AgriMarket という dApp の構築を目指しています。

  • サポートされているウォレット (この場合は MetaMask) を通じてユーザーが Web3 機能にアクセスできるようにします。
  • ユーザーはウォレットを dApp に接続することで、農産物とその価格を追加できます。
  • アプリは、MetaMask と対話してスマートコントラクトの呼び出しを確認します。
  • ユーザーはカートに商品を追加することができ、カートに複数の商品がある場合でも dApp はトランザクションを開始できます。
  • ユーザーは、カートと商品リストページの両方から、リアルタイム通知、取引領収書、商品削除機能を利用できます。

📥前提条件 - 始める前に、マシンに以下がインストールされていることを確認してください。

  • Node.js (v14 以上)
  • npm または yarn
  • スマートコントラクト開発のためのTruffleまたはHardhat
  • RSKテストネット用に設定されたMetaMask拡張機能
  • バージョン管理のための Git
  • VSCodeのようなIDE

📥プロジェクトのセットアップ

👉プロジェクトディレクトリを作成する


開発およびテストのプロセス全体を通じて、このメイン プロジェクトのディレクトリを優先するようにしてください。


図1.プロジェクトのディレクトリ


👉プロジェクトディレクトリを初期化する

ターミナルで次のコマンドを実行して、プロジェクト用の新しいディレクトリを作成します。

 mkdir rsk-agri-marketplace cd rsk-agri-marketplace


👉新しい npm プロジェクトを初期化します。

 npm init -y


👉Truffleプロジェクトの初期化


スマート コントラクトのコンパイルと開発には Truffle を使用しているため、ルート ディレクトリから初期化します。

 truffle init


これにより、基本的な構造が作成されます。 • contracts/ - Solidity コントラクトが含まれますmigrations/ -デプロイメント スクリプトtest/ -コントラクトのテストtruffle-config.js - Truffle 構成ファイル


📥環境変数を設定する

秘密鍵、Pimata API キーなどの機密情報は、.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 API はここから取得してください。

📥RSKテストネットへの接続

👉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


contracts/ディレクトリにMarketplace.sol作成します。

 // 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(); } }


👉migrates migrations/2_deploy_contracts.jsに移行スクリプトを記述する

const Marketplace = artifacts.require("Marketplace"); module.exports = function (deployer) { deployer.deploy(Marketplace); };


👉コントラクトをコンパイルしてデプロイする

ターミナル経由でコントラクトをコンパイルするには、次のコードを実行します。

 truffle compile


すべてが正しく実行されると、ターミナルに次のような内容が表示されます。

図2. Truffleを使用したコントラクトコンパイル


ターミナルで次のコマンドを実行して、 Marketplace.sol Rootstock のテストネットにデプロイします。

 truffle migrate --network rskTestnet

契約をデプロイする前に、ウォレットに一定量の tRBTC が必要です。RSK フォーセットから入手してください。

プロセスが成功すると、ターミナルに次のメッセージが表示されます。

図3.RSKテストネットにデプロイされたコントラクト

Marketplace.jsonファイルは\build\contracts\Marketplace.jsonにあります。覚えておいてください。このファイルを別のディレクトリにコピーします。


マーケットプレイス dApp のフロントエンド開発


スマート コントラクトをデプロイしたので、ユーザーがマーケットプレイスとやり取りできる魅力的なフロントエンドを構築します。フロントエンドには、製品リスト、製品の追加、購入、カートへの製品の追加/削除、トランザクションの追跡、通知や進行状況バーなどのリアルタイム フィードバックの提供などの機能があります。

📥フロントエンド開発

👉Reactアプリケーションを初期化する

フロントエンドにはReactを使用します。


プロジェクト ディレクトリで新しい React アプリを初期化します。

 npx create-react-app client


クライアント ディレクトリに移動します。

 cd client


UI用にWeb3とBootstrapをインストールする

npm install web3 bootstrap


👉プロジェクト構造

図 1 に示すように、フロントエンドの構造が必要になります。


👉src src/utils/Marketplace.jsonでの Web3 セットアップ

スマート コントラクトと対話するには、ABI (アプリケーション バイナリ インターフェイス) をインポートします。

  • 手順で説明したように、Truffle のbuild/contractsディレクトリからMarketplace.json ABI をclient/src/utils/フォルダにコピーします。


  • Web3 のセットアップはApp.jsファイルにあります。これをGitHubからダウンロードし、図 1 に示すように適切なディレクトリに配置します。


👉 リアルタイム通知と進捗バー

リアルタイム通知のために、 react-toastifyのようなライブラリを統合します。プログレスバーにはreact-bootstrap使用することもできます。


clientディレクトリにReact Toastifyをインストールする

npm install react-toastify


👉HTTP リクエスト (Pinata の API へ) 用に Axios をインストールします。

 npm install axios


さて、 GitHub リポジトリのクライアント フォルダー (フォルダー + ファイルを含む) からすべてのフロントエンド コンポーネントをダウンロードしてください。そして、適切なディレクトリに配置します。

📥アプリの最終仕上げと操作

👉これで、dApp を操作できるようになりました。ターミナルで次のコマンドを使用して、React アプリを実行できます。

 npm start


デフォルトのブラウザが自動的に開きます。MetMask ブラウザ拡張機能がインストールされ、RSK テストネットが適切に設定されていることを確認してください (ここでプロジェクトのガイドに従って正しいネットワークを選択できます)。


ここで、React アプリは MetaMask ウォレット拡張機能を呼び出します。呼び出しを確認してください。次の図に示すように、接続されたウォレットがメイン インターフェイスに表示されます。

図4. フロントエンドのメインUI



フロントエンドには豊富な機能があります。製品を追加/削除できます。そのたびに、MetaMask ウォレット拡張機能で呼び出しを確認するように求められます。次の gif を確認してください。


GIF 1. dAppのフロントエンドに商品を追加するプロセス


さて、これで、dApp がカートに追加されたトランザクションを適切に処理するかどうかをテストできます。「トランザクション履歴」セクションで、すべての技術的な詳細を含む詳細なトランザクション履歴を確認できます。購入が完了すると、dApp に製品を追加した所有者に資金が送られます。


一緒にアプリをテストしましょう:

GIF 2. カートからの取引を処理するための完全に機能するdApp


おめでとうございます!RSK テストネットで dApp の開発とテストに成功しました。必要な機能を追加することで、RSK メインネットに切り替えることができます。テストネットが言及されているコードを調整するだけで、本番環境対応のアプリを急いで構築する場合は、ここにあるプロジェクトのドキュメントも確認してください。

📥潜在的な課題と将来:

これは、製品の配送、ピックアップなどのいくつかのプロセスを含む農業市場を開始するための新しいアプローチになります。買い手と売り手の詳細を知らなければ、信頼の問題が生じる可能性があります。もう 1 つの課題は、まだ実験段階であり、進化するこの技術に対して消費者がどのように反応するかがわからないことです。


したがって、農家と消費者の両方が新しい技術を採用するには、教育とトレーニングが不可欠です。また、十分な協力関係は、農産物の持続可能な分散型市場を開発するための重要な要素です。

結論:

Rootstock (RSK) テストネット上に分散型農業マーケットプレイスを構築することに成功しました。セキュリティを最優先に考え、OpenZeppelin 契約を使用してスマートコントラクト コードを保護するための対策を講じています。テスト済みの dApp には、シンプルな分散型マーケットプレイスに必要なほぼすべての機能が含まれていますが、Rootstock のメインネットでアプリを起動する予定がある場合は、さらに多くの機能を追加して強化できます。また、すべてが意図したとおりにスムーズに機能するように、セキュリティにも留意してください。


私たちは、すべての取引を進めるために、取引手数料が低い Rootstock の高速取引処理機能を活用しようと試みました。これにより、ビットコインの悪名高い混雑問題が解決されます。もちろん、このような分散型マーケットプレイスには多くの問題が伴いますが、私たちは当然自由を求めているので、将来的にはより分散化されたマーケットプレイスが見つかると期待できます。