从零开始构建你的第一个以太坊应用,以太坊基础项目实战指南

以太坊作为全球第二大加密货币平台,更是一个强大的去中心化应用(DApp)开发平台,它通过智能合约实现了可编程的信任,为金融、游戏、供应链、社交媒体等众多领域带来了革命性的可能,对于初学者而言,理论学习固然重要,但“以太坊基础项目实战”才是真正掌握其核心魅力的不二法门,本文将带你走完一个简单的以太坊基础项目实战流程,从环境搭建到部署交互,让你亲身体验DApp开发的乐趣与挑战。

项目实战准备:工欲善其事,必先利其器

在开始编码之前,我们需要准备好开发环境:

  1. 安装Node.js和npm/yarn:Node.js是JavaScript运行时环境,npm是其包管理器,DApp开发的前端部分通常需要它们,从Node.js官网下载并安装LTS版本即可。
  2. 安装MetaMask:MetaMask是一款流行的浏览器钱包插件,它让你能与以太坊区块链进行交互,管理私钥、发送交易、与DApp进行连接,从MetaMask官网下载并安装到你的浏览器(如Chrome、Firefox)。
  3. 选择开发框架与库
    • Hardhat:一个流行的以太坊开发环境,编译、测试、部署智能合约非常方便,插件丰富。
    • Truffle:老牌的以太坊开发框架,功能全面,社区庞大。
    • Ethers.js:一个功能强大且灵活的JavaScript库,用于与以太坊网络和智能合约进行交互。
    • React/Vue:用于构建DApp的前端界面,本文将以React为例。
  4. 配置本地测试网络:为了避免在开发过程中消耗真实的ETH(测试币),我们通常在本地运行一个以太坊节点,Hardhat内置了Hardhat Network,开箱即用,非常适合开发测试。

项目实战步骤:构建一个简单的“留言板”DApp

我们将构建一个经典的“以太坊留言板”DApp,用户可以通过这个DApp在区块链上留下自己的留言,并查看所有留言。

初始化项目与安装依赖

  1. 创建一个新的项目目录,并初始化一个Node.js项目:
    mkdir ethereum-message-board
    cd ethereum-message-board
    npm init -y
  2. 安装Hardhat和Ethers.js:
    npm install --save-dev hardhat
    npm install ethers
  3. 初始化Hardhat项目:
    npx hardhat

    按照提示选择"Create a basic JavaScript project"(或其他你熟悉的语言),然后一路回车,Hardhat会帮你生成基本的contracts/scripts/test/

    随机配图
    目录。

编写智能合约

  1. contracts目录下,创建一个新的Solidity文件MessageBoard.sol

  2. 编写智能合约代码:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    contract MessageBoard {
        // 定义一个结构体来存储留言信息
        struct Message {
            address author; // 留言者地址
            string content; // 留言内容
            uint256 timestamp; // 留言时间戳
        }
        // 存储留言的数组
        Message[] public messages;
        // 留言事件,方便前端监听
        event NewMessage(address indexed author, string content, uint256 timestamp);
        // 留言函数
        function leaveMessage(string memory _content) public {
            require(bytes(_content).length > 0, "Message content cannot be empty");
            messages.push(Message(msg.sender, _content, block.timestamp));
            emit NewMessage(msg.sender, _content, block.timestamp);
        }
        // 获取所有留言
        function getMessages() public view returns (Message[] memory) {
            return messages;
        }
    }

    这个合约定义了一个Message结构体,一个存储留言的数组messages,以及两个核心函数:leaveMessage用于用户留言,getMessages用于获取所有留言。

编译智能合约

  1. 在Hardhat项目中,运行编译命令:
    npx hardhat compile

    编译成功后,你会在artifacts/contracts/MessageBoard.sol/目录下看到编译后的ABI(应用程序二进制接口)和字节码文件,ABI是前端与智能合约交互的桥梁。

部署智能合约

  1. scripts目录下,创建一个部署脚本deploy.js

    const hre = require("hardhat");
    async function main() {
      // 获取MessageBoard合约工厂
      const MessageBoard = await hre.ethers.getContractFactory("MessageBoard");
      // 部署合约
      const messageBoard = await MessageBoard.deploy();
      // 等待部署完成
      await messageBoard.deployed();
      console.log("MessageBoard deployed to:", messageBoard.address);
    }
    main()
      .then(() => process.exit(0))
      .catch((error) => {
        console.error(error);
        process.exit(1);
      });
  2. 配置Hardhat网络:在hardhat.config.js中,确保默认网络是Hardhat Network(通常默认配置即可)。

  3. 运行部署脚本:

    npx hardhat run scripts/deploy.js --network localhost

    执行成功后,你会看到输出的合约地址,这就是我们部署到本地测试网的留言板合约地址。请务必记下这个地址,前端需要用到它。

构建前端界面

  1. 在项目根目录下,创建一个src文件夹,用于存放前端代码。

  2. 初始化React应用(可选,也可以直接用HTML/CSS/JS):

    npx create-react-app frontend
    cd frontend
    npm install ethers
  3. frontend/src目录下,修改App.js或创建新的组件来构建界面:

    import React, { useState, useEffect } from 'react';
    import { ethers } from 'ethers';
    import MessageBoard from '../contracts/MessageBoard.json'; // 导入编译后的ABI
    function App() {
      const [account, setAccount] = useState(null);
      const [messageBoard, setMessageBoard] = useState(null);
      const [messages, setMessages] = useState([]);
      const [newMessage, setNewMessage] = useState('');
      // 初始化连接
      useEffect(() => {
        const init = async () => {
          if (window.ethereum) {
            try {
              // 请求账户访问
              const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
              setAccount(accounts[0]);
              // 创建provider和signer
              const provider = new ethers.providers.Web3Provider(window.ethereum);
              const signer = provider.getSigner();
              // 替换为你的合约部署地址
              const contractAddress = "0x..."; // 这里填入你部署的合约地址
              const messageBoardInstance = new ethers.Contract(contractAddress, MessageBoard.abi, signer);
              setMessageBoard(messageBoardInstance);
              // 获取初始留言
              const initialMessages = await messageBoardInstance.getMessages();
              setMessages(initialMessages);
            } catch (error) {
              console.error("Error connecting to MetaMask:", error);
            }
          } else {
            alert("Please install MetaMask!");
          }
        };
        init();
      }, []);
      // 留言功能
      const handleLeaveMessage = async () => {
        if (messageBoard && newMessage.trim() !== '') {
          try {
            const tx = await messageBoard.leaveMessage(newMessage);
            await tx.wait(); // 等待交易确认
            // 更新留言列表
            const updatedMessages = await messageBoard.getMessages();
            setMessages(updatedMessages);
            setNewMessage('');
          } catch (error) {
            console.error("Error leaving message:", error);
          }
        }
      };
      return (
        <div className="App">
          <h1>以太坊留言板</h1>
          {account ? (
            <p>当前账户: {account}</p>
          ) : (
            <p>请连接MetaMask</p>
          )}
          <div>
            <input
              type="text"
              value={newMessage}
              onChange={(e) => setNewMessage(e.target.value)}
              placeholder="输入你的留言"
            />
            <button onClick={handleLeaveMessage}>留言</button>
          </div>
          <div>
            <h2>留言列表:</h2>
            <ul>
              {messages.map((msg, index) => (
                <li key={index}>
                  <strong>{msg.author}:</strong> {msg.content} <em>({new Date(msg.timestamp * 1000).toLocaleString()})
本文由用户投稿上传,若侵权请提供版权资料并联系删除!