Ethereum Dapp Crash Course: Make an ERC20 token faucet + Frontend

2025-06-10

以太坊 Dapp 速成课程:制作 ERC20 代币水龙头 + 前端

在此处找到该项目的所有源代码链接

自 2016 年左右以来,以太坊智能合约开发已经可以学习。但如何真正构建一个全栈去中心化应用程序,则是另一回事。

这篇文章的灵感来自于 Nader Dabit关于 ETH 开发的精彩文章

Dapp 开发简史

Solidity 版本冲突、Truffle、Ganache、Web3.js 和测试网的难题,以及关于前端集成甚至基本设计原则的文档匮乏,使得全栈 DApp 开发变得岌岌可危。虽然上述工具(尤其是 Truffle!)为你的 DApp 开发之旅提供了一些绝佳的入门方法,但 ETH-dev 元宇宙的两位新成员的加入,让一切变得更加轻松。

hardhatethers.js

...

我想说,在过去的6到12个月里,启动并运行一个全栈去中心化应用程序实际上很有趣,而且并不难,而且不会让各种错误充斥你的终端。而且我发现,你可能遇到的任何错误都很容易解决。

Dapp 开发领域正在站稳脚跟,蓬勃发展。我们预计,未来几年,这一趋势将会持续增强。

如果您喜欢构建尖端技术,那么您来对地方了。

在开始这个速成课程之前,我建议您充分了解以太坊的工作原理、智能合约、交易、gas 费用,并熟悉 javascript 和 react。

在本教程结束时,你将拥有

  • 一个可共享 URL 上线的去中心化应用程序,连接到 Goreli 测试网
  • 了解 Dapp 开发框架和生命周期
  • 一个简单(但很棒)的 dapp
  • 你大吃一惊

让我们开始吧!

替代文本

我们的堆栈

react - 我们的客户端前端
react-bootstrap - 快速 css 组件样式
hardhat - 以太坊 / solidity 开发环境
ethers.js - 以太坊 / web 客户端库

其他工具

remix - 浏览器内置的 Solidity 开发环境
metamask - 我们的浏览器内置钱包,用于与我们的应用程序进行交互
openzeppelin contract一个安全且经过审计的智能合约 Solidity 代码库
chai - 一个用于运行测试的 JavaScript 断言库
waffle - 一个用于智能合约测试的库

infura.io - 一个 IPFS API,可将我们的应用程序连接到实时测试网
Goreli - 我们将使用的实时测试网
Github 和 Netlify - 用于托管我们的客户端 UI

它们如何组合在一起

安全帽开发环境

Hardhat 允许在本地运行区块链,以便在隔离环境中测试我们的应用程序。它允许我们在不使用实时网络的情况下编译、部署和测试 Solidity 智能合约。此外,还有大量专为 Hardhat 开发的实用插件

ethers.js

我们将导入到代码中的 JavaScript 库。它允许我们的客户端应用程序与我们将要部署到区块链上的智能合约进行通信。它通过生成包含 ABI 的 JSON 文件来实现这一点,ABI 充当 React 和智能合约之间的接口。

ABI 是以太坊原生术语,代表应用程序二进制接口。它基本上允许我们调用智能合约函数。

这里需要特别指出的是,我们需要 ABI 文件是因为以太坊使用 EVM(以太坊虚拟机)通过智能合约读写区块链数据。实际上,当我们编译智能合约代码时,安全帽会将其编译为字节码,并由 EVM 执行。它是区块链的底层计算层。

反应

这是 Facebook 开发的 JavaScript 框架,允许网站在同一个页面内实时渲染 HTML 元素,从而让像 Twitter 这样的复杂单页网站也能快速运行。建议你在开始本速成课程之前,先熟悉一下 React!

我们将结合 React 使用 ethers.js 库。这是一个强大的组合!

替代文本

反应引导

一个强大的 React 库,允许我们在 React 组件中使用 Bootstrap。使用它还可以帮助前端开发人员理解一些 React 的实用设计原则。

使用 React 的好处之一是,我们可以将我们的应用程序连接到 React 生态系统,轻松地引入我们可能想要使用的其他技术。

chaiwaffle 插件

我们将安装 hardhat waffle 插件,它带来了一个很好的测试库

我们的 Dapp - ERC20 代币水龙头

等等,我们又在做什么?我们将制作一个简单的单页应用程序,允许用户接收 100 FCT(水龙头代币)。

替代文本

水龙头可以用来获取测试网的虚拟以太币,用于我们的钱包开发。但是,如果我们想要一个水龙头来兑换我们自己的代币呢?

如果我们正在构建任何类型的 Dapp,那么有一个按钮允许用户接收我们的部分令牌可能会很有用,至少在我们仍在开发期间是这样。

我们将使用ERC20 代币标准作为我们的代币。

我们将向智能合约添加一个名为faucet()的函数,该函数允许用户接收 100 FCT。

用户将能够:

  • 获得 100 FCT
  • 检查他们的 FCT 余额
  • 将 FCT 发送到另一个地址(他们可以从 metamask 钱包中执行此操作,但我们无论如何都会将该功能添加到我们的 UI 中)

让我们开始吧

先决条件

  • Node.JS 已安装
  • Metamask 钱包作为浏览器扩展程序安装
  • 您根本不需要任何 ETH 即可参加此速成课程。

设置并安装依赖项

创建一个样板反应应用程序

npx create-react-app react-token-faucet
Enter fullscreen mode Exit fullscreen mode

进入你的项目目录并安装hardhatethers.js。你可以使用 NPM 或 Yarn。在同一行中,我们还添加了 waffle 插件。安装过程中你可能会看到一些 NPM 警告,不必担心。

npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers
Enter fullscreen mode Exit fullscreen mode

现在我们安装 react-bootstrap 库

npm install react-bootstrap bootstrap@4.6.0
Enter fullscreen mode Exit fullscreen mode

最后我们要安装 Open Zeppelin Lirbary

npm install @openzeppelin/contracts
Enter fullscreen mode Exit fullscreen mode

使用你选择的文本编辑器打开你的项目。你将看到默认的 create-react-app 文件夹。

在您的package.json文件中,您将看到我们安装的所有依赖项。

{
  "name": "react-token-faucet",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@nomiclabs/hardhat-ethers": "^2.0.2",
    "@nomiclabs/hardhat-waffle": "^2.0.1",
    "@openzeppelin/contracts": "^4.1.0",
    "@testing-library/jest-dom": "^5.12.0",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "bootstrap": "^4.6.0",
    "chai": "^4.3.4",
    "ethereum-waffle": "^3.3.0",
    "ethers": "^5.2.0",
    "hardhat": "^2.3.0",
    "react": "^17.0.2",
    "react-bootstrap": "^1.6.0",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

Enter fullscreen mode Exit fullscreen mode

/src中删除App.Tests.jslogo.svgsetupTests.js。我们不会使用任何这些文件,我们希望有一个干净的项目。

现在回到您的终端运行并初始化安全帽项目,通过初始化进入。

npx hardhat run
Enter fullscreen mode Exit fullscreen mode

现在将 .env 文件添加到您的项目中

touch .env
Enter fullscreen mode Exit fullscreen mode

在您的项目根目录中,您现在将看到添加到我们项目中的 hardhat 文件夹和文件,它们是:

hardhat.config.js - 项目配置
.gitignore - github 不应推送
/scripts/sample-script.js - 我们的部署脚本
/test/sample-test.js - 测试

我们需要编辑我们的.gitignore文件和我们的hardhat.config.js文件。

.gitignore

该文件包含出于安全原因我们不想推送到 github 的文件列表。

打开此文件并在#misc下添加.env

# misc
.env
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
Enter fullscreen mode Exit fullscreen mode

安全帽.config.js

该文件包含 hardhat 正确配置我们的项目所需的所有信息。

将您的安全帽配置文件更改为:

require("@nomiclabs/hardhat-waffle");
require('dotenv').config()

// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async () => {
  const accounts = await ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

/**
 * @type import('hardhat/config').HardhatUserConfig
 */
 module.exports = {
  paths: {
    artifacts: './src/artifacts',
  },

  networks: {
    hardhat: {
      chainId: 1337
    },
  },
  solidity: "0.8.3"
};

Enter fullscreen mode Exit fullscreen mode

第 2 行需要有一个 .env 文件。module.exports
包含了安全帽需要检查的大部分信息。

当我们编译和部署或 solidity 代码时, artifacts就是我们的 ABI 所包含的地方。

networks包含 Hardhat 需要了解的有关我们将代码部署到哪个网络的信息:以太坊主网、测试网还是本地网络。目前,我们将只使用我们的本地网络 Hardhat。注意:ChainId 属性需要设置为 1337,才能正确配置 Metamask。

最后将scripts/sample-script.js的文件名改为scripts/deploy.js。

水龙头智能合约

好的,现在我们将编写智能合约,将其部署到区块链并使用我们的 React 前端进行交互。

Remix IDE

如前所述,Remix 是一个浏览器内置的 Solidity 开发环境。我发现它是编写智能合约并在集成到我的项目之前进行测试的好方法。现在我们的项目已经设置完毕,我们将使用 Remix 来测试我们的智能合约。对于这门速成课程来说,使用 Remix IDE 可能有点冗长,但我认为有必要讲解一下。让我们来了解一下。前往

https://remix.ethereum.org/

在左侧的“合约”面板中,您将看到一些示例合约。点击“新建合约”图标即可创建新合约。

替代文本

创建一个名为FCTToken的新合约


pragma solidity ^0.8.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";

contract FCTToken is ERC20 {

    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        _mint(msg.sender, 10000 * (10 ** 18));
    }

    function faucet (address recipient , uint amount) external {
      _mint(recipient, amount);
    }
}

Enter fullscreen mode Exit fullscreen mode

这就是我们智能合约的全部代码!我们正在将 Open Zeppelin 库导入到我们的 Remix IDE 中。

当我们声明我们的合约与FCTToken的合约是ERC20时,我们的合约将继承开放的zeppelin ERC20代币的所有功能。

这些功能包括:

function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
Enter fullscreen mode Exit fullscreen mode

本速成课程不会深入探讨 Solidity 的细节,但如果您想更好地理解 ERC20 功能,那么值得查看 Open Zeppelin repo和文档。

我们代码的构造函数部分将使用部署时传递给它的值来初始化智能合约参数名称符号。这些值将是我们的代币名称及其符号,“Faucet”和“FCT”。

在构造函数中,我们调用_mint (一个继承的函数)来铸造 10,000 个代币。由于代币的基本单位,调用_mint时使用的数学运算必须自行实现

我们向这个智能合约水龙头添加了新功能,它接受两个参数*地址类型的接收者以及**uint类型的数量。

注意:Solidity 是一种静态类型语言,如果您熟悉 TypeScript,它遵循类似的原则。

现在让我们编译代码来测试一下。点击最左侧面板中的 Solidity 图标。

替代文本

现在单击左侧面板中的编译按钮。

替代文本

如果一切正常,您将看到 Remix 控制台运行编译器。

现在单击最左侧面板中的以太坊图标,在 remix 环境中部署我们的代码。

替代文本

我们可以看到我们的合约实例正在等待部署。点击“部署”。

替代文本

如果一切正常,您将在 Remix 控制台中看到一个绿色勾号。

现在我们应该在“已部署合约”下看到我们的智能合约实例。单击箭头图标将其展开。

替代文本

现在,您将看到智能合约中所有可用函数的列表。请记住,这包含我们从 Open Zeppelin Contracts 导入中继承的所有函数。(这真的帮助我在刚开始使用 Solidity 时直观地了解了智能合约函数!)

打开我们的水龙头功能。

替代文本

您将看到每个参数的输入,在我们的例子中是收件人金额

替代文本

在左侧面板顶部的“帐户”下,你会看到一个下拉菜单。这允许我们切换模拟用户帐户,每个帐户都加载了测试以太币。你当然应该尝试一下 Remix 来学习 Solidity。但现在我们将通过点击复制图标来复制当前帐户的地址。

替代文本

现在回到水龙头参数中,粘贴收件人的地址和 100 作为金额,然后单击交易

替代文本

我们运行并部署了一个智能合约函数!现在,为了检查它是否正常工作,请打开你的智能合约函数,并以你的地址作为参数调用balanceOf函数。

替代文本

在继续之前,值得注意的是橙色按钮的功能和蓝色按钮的功能之间的区别。

橙色函数将数据写入区块链,这算作一次交易,需要消耗 Gas。此操作不可更改。蓝色函数读取数据,这算作一次调用,此操作免费,并且不会更改区块链上的任何数据。

所以现在我们知道我们的智能合约正在运行,我们可以在我们的项目中安全地使用它。

在您的项目中的/contracts文件夹中删除那里的所有合约,并使用以下代码(我们刚刚测试过的代码)创建一个名为FCTToken.Sol的新合约。

pragma solidity ^0.8.3;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract FCTToken is ERC20 {

    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        _mint(msg.sender, 100000 * (10 ** 18));
    }

    function faucet (address recipient , uint amount) external {
      _mint(recipient, amount);
    }
}

Enter fullscreen mode Exit fullscreen mode

运行我们的安全帽本地区块链

在您的终端中,在您的项目目录中运行

npx hardhat node 
Enter fullscreen mode Exit fullscreen mode

您将看到 hard had 开始运行本地区块链。它将返回一个已加载测试 Eth 的地址列表。请保持此终端窗口运行,并在课程的剩余部分打开一个新的终端窗口。

与我们在 Remix 中部署智能合约的方式类似,我们现在将把 FCTToken 智能合约部署到我们的本地区块链。

打开你的脚本/deploy.js并将其更新为

const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();

  console.log(
    "Deploying contracts with the account:",
    deployer.address
  );

  const FCTToken = await hre.ethers.getContractFactory("FCTToken");
  const fctToken = await FCTToken.deploy("FCTToken", "TKN");

  await fctToken.deployed();

  console.log("Token deployed to:", fctToken.address);
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error);
    process.exit(1);
  });
Enter fullscreen mode Exit fullscreen mode

现在我们已经更新了部署脚本,我们可以编译和部署FCTtoken.sol

NB 编译器不接受 .Sol,文件名必须是 .sol,小写 S。

在新的终端窗口中,cd 进入您的项目并运行

npx hardhat compile

然后 -

npx hardhat run scripts/deploy.js --network localhost
Enter fullscreen mode Exit fullscreen mode

终端应该打印出类似

替代文本

注意:人类用户有钱包地址,智能合约也有。以太坊上的地址可以被视为用户/钱包以及智能合约的ID。

记下“Token Deployed To”地址,因为我们稍后会用到它。

太棒了!这样我们就把 FCTtoken.sol 合约部署到本地安全帽区块链了。

如果您还跟我在一起,那么现在是休息 10 分钟的好时机 ;)

React 前端

我们可以直接在终端上使用许多实用的命令行命令与合约进行交互。但在本速成课程中,我们将直接讲解 React。

我们的目标是创建一个包含几个按钮的网页。这些按钮将调用我们的智能合约函数。我们希望:

  • 水龙头按钮将 FCT 发送到用户钱包
  • 检查余额显示当前 FCT 用户余额的消息
  • 发送 FCT用户可以将 FCT 发送到另一个地址
  • 金额输入发送金额的输入
  • 地址输入收款人地址的输入

在我们的/src/app.css文件中,删除所有默认代码并将其替换为:


.App {
  text-align: center;
  background-color: rgba(252, 203, 250, 0.65);
  height: 100%;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.App-header {
  background-color: rgb(253, 204, 251);
  padding: 20px;
  color: white;
}

.App-intro {
  font-size: large;
}

Enter fullscreen mode Exit fullscreen mode

让我们清理一下App.js文件。首先

import './App.css';
import FCTToken from './artifacts/contracts/FCTToken.sol/FCTToken.json'

function App() {

  const Token = FCTToken;

  return (
    <div className="App">
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

现在在您的终端运行以启动您的本地主机

npm run start 
Enter fullscreen mode Exit fullscreen mode

这将在localhost:3000加载我们的空白页面,其中包含可爱的浅紫粉色。

替代文本

好吃

现在让我们进一步构建 App.js 组件。

import './App.css';
import FCTToken from './artifacts/contracts/FCTToken.sol/FCTToken.json'
import 'bootstrap/dist/css/bootstrap.min.css'
import { Container, Row, Col } from 'react-bootstrap'

function App() {

  const Token = FCTToken;

  return (
    <div className="App">
    <Container>
    <Row className="justify-content-md-center">
      <Col>
      <div>our faucet</div>
      </Col>
      <Col>
      <div> our send area</div>
      </Col>
    </Row>
    </Container>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

我们导入了一些 bootstrap-react 组件,并且刚刚勾勒出我们希望主要 UI 组件在页面上的位置。

如果您之前从未在 React 中实现过它们,请查看布局上漂亮的 bootstrap-react 文档页面。

每次对反应代码进行更改/保存更改时,您都应该看到页面重新加载。

让我们在代码中创建 Faucet 组件,方法是在第 22 行添加此代码片段

 <Faucet  tokenContract={Token}/>
Enter fullscreen mode Exit fullscreen mode

这将创建一个 React 组件并向其发送 prop Token。此变量包含我们在第 5 行导入的 ABI(还记得吗?)。

现在让我们编写水龙头组件的代码。

在你的终端运行

cd src 
mkdir components 
cd components 
touch Faucet.js 
Enter fullscreen mode Exit fullscreen mode

创建 Faucet.js 文件。React 组件的文件结构如下。

替代文本

这是我们的 Faucet.js 反应组件的代码。


import { useState } from 'react';
import { ethers } from 'ethers'
import Card from 'react-bootstrap/Card'
import Button from 'react-bootstrap/Button'

const tokenAddress = "{YOUR DEPLOYED TOKEN ADDRESS}"

const Faucet = (props) => {

  const [balance, setBalance] = useState()
  const [showBalance, setShowBalance] = useState(false)


  async function getBalance() {
    if (typeof window.ethereum !== 'undefined') {
      const [account] = await window.ethereum.request({ method: 'eth_requestAccounts' })
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const contract = new ethers.Contract(tokenAddress, props.tokenContract.abi, provider)
      const balance = await contract.balanceOf(account);
      console.log("Balance: ", balance.toString());
      setBalance(balance.toString());
      setShowBalance(true);
    }
  }

  async function faucet() {
    if (typeof window.ethereum !== 'undefined') {
      const account = await window.ethereum.request({ method: 'eth_requestAccounts' });
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      const contract = new ethers.Contract(tokenAddress, props.tokenContract.abi, signer);
      contract.faucet(account[0], 100);
    }
  }
    return (
        <div>
        <Card style={{background: "rgba(227, 104, 222, 0.71)"}}>
        <Card.Body>
        <Card.Subtitle>recieve faucet ERC20 to your wallet
        </Card.Subtitle><br></br>
        <div className="d-grid gap-2">
        <Button onClick={faucet}>get faucet token!</Button>
        <Button onClick={getBalance} variant="warning">check my balance</Button>   
        </div>
        </Card.Body>
        </Card>
        </div>
    )
}

export default Faucet
Enter fullscreen mode Exit fullscreen mode

在第 7 行,您需要将 tokenAddress 值替换为我们之前从终端获得的“Token Deployed To”地址。

上面的代码可能看起来有点笨重,但分解开来其实很简单。我们声明了两个异步函数getBalance()faucet()。这两个函数必须是异步函数,因为我们调用的是区块链中的智能合约,所以我们需要 JavaScript 来应对以太坊的挑战!

如果您不熟悉,请阅读 Javascript 中的异步编程,因为您将在 Dapp 开发中经常使用它。

在我们的函数中,我们检查用户是否正在运行 metamask,然后使用 ethers.js 库获取所需数据,并将数据赋值给局部变量。同样,这些数据可以通过 ABI 访问,我们在App.js中导入了 ABI ,并将其作为 prop 传递给Faucet.js

反应设计原则之美,与以太坊 ABI 一起流动!

呼!

好的,现在我们需要将我们可爱的组件导入到文件顶部的App.js中。

import Faucet from './components/Faucet.js'
Enter fullscreen mode Exit fullscreen mode

回到你的 localhost:3000 你应该会看到类似这样的内容...

替代文本

我们的 Faucet 组件周围呈现粉红色背景是因为我们将其包装在 react-bootstrap 组件中,并使用一些 CSS 样式对其进行了内联自定义。

使用变体属性设置不同颜色的按钮,您可以在此处阅读它们的工作原理

测试水龙头组件

让我们来体验一下我们的 UI。首先,我们需要设置 Metamask 钱包,以便它连接到我们的安全帽区块链节点。

“……不是另一个设置,”我听到你在虚空中尖叫……

当我们运行安全帽区块链节点时,终端会提供一份用于测试的地址和私钥列表。你的节点应该仍在运行。向上滚动,直到看到类似以下内容:

替代文本

我们可以使用其中任何一个账户将 Metamask 连接到本地区块链实例。为了清晰起见,请使用第一个账户。复制列表中第一个账户的私钥。

打开 Metamask,选择可用网络下拉菜单。连接到 localhost:8545,这是我们本地区块链的端口。

替代文本

现在转到导入帐户

替代文本

从你的终端粘贴第一个账户的私钥。账户连接后,你会看到你的账户里装满了假的测试ETH!

在我们的用户界面中单击获取余额

打开浏览器开发者控制台,您应该会看到此控制台日志。

替代文本

这是我们钱包里的FCT代币余额。我们铸造了合约,在我们的智能合约中,铸造者将获得全部供应。

在我们的用户界面中,单击获取水龙头令牌!

替代文本

Metamask 会要求您连接到该网站。然后,我们会在 Metamask 钱包中显示此交易以供确认。

替代文本

这显示了运行交易所需的 Gas 费用。显然,我们只是使用测试 Eth,但在主网上,这将花费实际的 Eth。

点击确认。

请记住,每次我们与智能合约交互时,如果我们更改存储在区块链中的数据,则算作一次交易。

现在,如果您点击“获取余额”,您应该会看到更新后的余额。

替代文本

您可以看到我们的余额已更新了 100 Wei。

将用户地址的余额作为只读调用获取,这不算作交易,因此不需要运行 gas。

让我们将 console.log 转换为一条消息,以便我们的 UI 动态更新。

在您的组件文件夹中创建一个新文件Message.js 。

替代文本

我们的消息反应组件的代码。

import Alert from 'react-bootstrap/Alert'

const Message = ({ balance }) => {
    return (
      <div>
      <Alert variant="info"> balance : {balance}</Alert>
      </div>
  )
}

export default Message
Enter fullscreen mode Exit fullscreen mode

我们从 Bootstrap 导入Alert组件,并传入balance属性。

回到Faucet.js文件,在我的文件的第 45 行添加以下代码。就在“获取余额”按钮下方

{ showBalance ? <Message balance={balance}/> : null }
Enter fullscreen mode Exit fullscreen mode

并将组件导入到代码顶部的Faucet.js文件中

import Message from './Message'
Enter fullscreen mode Exit fullscreen mode

现在,如果我们在 UI 中单击获取余额,我们将看到消息组件呈现到我们的页面上。

替代文本

现在让我们创建发送令牌组件

在我们的App.js文件中,新组件中有虚拟文本“我们的发送区域”

<TokenSend tokenContract={Token}/>
Enter fullscreen mode Exit fullscreen mode

我们再次将 TokenABI 作为 prop 传递给这个组件。

在组件文件夹中创建一个名为TokenSend.js的新文件

添加以下代码。


import { useState } from 'react';
import { ethers } from 'ethers'
import Card from 'react-bootstrap/Card'
import Button from 'react-bootstrap/Button'

const tokenAddress = "{YOUR DEPLOYED TOKEN ADDRESS}"

const TokenSend = (props) => {

  const [userAccount, setUserAccount] = useState()
  const [amount, setAmount] = useState()

  // request access to the user's MetaMask account
  async function requestAccount() {
    await window.ethereum.request({ method: 'eth_requestAccounts' });
  }

  async function sendCoins() {
  if (typeof window.ethereum !== 'undefined') {
    await requestAccount()
    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();
    const contract = new ethers.Contract(tokenAddress, props.tokenContract.abi, signer);
    const transation = await contract.transfer(userAccount, amount);
    await transation.wait();
    console.log(`${amount} Coins successfully sent to ${userAccount}`);
  }
}
    return (
        <Card style={{background: "rgba(227, 104, 222, 0.71)"}}>
        <Card.Body>
        <Card.Subtitle> send faucet to an address
        </Card.Subtitle>
        <br></br>
        <div className="d-grid gap-2">
        <input onChange={e => setUserAccount(e.target.value)} placeholder="Payee 0x address" />
        <input onChange={e => setAmount(e.target.value)} placeholder="Amount" />
        <Button onClick={sendCoins} variant="success">send </Button>
        </div>
        </Card.Body>
        </Card>
    )
}

export default TokenSend
Enter fullscreen mode Exit fullscreen mode

使用您部署的合约地址更新变量tokenAddress 。

最后回到你的App.js文件导入TokenSend.js组件。

import TokenSend from './components/TokenSend.js'
Enter fullscreen mode Exit fullscreen mode

您现在可以将代币发送给不同的钱包/用户。

在金额输入 10000000000000000000(等于 wei 中的一个完整令牌),然后从 hardhat 提供给我们的地址之一中添加一个地址。

点击发送。在我们的浏览器终端中确认 Metamask 中的交易,我们应该看到 console.log:

替代文本

您可以通过将不同的帐户导入到您的 metamask 并在它们之间切换来模拟多个用户,以测试功能。

做得好

我们现在有一个可以运行的去中心化应用程序。我们的前端运行在 localhost:3000 上,本地安全区块链运行在 localhost:8545 上。

现在我们将在真实网络上进行测试 - 真正的矿工将处理我们的交易!

准备实时测试网

我们将使用Goreli 测试网来部署我们的智能合约。

您需要将用于 Goreli 网络的测试 eth(或 GOeth)装入您的钱包。

首先,将您的 Metamask 钱包连接到 Goreli 测试网。

替代文本

我用的是这个,但如果你有谷歌的话还有其他的。

要连接到 Goreli,我们需要使用 API,Infura.io可以满足我们的要求,而且设置速度很快。

设置一个免费帐户并登录。进入仪表板并单击左侧面板中的以太坊图标。

现在单击页面右上角的创建新项目按钮。

替代文本

命名您的项目。

在您的项目设置中,将端点下拉框设置为Goreli

现在你想复制并保存你的

  • 项目编号
  • 端点 URL

这就是我们需要 Infura 提供的全部信息。

更改配置

打开您的hardhat.config.js文件并将其更新为

require("@nomiclabs/hardhat-waffle");
require('dotenv').config()

// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async () => {
  const accounts = await ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more

/**
 * @type import('hardhat/config').HardhatUserConfig
 */
 module.exports = {
  paths: {
    artifacts: './src/artifacts',
  },
  networks: {
    hardhat: {
      chainId: 1337
    },
    goreli: {
      url: "{YOUR END POINT URL}",
      accounts: [`0x${process.env.PRIVATE_KEY}`]

    }
  },
  solidity: "0.8.3"
};
Enter fullscreen mode Exit fullscreen mode

将gorlei.url属性更新为我们从 Infura 保存的端点 URL(没有花括号,只是一个字符串)。

在goreli.accounts中,我们引用了存储在 .env 文件中的变量 PRIVATE_KEY。该文件不会被推送到 GitHub,因为它存储在我们的 .gitignore 文件中。

要获取私钥,请打开您的 metamask,确保您在具有 Goreli 测试 eth 的帐户中。

点击三个按钮图标,进入“账户详情”。在弹出的窗口中,点击“导出私钥”。

您应该拥有不同的 metamask 帐户,用于开发和任何具有真实加密资产的东西。

替代文本

在您的.env文件中更新您的私钥。

PRIVATE_KEY="{YOUR-PRIVATE-KEY}"
Enter fullscreen mode Exit fullscreen mode

切勿在配置文件中暴露你的私钥,否则任何人都可以访问你的钱包并窃取你的资金

通过引用配置文件中的秘密变量,我们的私钥是安全的。

部署!

在你的终端运行

npx hardhat run scripts/deploy.js --network goreli
Enter fullscreen mode Exit fullscreen mode

如果一切正常,你会看到类似

替代文本

如果您在Goreli 的 etherscan上搜索已部署的合约地址,就会在区块链上看到它。在 etherscan 中,您可以查看有关该合约的有用信息,包括其总供应量,甚至原始源代码。

在我们测试我们的 UI 之前,我们需要更新我们的反应代码中的两行。

Faucet.js中,第 7 行。

const tokenAddress = "{YOUR-DEPLOYED-TOKEN-ADDRESS}"
Enter fullscreen mode Exit fullscreen mode

而在Token.js中,相同的局部变量名需要相同的地址。

现在我们的 UI 可以正常工作了。当我们点击“获取水龙头代币”“发送”时,我们会在 Goreli 测试网上调用智能合约的一个函数!

您可能需要等待一段时间才能在 Goreli 上挖掘交易,但您可以像检查任何正常交易一样在 Goreli etherscan 上检查交易状态。

很酷!

托管我们的 UI

如果我们可以通过单个 URL 共享我们的 Dapp,那不是很好吗?

是的。这就是我们要做的。

首先,创建一个新的仓库,并将你的项目推送到 master 分支。这里就不赘述了。我们的 .gitignore 文件已配置好,只将源代码推送到 Github。

推送到新的 Git 仓库后,前往netlify,创建新帐户或登录。

单击“从 git 新建站点”按钮。将 Netlify 与你的 Github 帐户连接,并选择你刚刚创建的 repo,以部署你的 UI。

Netlify 将计算任何 React 编译器警告和错误,因此请确保在部署之前 React 项目中没有警告。

就是这样!部署完成后,Netlify 将为您提供 Dapp 的 URL,并连接到 Goreli 测试网,以便您分享您的工作成果。

这是我的

概括

在本速成课程中,我尝试展示一个去中心化应用程序的完整开发周期。请注意,我们没有在这个项目中使用 Mocha 进行任何测试,这个话题留到以后再讨论。

欢迎自由分享和调整,创建您自己的 UI,并利用 UI 功能添加自定义智能合约功能。我期待看到您的作品。

我是一名 ETH/Solidity 开发人员,专攻前端集成和 UI。欢迎交流。

鏂囩珷鏉ユ簮锛�https://dev.to/richardmelko/ethereum-dapp-crash-course-make-an-erc20-token-faucet-frontend-2m43
PREV
Angular:如何构建像 Outlook 一样的全屏日历,首先让我们拥有 Angular 组件,其次让我们看看 CalendarDay 类是什么样子,第三让我们用所需的日期填充日历,第四让我们添加一些 HTML 和 CSS 来实际开始显示日历,第五现在是时候解释和展示块管道的代码了
NEXT
使用 Hooks 和 Context API 替换 Redux:如何