Web3 全栈指南

2022-11-07 10:33:23 浏览数 (1)

译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3]

也许你刚刚用solidity[4]、rust 编写了一个链上程序,但是如果没有一个很好的前端交互,几乎没有人可以使用它。

在这篇文章中,我们将了解如何在前端应用中,使用 HTML 和 JavaScript 与链上应用(智能合约或其他应用)交互。

并通过六种不同的方式,将你的 Metamask、Phantom 或其他区块链钱包地址连接到前端。最后,我们将看看有哪些流行的 Nextjs / React 前端软件包,可以辅助我们进行 web3 应用开发。

那么,让我们开始吧。

介绍

为了让 web3 体验友好,我们需要有用户友好的前端网站。全栈软件工程师在刚进入区块链领域可能会遇到一些挑战:

  1. 如何将Metamask[5](或Walletconnect[6], Phantom[7], 等等)连接到用户界面?
  2. 如何在网站上调用我的智能合约执行交易?
  3. 最好的实践都在做什么工具?

我在问自己这个问题时,看了几乎所有最流行的解决方案,并试图弄清楚应该向开发者推荐什么。因此,在这篇文章中,我们将了解到:

  1. 了解当我们想与区块链交互或向区块链发送交易时,浏览器中发生了什么。
  2. 看一下六种最流行的方法,来连接到我们的 web3 应用程序。
  3. 给出代码示例,并展示该领域所有最大的参与者在使用的哪些工具,这样我们也可以使用同样的工具。

如果你想看看现在一些专业的前端是什么样子,可以看一下Aave[8]或Uniswap[9]网站。

兴奋吗?我也是。我们开始吧。

如何将使用 Metamask 连接到智能合约

当然也可以是其他的钱包,如浏览器中的另一个钱包,如 Phantom、Walletconnect 等。

大多数区块链应用程序使用Hardhat[10]、Brownie[11]、DappTools[12]、Anchor[13]或Foundry[14]等框架构建(或者Remix[15] 工具)。而前端则使用在传统 web2 开发里学到的哪些东西:HTML、JavaScript、CSS,以及NextJS[16]、React[17]和Angular[18]等框架。

因此,如果你熟悉传统的网络开发,你就会走在别人的前面!

在浏览器中使用 Metamask

现在,跟上步伐,先安装Metamask[19],观看这个视频[20]以获得更深入的了解,安装完成之后,在页面右键单击,然后点击”检查(inspect)“:

右击屏幕,点击 检查(inspect)检查元素(inspect element)之后,可以看到像如下的内容:

他们是显示渲染网站页面的代码。然后,如果你点击顶部栏中的 sources,会看到如下图内容。(如果你找到sources,你可以点击>>按钮来显示更多选项)。

如果你在浏览器中安装了 Metamask,你会在左边看到一个 Metamask文件。如果你安装了 Phantom,你会看到一个 Phantom

他们是浏览器插件做的一些有趣的事情,它们自动 注入你的浏览器,并作为你所在网站的一部分显示出来,让网站有机会与它们交互。

每个浏览器中都有一个 window对象。我们可以通过点击console(控制台),进入 JavaScript 控制台[21], 输入 window,查看这个对象:

让我们继续输入window,看看我们得到什么。

我们在浏览器中看到了 JavaScript 的window对象。因为我们安装了Metamask,此时会有一个ethereum属性附加到window对象上。输入window.ethereum,看看返回了什么(如果你有 Phantom,你可以试试 window.solana)。

你会看到返回了一个对象! 如果你没有 Metamask,你会得到一个undefined。每个浏览器的钱包都会给 window 对象添加自己的属性,你通常可以在各自钱包的文档中找到它。这里是Metamask 文档[22],明确的介绍了window.ethereum

注意:在以前的版本中,为window.web3,后来改为window.ethereum

这就是所谓的区块链提供者(provider),那么我们为什么需要这个呢?

区块链连接与提供者(Provider)

每当我们想从区块链上读取数据,调用函数,或进行交易时,都需要连接到区块链网络。如果我们发送交易,还需要将签名的交易发送到一个区块链节点,这样它就可以将其发送到网络中的所有其他区块链节点。

你可能曾经在区块链应用程序中使用过Alchemy[23]、Infura[24]或Moralis Speedy Nodes[25]的RPC URL[26]。这些都是 ”节点即服务(node-as-a-service)“提供者,他们会提供我们一个 HTTP 端点来向区块链节点发送请求。加密货币钱包也是如此,Metamasks 内置有一个与区块链节点的连接。事实上,如果你去Metamask `network`标签[27],你可以看到 Metamask 正在使用的 RPC URL!

因此,每当我们用 Metamask 做一些事情,都会通过这个 RPC URL 进行 API 调用。

用 HTML 和 JavaScript 连接到加密货币钱包

我们将首先展示这一切是如何在 HTML 和 JavaScript 中完成的,然后我们将转向使用 Nextjs/React 例子。在我的 Github 这里[28]有一个使用 HTML/JavaScript 连接到加密货币钱包的完整例子,所有例子的列表也在我的 GitHub 里。[29]

首先,让我们创建一个标准的 HTML 文档,我们会给它一个连接(connect)按钮:

代码语言:javascript复制
<!DOCTYPE html>
<html>
  <head>
    <title>Javascript Test</title>
  </head><body>
    <button id="connectButton">Connect</button>
  </body>
</html>

可以给我们的按钮添加一些功能,添加一个script标签,并创建一个 JavaScript 函数,寻找window.ethereum,如果找到它,就发出连接请求:

代码语言:javascript复制
<!DOCTYPE html>
<head>
    <title>Javascript Test</title>
</head>
<body>
    <button id="connectButton" onclick="connect()">Connect</button>
</body>
<script>
async function connect() {
  if (typeof window.ethereum !== "undefined") {
    try {
      await window.ethereum.request({ method: "eth_requestAccounts" });
    } catch (error) {
      console.log(error);
    }
}}
</script>
</html>

这就是连接需要的全部代码。 eth_requestAccounts直接来自Metamask 文档[30]。如果你把文件命名为index.html并在浏览器中运行,你的 metamask 就会弹出要求连接:

发送交易

现在已经连接了 Metamask,是时候发送一个交易了。这时我们可以使用ethersjs[31]和web3js[32]等包来连接我们的提供者,然后发送一个交易。通常情况下,在 JavaScript 中执行一个函数/发送一个交易的 JavaScript 类似于这样:

代码语言:javascript复制
const etheres = require("ethers")

contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
const abi = // some big javascript ABI here...

const provider = new ethers.providers.JsonRpcProvider(/* alchemy or infura */)
const wallet = new ethers.Wallet(/* Private key */, provider)

const contract = new ethers.Contract(contractAddress, abi, wallet)
const contractWithSigner = contract.connect(wallet)
const transactionResponse = contract.someFunction()

在浏览器中发送交易的唯一区别是,我们将提供者改为window.ethereum,现在wallet将直接来provider。由于 Metamask 即是我们的提供者也是钱包(或签名者),代码将看起来像这样:

代码语言:javascript复制
const etheres = require("ethers")

contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
const abi = // some big javascript ABI here...

const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner();

const contract = new ethers.Contract(contractAddress, abi, signer)
const contractWithSigner = contract.connect(wallet)
const transactionResponse = contract.someFunction()

你会注意到,只有中间的两行改变了,现在从window.ethereum获得钱包,我们的签名者(signer)来自提供者(即 metamask)。

现在,这里有一个问题。我们的浏览器无法识别require(有时import也有问题),所以需要添加一些包来帮助我们。

因为我不希望这里变成一个介绍前端的文章,你可以参看我的html-js-ethers-connect[33]的例子,它向我们展示了如何自己运行示例。你只需要安装以下东西就可以了:

  • Git[34]
  • NodeJS[35]
  • Yarn[36]
  • 以及Metamask[37]

然后,你可以按照README.md[38]中的说明进行初始化,用纯 HTML 和 JavaScript 做一个完整的例子,在浏览器中发送交易!

你将拥有一个与智能合约一起工作的简约的前端!

5 个最佳前端 Web3 的实践

没有特别的顺序

现在,让我们开始为全栈应用提供所需的工具。这些配置将包括:

  1. 如何初始化
  2. 极简的演示
  3. 真实世界的例子

你可以选择最适合你的那一个! 我们用NextJS[39]来做这些工作,因为ReactJS[40]是目前地球上最流行的前端框架,而 NextJS 是建立在它之上的,在我看来,它比原始的 ReactJS 更方便使用。然而,你 100%可以用 Angular、Svelte 或其他方式工作。

你可以找到我所有的简约代码示例full-stack-web3-metamask-connectors[41]仓库,其中链接出所有的演示。

初始化一个基本的 NextJS 项目

为了方便入门,所有这些项目都将从一个基本的 NextJS 项目开始。需要安装Node[42]、Git[43]和Yarn[44]才能继续。你还可以跟随nextjs 入门文档[45]

运行以下命令:

代码语言:javascript复制
yarn create next-app full-stack-web3
cd full-stack-web3

现在有了一个基本的项目框架,现在可以运行yarn dev,看看现在的网站会是什么样子。最后,删除所有开始时的 示例代码,进入index.js文件,删除所有内容,仅保留:

代码语言:javascript复制
export default function Home() {
  return <div>Hi</div>;
}

现在前端就显示一个 Hi

设置本地 Hardhat 区块链和合约

现在,由于我们要测试函数交互,因此需要一个区块链来发送交易,以及相应的智能合约。代码已经为准备好了,在代码库hardhat-simple-storage GitHub[46]。你可以按照README.md来进行设置,或者新开一个命令终端(与前端不同的终端)运行以下程序。

代码语言:javascript复制
git clone https://github.com/PatrickAlphaC/hardhat-simple-storage
cd hardhat-simple-storage
yarn
yarn hardhat node

此时会启动一个本地区块链,给你一些临时私钥(账号),可用于部署 SimpleStorage合约,合约有一个 store函数。它接收一个uint256 _favoriteNumber作为输入参数,并将该数字存储到一个公共变量中。在SimpleStorage.sol文件中可以查看该合约代码。

用本地区块链设置你的 MetaMask

现在,要将 Metamask 连接到我们的本地区块链。这样就可以快速发送交易和测试。本地区块链和真实的区块链类似,但这个区块链是我们可以控制的。如果你愿意,你也可以使用测试网,跳过这一步,但你必须等待很长的时间来处理交易,这是没有人愿意的。

在区块链节点运行的终端,你会看到一个类似的输出:Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/。这就是 RPC URL,类似于 Alchemy。

现在,在 Metamask 中(请永远不要使用有真实资金的 Metamask 进行开发。最好创建一个新的浏览器账号配置(Profile)或下载另一个有 Metamask 插件的浏览器)点击顶部的网络按钮,然后 添加网络(Add Network)

按如下内容设置它,然后点击保存,然后确保你切换到该网络(在网络下拉列表中选择刚设置的网络)。

现在,点击右上方的大圆圈(账号),然后点击 导入账户(import account)

然后从 yarn hardhat node命令的输出中添加一个私钥。之后,你应该看到一个账户,在本地网络上,并且有一些测试 ETH。Metamask 应该看起来像这样:

然后我们就可以开始了 :)

重要提示:如果你遇到了 nonce被关闭的问题,或者交易不能正常发送。在 metamask 中,去右上方的圆圈->设置->高级->重置账户。就可以消除 nonce 的问题。

使用原始 Ethers

完整代码在这里[47]

最简单的方法是使用一些你已经熟悉的工具,比如 Ethers,我们可以从复制粘贴在 HTML 设置中的内容到index.js文件中:

代码语言:javascript复制
import styles from "../styles/Home.module.css";
import { ethers } from "ethers";
import { useEffect, useState } from "react";
export default function Home() {
  const [isConnected, setIsConnected] = useState(false);
  const [hasMetamask, setHasMetamask] = useState(false);
  const [signer, setSigner] = useState(undefined);
useEffect(() => {
    if (typeof window.ethereum !== "undefined") {
      setHasMetamask(true);
    }
  });
async function connect() {
    if (typeof window.ethereum !== "undefined") {
      try {
        await ethereum.request({ method: "eth_requestAccounts" });
        setIsConnected(true);
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        setSigner(provider.getSigner());
      } catch (e) {
        console.log(e);
      }
    } else {
      setIsConnected(false);
    }
  }
async function execute() {
    if (typeof window.ethereum !== "undefined") {
      const contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
      const abi = [
        {
          inputs: [
            {
              internalType: "string",
              name: "_name",
              type: "string",
            },
            {
              internalType: "uint256",
              name: "_favoriteNumber",
              type: "uint256",
            },
          ],
          name: "addPerson",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "string",
              name: "",
              type: "string",
            },
          ],
          name: "nameToFavoriteNumber",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          name: "people",
          outputs: [
            {
              internalType: "uint256",
              name: "favoriteNumber",
              type: "uint256",
            },
            {
              internalType: "string",
              name: "name",
              type: "string",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [],
          name: "retrieve",
          outputs: [
            {
              internalType: "uint256",
              name: "",
              type: "uint256",
            },
          ],
          stateMutability: "view",
          type: "function",
        },
        {
          inputs: [
            {
              internalType: "uint256",
              name: "_favoriteNumber",
              type: "uint256",
            },
          ],
          name: "store",
          outputs: [],
          stateMutability: "nonpayable",
          type: "function",
        },
      ];
      const contract = new ethers.Contract(contractAddress, abi, signer);
      try {
        await contract.store(42);
      } catch (error) {
        console.log(error);
      }
    } else {
      console.log("Please install MetaMask");
    }
  }
  return (
    <div>
      {hasMetamask ? (
        isConnected ? (
          "Connected! "
        ) : (
          <button onClick={() => connect()}>Connect</button>
        )
      ) : (
        "Please install metamask"
      )}
{isConnected ? <button onClick={() => execute()}>Execute</button> : ""}
    </div>
  );
}

为此,我们添加了一些额外的功能,以便在连接或用户没有 Metamask 时显示 请安装Metamask已连接。你还会看到像useStateuseEffect这样的命令,这些被称为 React Hooks,你可以从这个Fireship 视频[48]或react docs.[49]中了解它们的全部内容。虽然没有它们,这个应用也可以正常工作,只是我们无法在渲染之间保存应用的状态。

优点

  • 直接使用 Ethers 对 UI 进行最精细的控制

缺点

  • 我们必须写很多自己的代码,包括Contexts[50]
  • 如果支持更多的钱包连接会比较麻烦。

使用示例

Nader Dabit Explainer[51]

另外,在下面的例子中,我打算从另一个文件中导入abi,这样就不会让文章的内容臃肿了。

使用 Web3Modal

完整代码在这里[52]

将基于 EVM 的区块链应用程序连接到钱包的另一种最流行的方式是使用Walletconnect[53]。我将要展示的所有例子(包括原始 Ethers 的例子)都可以连接到 Walletconnect(而且应该连接),使用 Web3Modal 并不是唯一可选的工具。Walletconnect 团队成员创建的创建了这个奇妙的Web3Modal[54]工具,它允许使用一个框架来连接到任何 Provider,包括Ledger[55]、WalletConnect、Torus[56]、Coinbase Wallet[57],等等。

我们只需要导入这个包,之后index.js可能看起来像这样:

代码语言:javascript复制
import styles from "../styles/Home.module.css";
import Web3Modal from "web3modal";
import { useState, useEffect } from "react";
import { ethers } from "ethers";
import WalletConnectProvider from "@walletconnect/web3-provider";
import { abi } from "../constants/abi";
let web3Modal;
const providerOptions = {
  walletconnect: {
    package: WalletConnectProvider, // required
    options: {
      rpc: { 42: process.env.NEXT_PUBLIC_RPC_URL }, // required
    },
  },
};
if (typeof window !== "undefined") {
  web3Modal = new Web3Modal({
    cacheProvider: false,
    providerOptions, // required
  });
}
export default function Home() {
  const [isConnected, setIsConnected] = useState(false);
  const [hasMetamask, setHasMetamask] = useState(false);
  const [signer, setSigner] = useState(undefined);
useEffect(() => {
    if (typeof window.ethereum !== "undefined") {
      setHasMetamask(true);
    }
  });
async function connect() {
    if (typeof window.ethereum !== "undefined") {
      try {
        const web3ModalProvider = await web3Modal.connect();
        setIsConnected(true);
        const provider = new ethers.providers.Web3Provider(web3ModalProvider);
        setSigner(provider.getSigner());
      } catch (e) {
        console.log(e);
      }
    } else {
      setIsConnected(false);
    }
  }
async function execute() {
    if (typeof window.ethereum !== "undefined") {
      const contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
      const contract = new ethers.Contract(contractAddress, abi, signer);
      try {
        await contract.store(42);
      } catch (error) {
        console.log(error);
      }
    } else {
      console.log("Please install MetaMask");
    }
  }
return (
    <div>
      {hasMetamask ? (
        isConnected ? (
          "Connected! "
        ) : (
          <button onClick={() => connect()}>Connect</button>
        )
      ) : (
        "Please install metamask"
      )}
{isConnected ? <button onClick={() => execute()}>Execute</button> : ""}
    </div>
  );
}

你会看到,我们设置了一些providerOptions来告诉前端要支持哪些钱包,以及我们要支持哪些链以及需要设置一个NEXT_PUBLIC_RPC_URL,它指向一个 RPC_URL 来连接到区块链。如果我们使用 walletconnect,我们实际上不使用用户的 metamasks 的内置区块链节点。

优点

  • 易于整合多个钱包
  • Ethers 很好集成

缺点

  • 仍然没有内置的上下文组件

使用示例

  • Web3Modal-Example[58]
  • Scaffold-ETH[59]
  • create-eth-app[60]

如果你想看看 Web3Modal、区块链等的一些前沿的前端使用,可以查看 Scaffold-ETH。这是一个了不起的学习工具,由Austin Griffith[61]编写,你可以用来解构一些最佳实践。

Moralis

完整代码在这里[62]

Moralis(或者更具体地说,react-moralis[63])是第一个包含上下文管理组件的软件包,它是非常有用的。它允许整个应用在组件之间轻松地共享状态,这是必要的,因为我们需要传递 Metamask 的授权。

Moralis 是由Ivan on Tech[64]及其团队创建,不仅可以帮助开发者连接到 Metamask,还可以帮助开发其他后端系统(全栈应用可能需要)。Etherscan[65]和Opensea[66]都是 web3 应用程序的例子,它们仍然需要后台和数据库。为什么呢?因为很多时候,你想添加大量的功能,在链上做起来会花费太多 Gas!所以你仍然想有一个后台和数据库。

因此,你仍然让智能合约做主要工作,而 Moralis 可以做所有围绕它的一些工作。下面是使用 Moralis 的代码:

代码语言:javascript复制
import styles from "../styles/Home.module.css";
import { useMoralis, useWeb3Contract } from "react-moralis";
import { abi } from "../constants/abi";
import { useState, useEffect } from "react";
export default function Home() {
  const [hasMetamask, setHasMetamask] = useState(false);
  const { enableWeb3, isWeb3Enabled } = useMoralis();
  const { data, error, runContractFunction, isFetching, isLoading } =
    useWeb3Contract({
      abi: abi,
      contractAddress: "0x5FbDB2315678afecb367f032d93F642f64180aa3",   // your contract address here
      functionName: "store",
      params: {
        _favoriteNumber: 42,
      },
    });
useEffect(() => {
    if (typeof window.ethereum !== "undefined") {
      setHasMetamask(true);
    }
  });
return (
    <div>
      {hasMetamask ? (
        isWeb3Enabled ? (
          "Connected! "
        ) : (
          <button onClick={() => enableWeb3()}>Connect</button>
        )
      ) : (
        "Please install metamask"
      )}
{isWeb3Enabled ? (
        <button onClick={() => runContractFunction()}>Execute</button>
      ) : (
        ""
      )}
    </div>
  );
}

你会看到 Moralis 带有强大的 Hook 函数,如useWeb3Contract,使获得状态和与合约交互更加容易,而且不需要 ethers。

Moralis 还提供的enableWeb3函数代替了自己编写的connect函数。

此外,在_app.js中,需要用一个 Context 提供者来包装整个应用程序:

代码语言:javascript复制
import "../styles/globals.css";
import { MoralisProvider } from "react-moralis";

function MyApp({ Component, pageProps }) {
  return (
    <MoralisProvider initializeOnMount={false}>
      <Component {...pageProps} />
    </MoralisProvider>
  );
}

export default MyApp;

Morlais 有内置的属性选项,例如:可以用数据库设置前端,然而,如果你只想使用钩子和函数,你可以把initializeOnMount设置为 false,等将来需要时才设置服务器

优点

  • 有上下文提供者
  • 内置与智能合约交互功能
  • 可以选择引入后端,以获得更丰富的前端功能

缺点

  • 必须手动添加自己的钱包

真实案例

  • 以太坊 Boilerplate[67]

Web3-React

完整代码在这里[68]

Uniswap 工程负责人 Noah Zinsmeister 和朋友们建立了一个优秀的软件包,叫做web3-react[69]。这是被Uniswap[70]、Aave[71]和Compound[72]等顶级项目最广泛使用的包之一。它还包含了一个上下文组件管理器和一些令人难以置信的强大的 Hook 函数,让你可以直接上手并开始工作,还内置了一些 web3 钱包连接。

以下是index.js修改后的代码:

代码语言:javascript复制
import styles from "../styles/Home.module.css";
import { useWeb3React } from "@web3-react/core";
import { InjectedConnector } from "@web3-react/injected-connector";
import { abi } from "../constants/abi";
import { useState, useEffect } from "react";
import { ethers } from "ethers";
export const injected = new InjectedConnector();
export default function Home() {
  const [hasMetamask, setHasMetamask] = useState(false);
useEffect(() => {
    if (typeof window.ethereum !== "undefined") {
      setHasMetamask(true);
    }
  });
const {
    active,
    activate,
    chainId,
    account,
    library: provider,
  } = useWeb3React();
async function connect() {
    if (typeof window.ethereum !== "undefined") {
      try {
        await activate(injected);
        setHasMetamask(true);
      } catch (e) {
        console.log(e);
      }
    }
  }
async function execute() {
    if (active) {
      const signer = provider.getSigner();
      const contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
      const contract = new ethers.Contract(contractAddress, abi, signer);
      try {
        await contract.store(42);
      } catch (error) {
        console.log(error);
      }
    } else {
      console.log("Please install MetaMask");
    }
  }
return (
    <div>
      {hasMetamask ? (
        active ? (
          "Connected! "
        ) : (
          <button onClick={() => connect()}>Connect</button>
        )
      ) : (
        "Please install metamask"
      )}
{active ? <button onClick={() => execute()}>Execute</button> : ""}
    </div>
  );
}

_app.js代码:

代码语言:javascript复制
import "../styles/globals.css";
import { Web3ReactProvider } from "@web3-react/core";
import { Web3Provider } from "@ethersproject/providers";
const getLibrary = (provider) => {
  return new Web3Provider(provider);
};
function MyApp({ Component, pageProps }) {
  return (
    <Web3ReactProvider getLibrary={getLibrary}>
      <Component {...pageProps} />
    </Web3ReactProvider>
  );
}
export default MyApp;

正如你所看到的,我们仍然使用 ethers 与智能合约交互,但我们使用 Hook 函数来启用 Metamask 和任何其他想要的钱包 Provider

优点

  • 上下文提供者
  • 内置与智能合约交互的功能
  • 内置钱包连接

缺点

  • 不像 web3modal 那样容易设置钱包
  • 需要编写或使用自己的 Hook 来与智能合约交互。

真实案例

  • Web3 React 示例[73]
  • Aave[74]
  • Uniswap[75]

使用 Dapp

完整代码的代码在这里[76]

Ethworks 和最流行的测试框架 waffle[77] , 他们背后是同一个团队,waffle 被hardhat[78]使用。现在他们又做了一个类似 moralis 的框架,你可以利用所有的 Hooks 和工具来构建一个前端,还包括一个上下文提供者。

下面是使用 Ethworks 后index.js 的代码:

代码语言:javascript复制
import styles from "../styles/Home.module.css";
import { useEthers, useContractFunction } from "@usedapp/core";
import { useState, useEffect } from "react";
import { ethers } from "ethers";
import { abi } from "../constants/abi";
export default function Home() {
  const { activateBrowserWallet, account } = useEthers();
  const [hasMetamask, setHasMetamask] = useState(false);
useEffect(() => {
    if (typeof window.ethereum !== "undefined") {
      setHasMetamask(true);
    }
  });

async function connect() {
    await activateBrowserWallet();
  }
  const contractAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
  const contract = new ethers.Contract(contractAddress, abi);
const { send, state } = useContractFunction(contract, "store", {
    transactionName: "store",
  });
useEffect(() => {
    console.log(`State: ${state.status}`);
  }, [state]);
return (
    <div>
      {hasMetamask ? (
        account ? (
          "Connected! "
        ) : (
          <button onClick={() => connect()}>Connect</button>
        )
      ) : (
        "Please install metamask"
      )}
{account ? <button onClick={() => send(42)}>Execute</button> : ""}
    </div>
  );
}

_app.js如下:

代码语言:javascript复制
import "../styles/globals.css";
import { DAppProvider } from "@usedapp/core";
const config = {
  multicallAddresses: ["0x5FbDB2315678afecb367f032d93F642f64180aa3"],
};
function MyApp({ Component, pageProps }) {
  return (
    <DAppProvider config={config}>
      <Component {...pageProps} />
    </DAppProvider>
  );
}
export default MyApp;

向应用程序传递参数,用于配置如:支持的区块链和其他连接属性。与 Moralis 类似,useDapp带有activateBrowserWallet功能,用来激活 metamask/浏览器钱包,以及像useContractFunction这样的 hook 函数,与智能合约交互(你不必使用 ethers)。

优点

  • 上下文提供者
  • 内置智能合约交互功能

缺点

  • 不像 web3modal 那样容易设置钱包
  • 没有内置数据库的选项

真实案例

  • defi-stake-yield-brownie[79]

小结

每个工具都有其各自的优缺点,你可以根据自己的喜好、醒目的需求进行选择。

编码愉快!


本翻译由 Duet Protocol[80] 赞助支持。

原文:https://betterprogramming.pub/everything-you-need-to-know-about-fullstack-web3-94c0f1b18019

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

翻译小组: https://learnblockchain.cn/people/412

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

solidity: https://learnblockchain.cn/docs/solidity/

[5]

Metamask: https://metamask.io/

[6]

Walletconnect: https://walletconnect.com/

[7]

Phantom: https://phantom.app/

[8]

Aave: https://app.aave.com/#/dashboard

[9]

Uniswap: https://app.uniswap.org/#/swap?chain=mainnet

[10]

Hardhat: https://hardhat.org/

[11]

Brownie: https://eth-brownie.readthedocs.io/en/stable/

[12]

DappTools: https://medium.com/@patrick.collins_58673/how-to-use-dapptools-code-like-makerdao-fed9909d055b

[13]

Anchor: https://project-serum.github.io/anchor/getting-started/introduction.html

[14]

Foundry: https://github.com/gakonst/foundry

[15]

Remix: https://remix.ethereum.org/

[16]

NextJS: https://nextjs.org/docs/api-reference/create-next-app

[17]

React: https://reactjs.org/

[18]

Angular: https://angular.io/

[19]

Metamask: https://metamask.io/

[20]

观看这个视频: https://www.youtube.com/watch?v=Af_lQ1zUnoM

[21]

JavaScript控制台: https://javascript.info/debugging-chrome#console

[22]

Metamask文档: https://docs.metamask.io/guide/mobile-best-practices.html#the-provider-window-ethereum

[23]

Alchemy: https://alchemy.com/?r=7d60e34c-b30a-4ffa-89d4-3c4efea4e14b

[24]

Infura: https://infura.io/

[25]

Moralis Speedy Nodes: https://moralis.io/speedy-nodes/

[26]

RPC URL: https://eth.wiki/json-rpc/API

[27]

Metamask network 标签: https://metamask.zendesk.com/hc/en-us/articles/360056196151-Using-custom-networks-with-MetaMask

[28]

我的Github这里: https://github.com/PatrickAlphaC/html-js-ethers-connect

[29]

也在我的GitHub里。: https://github.com/PatrickAlphaC/full-stack-web3-metamask-connectors

[30]

Metamask文档: https://docs.metamask.io/guide/rpc-api.html#table-of-contents

[31]

ethersjs: https://learnblockchain.cn/docs/ethers.js/

[32]

web3js: https://learnblockchain.cn/docs/web3.js/

[33]

html-js-ethers-connect: https://github.com/PatrickAlphaC/html-js-ethers-connect/tree/7fd43da59ff0c6ba4cf2c3dae0395bc6b8df03ad

[34]

Git: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git

[35]

NodeJS: https://nodejs.org/en/

[36]

Yarn: https://classic.yarnpkg.com/lang/en/docs/install/

[37]

Metamask: https://metamask.io/

[38]

README.md: https://github.com/PatrickAlphaC/html-js-ethers-connect

[39]

NextJS: https://nextjs.org/

[40]

ReactJS: https://reactjs.org/

[41]

full-stack-web3-metamask-connectors: https://github.com/PatrickAlphaC/full-stack-web3-metamask-connectors

[42]

Node: https://nodejs.org/en/download/

[43]

Git: https://git-scm.com/downloads

[44]

Yarn: https://classic.yarnpkg.com/en/docs/cli/install/

[45]

nextjs入门文档: https://nextjs.org/docs/getting-started

[46]

hardhat-simple-storage GitHub: https://github.com/PatrickAlphaC/hardhat-simple-storage

[47]

完整代码在这里: https://github.com/PatrickAlphaC/nextjs-ethers-metamask-connect

[48]

Fireship视频: https://www.youtube.com/watch?v=TNhaISOUy6Q

[49]

react docs.: https://reactjs.org/docs/hooks-overview.html

[50]

Contexts: https://reactjs.org/docs/context.html

[51]

Nader Dabit Explainer: https://dev.to/dabit3/the-complete-guide-to-full-stack-ethereum-development-3j13

[52]

完整代码在这里: https://github.com/PatrickAlphaC/nextjs-ethers-metamask-connect

[53]

Walletconnect: https://walletconnect.com/

[54]

Web3Modal: https://github.com/Web3Modal/web3modal

[55]

Ledger: https://www.ledger.com/

[56]

Torus: https://app.tor.us/

[57]

Coinbase Wallet: https://www.coinbase.com/wallet

[58]

Web3Modal-Example: https://github.com/ChangoMan/web3modal-example

[59]

Scaffold-ETH: https://github.com/scaffold-eth/scaffold-eth

[60]

create-eth-app: https://github.com/paulrberg/create-eth-app

[61]

Austin Griffith: https://austingriffith.com/

[62]

完整代码在这里: https://github.com/PatrickAlphaC/nextjs-moralis-metamask-connect

[63]

react-moralis: https://github.com/MoralisWeb3/react-moralis

[64]

Ivan on Tech: https://www.youtube.com/channel/UCrYmtJBtLdtm2ov84ulV-yg

[65]

Etherscan: https://etherscan.io/

[66]

Opensea: https://opensea.io/

[67]

以太坊 Boilerplate: https://github.com/ethereum-boilerplate/ethereum-boilerplate

[68]

完整代码在这里: https://github.com/PatrickAlphaC/nextjs-web3-react-metamask-connect/tree/e9fd7e1c1f78441bc25347c37f581170aab14c40

[69]

web3-react: https://github.com/NoahZinsmeister/web3-react

[70]

Uniswap: https://uniswap.org/

[71]

Aave: https://aave.com/

[72]

Compound: https://compound.finance/

[73]

Web3 React 示例: https://github.com/NoahZinsmeister/web3-react/tree/main/packages/example

[74]

Aave: https://github.com/aave/aave-ui

[75]

Uniswap: https://github.com/Uniswap/interface

[76]

完整代码的代码在这里: https://github.com/PatrickAlphaC/nextjs-usedapp-metamask-connect

[77]

waffle: https://github.com/EthWorks/Waffle

[78]

hardhat: https://hardhat.org/

[79]

defi-stake-yield-brownie: https://github.com/PatrickAlphaC/defi-stake-yield-brownie

[80]

Duet Protocol: https://duet.finance/?utm_souce=learnblockchain

0 人点赞