如何使用 Gas API 和 Next.js 构建简单的 Gas 追踪应用

了解如何利用 MetaMask Gas API、Next.js 和 ShadcnUI 构建一个简单的 Gas 追踪应用。

8 分钟阅读
如何使用 Gas API 和 Next.js 构建简单的 Gas 追踪应用

"Gas"是指衡量执行操作(例如进行交易或运行智能合约)所需计算量的单位。它类似于汽车的燃料——是网络处理和验证操作的必要条件。以太坊上的每笔交易都需要一定数量的 gas,具体数量由交易的复杂程度决定。用户以 Gwei(1 Gwei = 十亿分之一以太币)为单位设置 gas 价格,代表他们愿意为每单位 gas 支付的以太币数量。

了解 gas 价格对于区块链网络至关重要,它帮助用户管理交易成本。掌握当前 gas 价格,用户可以选择最经济的时机发起交易,并确定交易速度。了解 gas 价格对于防止交易失败、规划预算、理解网络拥堵状况以及做出明智的投资决策同样不可或缺。

MetaMask Gas API

MetaMask Gas API 通过 Infura 提供,是一款专为以太坊虚拟机(EVM)兼容网络提供实时 gas 价格信息而设计的专业工具。它作为预言机运行,提供在这些网络上执行操作或交易所需计算成本的最新数据。该 API 赋能开发者构建高级 gas 估算功能,从而降低后端交易操作的成本,或提升用户界面体验。

在本教程中,我们将学习如何使用 Gas API、Next.js 和 ShadcnUI 构建一个 Gas 追踪应用。该应用将使 dapp 用户能够根据其交易优先级获取推荐的 gas 价格,从而确保这些交易高效地被纳入区块链区块中。

前提条件

配置 Next.js + ShadcnUI

首先,确保您的机器上已安装 Node.js。完成 Node.js 的配置后,打开终端并执行以下命令,启动一个新的 Next.js 应用:

npx create-next-app@latest

执行命令后,不仅会出现若干提示,还会在您指定的项目名称下生成一个新目录——我使用的是 gastracker-app,从而建立 Next.js 的基础结构并安装必要的依赖项。现在,进入您的项目目录:

npx create-next-app@latest
✔ What is your project named? … gastracker-app
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
复制

进入新项目目录后,使用以下命令以开发模式启动 Next.js 应用。然后,您可以在浏览器中访问 http://localhost:3000 来浏览您的应用。

cd gastracker-app
npm run dev
复制

构建用户界面

我们的应用将使用一个组件库。首先安装 ShadcnUI:

npx shadcn-ui@latest init

安装过程中,系统将引导您通过以下提示配置 components.json 文件:

Would you like to use TypeScript (recommended)? no / yes
Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Where is your global CSS file? › › app/globals.css
Do you want to use CSS variables for colors? › no / yes
Where is your tailwind.config.js located? › tailwind.config.js
Configure the import alias for components: › @/components
Configure the import alias for utils: › @/lib/utils
Are you using React Server Components? › no / yes
复制

完成上述步骤后,我们还需安装 Shadcn UI 的 Card 组件:

npx shadcn-ui@latest add card

在本教程中,我们将重点使用 Shadcn UI 的 Card 组件。如需了解更多关于这些组件的信息,请访问 Shadcn UI 官网。前端配置完成后,我们就可以开始使用 Gas API 了。

在根目录中,创建一个名为 .env 的文件,用于存储以下凭据:

INFURA_API_KEY=
INFURA_API_KEY_SECRET=
复制

请确保从您的 Infura 控制台获取 API_KEY 和 API_KEY_SECRET。务必避免将 API 密钥推送到 GitHub。在根目录中,检查 .gitignore 文件,确认其中包含必要的内容。

# Ignore environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
复制

我们还需要安装 axios 和 dotenv 包:

npm install axios
npm install dotenv
复制

现在,在 gastracker-app 的根目录中创建一个名为 'index.js' 的文件,并将以下代码复制到其中:

const axios = require("axios");
require("dotenv").config();

const Auth = Buffer.from(
  process.env.INFURA_API_KEY + ":" + process.env.INFURA_API_KEY_SECRET,
).toString("base64");

// The chain ID of the supported network
const chainId = 1;

(async () => {
  try {
    const { data } = await axios.get(
      `https://gas.api.infura.io/networks/${chainId}/suggestedGasFees`,
      {
        headers: {
          Authorization: `Basic ${Auth}`,
        },
      },
    );
    console.log("Suggested gas fees:", data);
  } catch (error) {
    console.log("Server responded with:", error);
  }
})();
复制

在另一个终端窗口中,运行以下命令。

node index.js

您应该会看到以下内容:

Suggested gas fees: {
  low: {
    suggestedMaxPriorityFeePerGas: '0.05',
    suggestedMaxFeePerGas: '28.501086221',
    minWaitTimeEstimate: 15000,
    maxWaitTimeEstimate: 30000
  },
  medium: {
    suggestedMaxPriorityFeePerGas: '0.1',
    suggestedMaxFeePerGas: '38.508966399',
    minWaitTimeEstimate: 15000,
    maxWaitTimeEstimate: 45000
  },
  high: {
    suggestedMaxPriorityFeePerGas: '0.3',
    suggestedMaxFeePerGas: '48.666846576',
    minWaitTimeEstimate: 15000,
    maxWaitTimeEstimate: 60000
  },
  estimatedBaseFee: '28.451086221',
  networkCongestion: 0.7718,
  latestPriorityFeeRange: [ '0.05', '9.249760902' ],
  historicalPriorityFeeRange: [ '0.023435712', '56.009283908' ],
  historicalBaseFeeRange: [ '19.277073248', '31.361941035' ],
  priorityFeeTrend: 'down',
  baseFeeTrend: 'up'
}
复制

如果您在终端中看到显示的数据,说明我们已成功接收到 API 的响应。下一步是将这些数据呈现在前端界面上。现在您可以删除 index.js 文件。

在前端展示 gas 数据

为了在整个项目中使用自定义类型,请在根目录中创建一个名为 'index.d.ts' 的文件,并添加以下内容:

interface GasFeeEstimate {
    suggestedMaxPriorityFeePerGas: string;
    suggestedMaxFeePerGas: string;
    minWaitTimeEstimate: number;
    maxWaitTimeEstimate: number;
  }

  interface GasFeesApiResponse {
    low: GasFeeEstimate;
    medium: GasFeeEstimate;
    high: GasFeeEstimate;
    estimatedBaseFee: string;
    networkCongestion: number;
    latestPriorityFeeRange: string[];
    historicalPriorityFeeRange: string[];
    historicalBaseFeeRange: string[];
    priorityFeeTrend: 'up' | 'down';
    baseFeeTrend: 'up' | 'down';
  }
复制

全局文件中的这些 TypeScript 接口声明定义了 gas 费用估算和 API 响应的数据结构,涵盖区块链网络上不同交易优先级的费用建议、等待时间、网络拥堵情况以及费用趋势等详细信息。

在 'lib' 文件夹中,创建一个名为 'getData.ts' 的文件,并添加以下代码:

const Auth = Buffer.from(
  process.env["INFURA_API_KEY"] + ":" + process.env["INFURA_API_KEY_SECRET"]
).toString("base64");

// The chain ID of the supported network
const chainId = 1;

export const getData = async () => {
  try {
    const res = await fetch(
      `https://gas.api.infura.io/networks/${chainId}/suggestedGasFees`,
      {
        headers: {
          Authorization: `Basic ${Auth}`,
        },
      }
    );

    const data = await res.json();

    return data as GasFeesApiResponse;
  } catch (error) {
    console.log("Server responded with:", error);
  }
};
复制

这些代码从 Gas API 获取 gas 费用数据:

  1. 身份验证配置:从 INFURA_API_KEY 和 INFURA_API_KEY_SECRET(均设置为环境变量)创建一个 Buffer,然后将其转换为 base64 字符串(命名为 'Auth'),用于 API 请求的基本身份验证。

  2. Chain ID 指定:将变量 chainId 设置为 1,在区块链中通常代表以太坊主网。

  3. getData 函数:一个用于获取 gas 费用数据的异步函数:

  • 使用 fetch 向 Infura API 端点发起 GET 请求,获取指定 chainId 的建议 gas 费用。

  • 使用之前创建的 Auth 令牌在请求中设置 Authorization 请求头。

  • 如果请求成功,将响应解析为 JSON 并以 GasFeesApiResponse 类型返回,与之前定义的接口保持一致。

  • 将网络问题或服务器错误等任何错误记录到控制台。

Chain ID 可变性:chainId 可根据应用所针对的网络进行调整。Infura 上的 Gas API 支持大多数主流 EVM 网络。有关支持网络的更多信息,请访问文档。

构建 UI

现在我们进入令人兴奋的部分——专注于 UI 以展示数据。让我们进入 components 文件夹,创建一个名为 'GasCard.tsx' 的组件。

import { getData } from "@/lib/getData";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";

export const GasCard = async () => {
  const data = await getData();

  const renderGasFeeEstimateCard = (
    estimate: GasFeeEstimate,
    title: string
  ) => (
    <Card>
      <CardHeader>
        <CardTitle>{title}</CardTitle>
      </CardHeader>
      <CardContent>
        <p>Max Priority Fee: {estimate.suggestedMaxPriorityFeePerGas}</p>
        <p>Max Fee Per Gas: {estimate.suggestedMaxFeePerGas}</p>
        <p>Min Wait Time: {estimate.minWaitTimeEstimate} seconds</p>
        <p>Max Wait Time: {estimate.maxWaitTimeEstimate} seconds</p>
      </CardContent>
    </Card>
  );

  return (
    <div className="space-y-4">
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        {data?.low &&
          renderGasFeeEstimateCard(data.low, "Low Gas Fee Estimate")}
        {data?.medium &&
          renderGasFeeEstimateCard(data.medium, "Medium Gas Fee Estimate")}
        {data?.high &&
          renderGasFeeEstimateCard(data.high, "High Gas Fee Estimate")}
      </div>
      <Card>
        <CardContent>
          <h2 className="font-semibold">Estimated Base Fee</h2>
          <p>Gas Price: {data?.estimatedBaseFee}</p>
          <h2 className="font-semibold">Network Congestion</h2>
          <p>{data?.networkCongestion}</p>
          <h2 className="font-semibold">Latest Priority Fee Range</h2>
          <p>{data?.latestPriorityFeeRange.join(" - ")}</p>
          <h2 className="font-semibold">Historical Priority Fee Range</h2>
          <p>{data?.historicalPriorityFeeRange.join(" - ")}</p>
          <h2 className="font-semibold">Historical Base Fee Range</h2>
          <p>{data?.historicalBaseFeeRange.join(" - ")}</p>
          <h2 className="font-semibold">Priority Fee Trend</h2>
          <p>{data?.priorityFeeTrend}</p>
          <h2 className="font-semibold">Base Fee Trend</h2>
          <p>{data?.baseFeeTrend}</p>
        </CardContent>
      </Card>
    </div>
  );
};
复制

让我们来看看这里发生了什么:

  1. 导入与数据获取:

  • 该组件导入了用于获取 gas 费用数据的 getData 函数,以及各种 UI 组件,如 Card、CardContent、CardHeader 和 CardTitle,这些都是我们之前安装的 Shadcn UI 的一部分。

  • 在 GasCard 组件内部,调用 getData 函数来获取 gas 费用数据。

  1. 渲染 Gas 费用估算:

  • 定义了一个名为 renderGasFeeEstimateCard 的函数,用于为特定的 gas 费用估算(GasFeeEstimate)和标题(title)渲染卡片 UI。

  • 该函数构建一个 Card 组件,显示最高优先费、每单位 gas 最高费用以及预计等待时间等详细信息。

  1. 组件结构:

  • GasCard 组件的 JSX 结构在 return 语句中定义。它采用网格布局展示低、中、高三档 gas 费用估算的卡片,这些卡片根据数据可用性进行条件渲染。

  • 另一张卡片显示更多信息,如预计基础费用、网络拥堵情况、优先费范围(最新及历史数据)以及优先费和基础费用的趋势。

现在,唯一剩下的步骤是将 GasCard.tsx 导入 page.tsx 文件。完成后,所有数据应该都能在前端界面上显示。

开始使用 Gas API

使用 Infura 上的 Gas API 为与 EVM 兼容网络交互的开发者提供了显著优势。它提供对波动 gas 市场的实时洞察,帮助用户就交易费用做出明智决策,尤其有助于优化交易速度和成本效益。

本教程介绍了如何开始使用 GasAPI 并创建一个简单的 Gas 追踪应用。您可以在此处找到代码:GitHub 上的 GasAPI-Template。

当然,我们还可以用它做更多有趣的事情:例如添加带倒计时的定时刷新 GasData 功能,也可以将 GasAPI 集成到任何现有应用中。我建议参考以下资源:

Gas API 文档:Infura Gas API 文档

EventSea:一个创意使用 GasAPI 的全栈活动 Dapp:GitHub 上的 EventSea

祝您构建愉快!🚀

AI 翻译。可能包含错误。请务必核实信息。

评价此翻译