Как создать простой трекер газа с Gas API и Next.js

Узнайте, как создать простое приложение для отслеживания газа с помощью MetaMask gas API, Next.js и ShadcnUI.

8 мин чтения
Как создать простой трекер газа с Gas API и Next.js

'Gas' (газ) — это единица измерения вычислительных усилий, необходимых для выполнения операций, таких как проведение транзакций или запуск смарт-контрактов. По аналогии с топливом для автомобиля — газ необходим сети для обработки и подтверждения операций. Каждая транзакция в Ethereum требует определённого количества газа, которое определяется её сложностью. Пользователи устанавливают цену газа в Gwei (1 Gwei = 1 миллиардная часть Ether), указывая тем самым, сколько Ether они готовы заплатить за единицу газа.

Понимание цен на газ имеет ключевое значение в блокчейн-сетях, поскольку помогает пользователям управлять стоимостью своих транзакций. Знание актуальных цен на газ позволяет выбрать наиболее экономичное время для инициирования транзакции и определить её скорость. Осведомлённость о ценах на газ также важна для предотвращения неудачных транзакций, планирования бюджета, понимания загруженности сети и принятия взвешенных инвестиционных решений.

Gas API от MetaMask

MetaMask Gas API, доступный через Infura, — это специализированный инструмент, предназначенный для предоставления актуальной информации о ценах на газ для сетей, совместимых с Ethereum Virtual Machine (EVM). Он функционирует как оракул, предоставляя актуальные данные о вычислительных затратах, необходимых для выполнения операций или транзакций в этих сетях. API даёт разработчикам возможность создавать продвинутые функции оценки газа, что может привести к экономии затрат на серверные транзакционные операции или улучшить пользовательский интерфейс.

В этом руководстве мы научимся создавать приложение Gas Tracker с использованием Gas API, Next.js и ShadcnUI. Это приложение позволит пользователям dapp получать доступ к рекомендуемым ценам на газ с учётом приоритетов их транзакций, помогая обеспечить эффективное включение этих транзакций в блок блокчейна.

Предварительные требования

  • Действующий Web3 API key и API key secret.

  • Установленные Node.js и npm или yarn.

  • Знакомство с Next.js и React.

Настройка Next.js + ShadcnUI

Для начала убедитесь, что на вашем компьютере установлен 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
Копировать

Разобравшись с этим, установим также компонент Card из Shadcn UI:

npx shadcn-ui@latest add card

В этом руководстве мы сосредоточимся на использовании компонента Card из Shadcn UI. Чтобы узнать больше об этих компонентах, посетите сайт Shadcn UI. Теперь, когда фронтенд настроен, мы готовы приступить к работе с Gas API.

В корневом каталоге создайте файл с именем .env, в котором будут храниться следующие учётные данные:

INFURA_API_KEY=
INFURA_API_KEY_SECRET=
Копировать

Обязательно получите API_KEY и API_KEY_SECRET из панели управления Infura. Крайне важно не публиковать 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
Копировать

Теперь создайте файл с именем 'index.js' в корне нашего gastracker-app и скопируйте в него следующий код:

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.

Отображение данных о газе на фронтенде

Чтобы определить пользовательские типы для использования в рамках всего проекта, создайте файл с именем '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 в глобальном файле определяют структуры для оценки комиссий за газ и ответов 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:

  1. Настройка аутентификации: создаёт Buffer из INFURA_API_KEY и INFURA_API_KEY_SECRET, заданных в качестве переменных окружения. Затем этот Buffer преобразуется в строку base64 (с именем 'Auth') для базовой аутентификации в API-запросах.

  2. Указание Chain ID: устанавливает переменную chainId равной 1, что обычно соответствует основной сети Ethereum (mainnet) в контексте блокчейна.

  3. Функция getData: асинхронная функция для получения данных о комиссиях за газ:

  • Использует fetch для выполнения GET-запроса к конечной точке Infura API, получая рекомендуемые комиссии за газ для указанного chainId.

  • Устанавливает заголовок Authorization в запросе с использованием ранее созданного токена Auth.

  • В случае успеха разбирает ответ как JSON и возвращает его в виде GasFeesApiResponse, соответствующего ранее определённому интерфейсу.

  • Записывает любые ошибки, такие как сетевые проблемы или ошибки сервера, в консоль.

Вариативность Chain ID: chainId можно изменить в зависимости от сети, для которой создаётся приложение. Gas API на Infura поддерживает большинство крупных EVM-сетей. Для получения дополнительной информации о поддерживаемых сетях посетите документацию.

Работа над пользовательским интерфейсом

Мы добрались до самой интересной части — работы над 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. Импорты и получение данных:

  • Компонент импортирует функцию getData для получения данных о комиссиях за газ, а также различные UI-компоненты: Card, CardContent, CardHeader и CardTitle, которые являются частью ранее установленного Shadcn UI.

  • Внутри компонента GasCard вызывается функция getData для получения данных о комиссиях за газ.

  1. Отображение оценок комиссий за газ:

  • Определяется функция renderGasFeeEstimateCard, которая отображает карточку UI для конкретной оценки комиссии за газ (GasFeeEstimate) и заголовка (title).

  • Эта функция формирует компонент Card, отображающий такие детали, как максимальная приоритетная комиссия, максимальная комиссия за газ и ожидаемое время ожидания.

  1. Структура компонента:

  • JSX-структура компонента GasCard описана в операторе return. Она использует сеточный макет для отображения карточек с низкими, средними и высокими оценками комиссий за газ, которые отображаются условно в зависимости от наличия данных.

  • Дополнительная карточка показывает более подробную информацию: расчётную базовую комиссию, загруженность сети, диапазоны приоритетных комиссий (актуальные и исторические), а также тенденции приоритетных и базовых комиссий.

Теперь остался единственный шаг — импортировать GasCard.tsx в файл page.tsx. После этого все данные должны отображаться на нашем фронтенде.

Начало работы с Gas API

Использование Gas API на Infura предоставляет разработчикам, работающим с EVM-совместимыми сетями, значительные преимущества. Он обеспечивает актуальную информацию о постоянно меняющемся рынке газа, позволяя пользователям принимать взвешенные решения о комиссиях за транзакции. Это особенно полезно для оптимизации как скорости, так и экономической эффективности транзакций.

В этом руководстве рассматривается, как начать работу с GasAPI и создать простое приложение Gas Tracker. Код можно найти здесь: GasAPI-Template на GitHub.

Но с этим можно делать ещё много интересного: добавить обновление GasData через определённые промежутки времени с обратным отсчётом, а также интегрировать GasAPI в любое существующее приложение. Рекомендую ознакомиться со следующими ресурсами:

Документация Gas API: Документация Infura Gas API

EventSea: Полноценный dapp для мероприятий, творчески использующий GasAPI: EventSea на GitHub

Удачной разработки! 🚀

Переведено ИИ. Может содержать ошибки. Пожалуйста, всегда проверяйте информацию.

Оцените перевод