Cách tạo kho lưu trữ băm IPFS phi tập trung trên Morph Blockchain

IPFS là gì? 🤔
Theo Wikipedia, Hệ thống Tệp Liên Hành Tinh (InterPlanetary File System - IPFS) là một giao thức phi tập trung, siêu phương tiện và mạng ngang hàng dùng để lưu trữ và chia sẻ tệp một cách phân tán. Bằng cách sử dụng phương pháp định địa chỉ nội dung (content-addressing), IPFS xác định duy nhất các tệp trong một không gian tên toàn cầu kết nối các máy chủ IPFS, tạo thành một hệ thống siêu phương tiện cho phép phân phối dữ liệu hiệu quả và đáng tin cậy.

Tính năng tương tác với các ứng dụng phi tập trung là một điểm mạnh của IPFS, cung cấp một nền tảng vững chắc cho hệ sinh thái Web3 và blockchain.

Trong bài viết này, chúng ta sẽ phát triển một ứng dụng phi tập trung trên mạng thử nghiệm Morph Holesky, sử dụng Pinata làm hệ thống lưu trữ để tạo và lưu trữ IPFS Hash trên chuỗi.


Yêu cầu cơ bản 📚

  • NodeJs (Phiên bản 18 hoặc mới hơn)

  • NPM (Phiên bản 7 hoặc mới hơn)

  • Metamask

  • Ether trên mạng thử nghiệm

  • Pinata API Key


Công cụ Dev 🛠

  • Yarn

    npm install -g yarn

Bước 1: Tạo một ứng dụng React mới

Hãy bắt đầu bằng việc tạo một ứng dụng React mới có tên là ipfs-hash-storage:

npm create vite@latest ipfs-hash-storage --template react

Làm theo hướng dẫn bằng cách chọn ReactJavaScript.

Điều hướng đến thư mục của ứng dụng React vừa tạo:

cd ipfs-hash-storage

Bước 2: Cài đặt gói Hardhat làm thư viện phụ thuộc

yarn add hardhat

Bước 3: Khởi tạo Hardhat làm môi trường phát triển Ethereum

npx hardhat init

Làm theo hướng dẫn bằng cách chọn Tạo một dự án JavaScript.

Xóa các tệp trong thư mục contractstest để bắt đầu một dự án mới từ đầu.


Phần thưởng: 💚 Cách tạo Pinata API Key

  1. Đăng ký hoặc đăng nhập tại pinata.cloud.

  2. Trong thanh bên, chọn API Keys.

  3. Ở góc trên bên phải, nhấp vào New Key.

  4. Chọn Admin để truy cập tất cả các endpoint và cài đặt tài khoản.

  5. Đặt tên cho khóa và nhấp vào Generate Key.

Một cửa sổ sẽ hiện ra chứa toàn bộ thông tin của API Key.

  1. Sao chép JWT Token và lưu trữ cẩn thận.

  2. Trong thanh bên, chọn Gateways và sao chép Domain link, sau đó lưu trữ cẩn thận.

Domain link này sẽ được sử dụng để tương tác với node IPFS thông qua Pinata.


Bước 4: Thiết lập thông tin môi trường

Cài đặt plugin để cấu hình biến môi trường:

yarn add --dev dotenv

Tạo một tệp mới có tên là .env trong thư mục gốc và thêm các biến sau:

RPC_URL="https://rpc-quicknode-holesky.morphl2.io"
DEV_PRIVATE_KEY="insert-your-private-key-here"
VITE_PINATA_JWT="insert-your-jwt-token-here"
VITE_PINATA_GATEWAY="insert-your-gateway-domain-link-here"

Bước 5: Cấu hình Hardhat để phát triển DApp

Mở tệp hardhat.config.cjs và cấu hình như sau:

require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();

const { RPC_URL, DEV_PRIVATE_KEY } = process.env;

module.exports = {
  solidity: "0.8.25",
  paths: {
    artifacts: "./src/artifacts",
  },
  networks: {
    morphTestnet: {
      chainId: 2810,
      url: RPC_URL,
      accounts: [DEV_PRIVATE_KEY],
      gasPrice: 2000000000,
    },
  },
};

Bước 6: Cấu hình Pinata cho mục đích lưu trữ

Cài đặt plugin Pinata:

yarn add pinata

Đi đến thư mục src và tạo tệp mới có tên là config.js.
Thêm mã sau vào tệp src/config.js để cấu hình Pinata:

import { PinataSDK } from "pinata";

const pinataJwt = import.meta.env.VITE_PINATA_JWT;
const pinataGateway = import.meta.env.VITE_PINATA_GATEWAY;

export const pinata = new PinataSDK({
  pinataJwt,
  pinataGateway,
});

Bước 7: Viết mã Solidity cho hợp đồng thông minh

Trong thư mục contracts, tạo tệp mới có tên là IpfsHashStorage.sol.
Dưới đây là mã nguồn cho hợp đồng thông minh:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract IpfsHashStorage {
    string private ipfsHash;

    // Hàm thiết lập Hash
    function setIPFSHash (string memory _ipfsHash) public {
        ipfsHash = _ipfsHash;
    }

    // Hàm lấy Hash
    function getIPFSHash() public view returns(string memory) {
        return ipfsHash;
    }
}

Bước 8: Biên dịch hợp đồng thông minh

Thực hiện lệnh sau để biên dịch mã hợp đồng thông minh:

yarn hardhat compile

Kết quả biên dịch sẽ hiển thị như sau:

Compiled 1 Solidity file successfully (evm target: paris).
✨ Done in 3.70s.

Bước 9: Triển khai DApp lên mạng thử nghiệm Morph

Cài đặt gói triển khai Hardhat:

yarn add --dev hardhat-deploy

Mở tệp hardhat.config.cjs và thêm phần cấu hình deployer như sau:

namedAccounts: {
  deployer: {
    default: 0,
  },
},

Tạo thư mục mới deploy ở thư mục gốc, sau đó thêm tệp deploy.cjs với nội dung sau:

module.exports = async ({ getNamedAccounts, deployments }) => {
  const { deploy, log } = deployments;
  const { deployer } = await getNamedAccounts();
  const args = [];
  await deploy("IpfsHashStorage", {
    contract: "IpfsHashStorage",
    args: args,
    from: deployer,
    log: true,
  });
};
module.exports.tags = ["IpfsHashStorage"];

Tích hợp Frontend với Blockchain

Dùng mã React để xây dựng giao diện người dùng, tải lên Pinata, lưu trữ Hash trên blockchain, và truy xuất Hash từ blockchain.

Bước 10: Cài đặt thư viện tương tác với blockchain

Để ứng dụng React tương tác với hợp đồng thông minh, chúng ta cần cài đặt một số thư viện cần thiết:

yarn add ethers web3modal

Bước 11: Tích hợp giao diện người dùng với Pinata và IPFS

Trong thư mục src, tạo hai tệp:

  1. UploadToPinata.js – Dùng để tải tệp lên Pinata.

  2. IpfsHashManager.js – Quản lý giao tiếp với hợp đồng thông minh để lưu trữ và truy xuất Hash từ blockchain.

Tệp UploadToPinata.js

Tệp này sẽ sử dụng Pinata SDK để tải tệp lên và nhận về IPFS Hash:

import { pinata } from "./config";

export const uploadToPinata = async (file) => {
  try {
    const formData = new FormData();
    formData.append("file", file);

    const response = await pinata.pinFileToIPFS(formData);
    return response.IpfsHash; // Hash IPFS của tệp
  } catch (error) {
    console.error("Lỗi khi tải lên Pinata:", error);
    throw new Error("Không thể tải lên Pinata");
  }
};

Tệp IpfsHashManager.js

Tệp này sẽ kết nối với hợp đồng thông minh để lưu và lấy IPFS Hash:

import { ethers } from "ethers";
import IpfsHashStorageABI from "./artifacts/contracts/IpfsHashStorage.sol/IpfsHashStorage.json";

const contractAddress = "Địa chỉ triển khai hợp đồng thông minh";

export const setIpfsHashOnBlockchain = async (ipfsHash) => {
  if (!window.ethereum) throw new Error("MetaMask chưa được cài đặt");

  const provider = new ethers.providers.Web3Provider(window.ethereum);
  const signer = provider.getSigner();
  const contract = new ethers.Contract(contractAddress, IpfsHashStorageABI.abi, signer);

  const tx = await contract.setIPFSHash(ipfsHash);
  await tx.wait();
  return tx.hash; // Trả về hash giao dịch
};

export const getIpfsHashFromBlockchain = async () => {
  if (!window.ethereum) throw new Error("MetaMask chưa được cài đặt");

  const provider = new ethers.providers.Web3Provider(window.ethereum);
  const contract = new ethers.Contract(contractAddress, IpfsHashStorageABI.abi, provider);

  return await contract.getIPFSHash();
};

Bước 12: Xây dựng giao diện người dùng chính

Trong tệp src/App.js, tạo giao diện người dùng để tải tệp, lưu Hash lên blockchain, và truy xuất lại:

import React, { useState } from "react";
import { uploadToPinata } from "./UploadToPinata";
import { setIpfsHashOnBlockchain, getIpfsHashFromBlockchain } from "./IpfsHashManager";

const App = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  const [ipfsHash, setIpfsHash] = useState("");
  const [retrievedHash, setRetrievedHash] = useState("");

  const handleFileChange = (e) => {
    setSelectedFile(e.target.files[0]);
  };

  const handleUpload = async () => {
    try {
      if (!selectedFile) throw new Error("Chọn tệp trước khi tải lên");
      const hash = await uploadToPinata(selectedFile);
      setIpfsHash(hash);
      alert(`Tệp được tải lên thành công: ${hash}`);
    } catch (error) {
      console.error(error);
      alert("Tải lên thất bại");
    }
  };

  const handleSaveToBlockchain = async () => {
    try {
      if (!ipfsHash) throw new Error("Không có IPFS Hash để lưu");
      const txHash = await setIpfsHashOnBlockchain(ipfsHash);
      alert(`Lưu Hash lên blockchain thành công: ${txHash}`);
    } catch (error) {
      console.error(error);
      alert("Lưu lên blockchain thất bại");
    }
  };

  const handleRetrieveFromBlockchain = async () => {
    try {
      const hash = await getIpfsHashFromBlockchain();
      setRetrievedHash(hash);
      alert(`Hash truy xuất từ blockchain: ${hash}`);
    } catch (error) {
      console.error(error);
      alert("Truy xuất từ blockchain thất bại");
    }
  };

  return (
    <div style={{ padding: "20px" }}>
      <h1>IPFS Hash Storage DApp</h1>
      <div>
        <input type="file" onChange={handleFileChange} />
        <button onClick={handleUpload}>Tải tệp lên Pinata</button>
      </div>
      <div>
        <p>IPFS Hash: {ipfsHash}</p>
        <button onClick={handleSaveToBlockchain}>Lưu Hash lên Blockchain</button>
      </div>
      <div>
        <button onClick={handleRetrieveFromBlockchain}>Truy xuất Hash từ Blockchain</button>
        <p>Hash từ Blockchain: {retrievedHash}</p>
      </div>
    </div>
  );
};

export default App;

Bước 13: Chạy ứng dụng

Để khởi chạy ứng dụng React:

Ứng dụng sẽ chạy tại địa chỉ http://localhost:3000.


Kết quả

  • Người dùng có thể tải tệp lên Pinata để nhận IPFS Hash.

  • Hash được lưu trên blockchain thông qua hợp đồng thông minh.

  • Hash có thể được truy xuất từ blockchain thông qua ứng dụng.

🎉 Chúc mừng, bạn đã xây dựng thành công một DApp sử dụng IPFS và blockchain!

Loading...
highlight
Collect this post to permanently own it.
The Journal Of Onchain Journey logo
Subscribe to The Journal Of Onchain Journey and never miss a post.