テクノロジーは人類に奉仕するものでなければなりません。すでに多くの分野に革命を起こしているブロックチェーン技術は、農業分野にも変革をもたらす可能性があります。この分散型テクノロジーを主流の採用トレンドにするには、一般大衆に届くように簡素化し、より幅広いユーザーに浸透させて、最終的に使用例を増やす必要があります。 このチュートリアルでは、ユーザーが Rootstock (RSK) ブロックチェーン ネットワーク上で農産物を売買できる分散型アプリケーション (dApp) を構築します。主な目的は、ブロックチェーン ネットワーク上で実行される dApp を構築することです。あらゆる種類のユーザーが、過度の人的介入なしに農産物を販売して収益を得るために、簡単に製品を追加できます。 当初、アプリは Rootstock のテストネットでテストされており、ほぼ本番環境対応の状態です (Rootstock のメインネットに切り替えるために若干の調整が必要でした)。プロジェクトはすでに GitHub にアップロードされているため、リポジトリをクローンして自分でテストすることができます。 このため、私は の 好みます。ただし、このチュートリアルでは、あらゆる種類のユーザーがチュートリアルを段階的に理解しながら簡単に dApp を構築できるように、詳細にガイドします。GitHub リポジトリからフロントエンド コードをダウンロードし、適切なディレクトリに追加することをお勧めします。プロジェクトのセットアップからスマート コントラクトのデプロイ、リアルタイム機能を備えたインタラクティブなフロントエンドの作成まで、すべてをカバーします。 GitHub Readme.md 始める前に、私たちは以下の機能を持つと予想される AgriMarket という dApp の構築を目指しています。 サポートされているウォレット (この場合は MetaMask) を通じてユーザーが Web3 機能にアクセスできるようにします。 ユーザーはウォレットを dApp に接続することで、農産物とその価格を追加できます。 アプリは、MetaMask と対話してスマートコントラクトの呼び出しを確認します。 ユーザーはカートに商品を追加することができ、カートに複数の商品がある場合でも dApp はトランザクションを開始できます。 ユーザーは、カートと商品リストページの両方から、リアルタイム通知、取引領収書、商品削除機能を利用できます。 📥前提条件 - 始める前に、マシンに以下がインストールされていることを確認してください。 Node.js (v14 以上) npm または yarn スマートコントラクト開発のためのTruffleまたはHardhat RSKテストネット用に設定されたMetaMask拡張機能 バージョン管理のための Git VSCodeのようなIDE 📥プロジェクトのセットアップ 👉プロジェクトディレクトリを作成する 開発およびテストのプロセス全体を通じて、このメイン プロジェクトのディレクトリを優先するようにしてください。 👉プロジェクトディレクトリを初期化する ターミナルで次のコマンドを実行して、プロジェクト用の新しいディレクトリを作成します。 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 余分なスペースや文字の不一致のない ファイルを作成してください。そうしないと、後で問題が発生します。後でスマート コントラクトを更新するので、この を覚えておいてください。Pinata API は から取得してください。 .env 手順 ここ 📥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 すべてが正しく実行されると、ターミナルに次のような内容が表示されます。 ターミナルで次のコマンドを実行して、 Rootstock のテストネットにデプロイします。 Marketplace.sol truffle migrate --network rskTestnet 契約をデプロイする前に、ウォレットに一定量の tRBTC が必要です。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 での Web3 セットアップ src/utils/Marketplace.json スマート コントラクトと対話するには、ABI (アプリケーション バイナリ インターフェイス) をインポートします。 で説明したように、Truffle の ディレクトリから ABI を フォルダにコピーします。 手順 build/contracts Marketplace.json client/src/utils/ Web3 のセットアップは ファイルにあります。これを からダウンロードし、図 1 に示すように適切なディレクトリに配置します。 App.js GitHub 👉 リアルタイム通知と進捗バー リアルタイム通知のために、 のようなライブラリを統合します。プログレスバーには 使用することもできます。 react-toastify react-bootstrap ディレクトリにReact Toastifyをインストールする client npm install react-toastify 👉HTTP リクエスト (Pinata の API へ) 用に Axios をインストールします。 npm install axios さて、 のクライアント フォルダー (フォルダー + ファイルを含む) からすべてのフロントエンド コンポーネントをダウンロードしてください。そして、適切なディレクトリに配置します。 GitHub リポジトリ 📥アプリの最終仕上げと操作 👉これで、dApp を操作できるようになりました。ターミナルで次のコマンドを使用して、React アプリを実行できます。 npm start デフォルトのブラウザが自動的に開きます。MetMask ブラウザ拡張機能がインストールされ、RSK テストネットが適切に設定されていることを確認してください ( プロジェクトのガイドに従って正しいネットワークを選択できます)。 ここで ここで、React アプリは MetaMask ウォレット拡張機能を呼び出します。呼び出しを確認してください。次の図に示すように、接続されたウォレットがメイン インターフェイスに表示されます。 フロントエンドには豊富な機能があります。製品を追加/削除できます。そのたびに、MetaMask ウォレット拡張機能で呼び出しを確認するように求められます。次の gif を確認してください。 さて、これで、dApp がカートに追加されたトランザクションを適切に処理するかどうかをテストできます。「トランザクション履歴」セクションで、すべての技術的な詳細を含む詳細なトランザクション履歴を確認できます。購入が完了すると、dApp に製品を追加した所有者に資金が送られます。 一緒にアプリをテストしましょう: おめでとうございます!RSK テストネットで dApp の開発とテストに成功しました。必要な機能を追加することで、RSK メインネットに切り替えることができます。テストネットが言及されているコードを調整するだけで、本番環境対応のアプリを急いで構築する場合は、ここにある も確認してください。 プロジェクトのドキュメント 📥潜在的な課題と将来: これは、製品の配送、ピックアップなどのいくつかのプロセスを含む農業市場を開始するための新しいアプローチになります。買い手と売り手の詳細を知らなければ、信頼の問題が生じる可能性があります。もう 1 つの課題は、まだ実験段階であり、進化するこの技術に対して消費者がどのように反応するかがわからないことです。 したがって、農家と消費者の両方が新しい技術を採用するには、教育とトレーニングが不可欠です。また、十分な協力関係は、農産物の持続可能な分散型市場を開発するための重要な要素です。 結論: Rootstock (RSK) テストネット上に分散型農業マーケットプレイスを構築することに成功しました。セキュリティを最優先に考え、OpenZeppelin 契約を使用してスマートコントラクト コードを保護するための対策を講じています。テスト済みの dApp には、シンプルな分散型マーケットプレイスに必要なほぼすべての機能が含まれていますが、Rootstock のメインネットでアプリを起動する予定がある場合は、さらに多くの機能を追加して強化できます。また、すべてが意図したとおりにスムーズに機能するように、セキュリティにも留意してください。 私たちは、すべての取引を進めるために、取引手数料が低い Rootstock の高速取引処理機能を活用しようと試みました。これにより、ビットコインの悪名高い混雑問題が解決されます。もちろん、このような分散型マーケットプレイスには多くの問題が伴いますが、私たちは当然自由を求めているので、将来的にはより分散化されたマーケットプレイスが見つかると期待できます。