「Gas」とは、トランザクションの実行やスマートコントラクトの起動など、各種オペレーションに必要な計算処理量を測る単位です。車の燃料に例えられるように、ネットワークがオペレーションを処理・検証するために不可欠なものです。Ethereum上の各トランザクションには、その複雑さに応じた特定量のガスが必要です。ユーザーはGwei(1 Gwei = Etherの10億分の1)単位でガス価格を設定し、ガス1単位あたりに支払う意思のあるEtherの量を指定します。
ブロックチェーンネットワークにおいて、ガス価格を理解することはトランザクションコストを管理するうえで非常に重要です。現在のガス価格を把握することで、最もコスト効率の良いタイミングでトランザクションを開始し、その処理速度を決定することができます。また、ガス価格を意識することは、トランザクションの失敗防止、予算計画、ネットワーク混雑状況の把握、そして適切な投資判断を行ううえでも欠かせません。
MetaMask Gas API
Infuraを通じて提供されるMetaMask Gas APIは、Ethereum Virtual Machine(EVM)互換ネットワーク向けにリアルタイムのガス価格情報を提供する専用ツールです。オラクルとして機能し、これらのネットワーク上でオペレーションやトランザクションを実行するために必要な計算コストに関する最新データを提供します。このAPIにより、開発者は高度なガス見積もり機能を構築でき、バックエンドのトランザクション処理コストの削減や、ユーザー向けインターフェースの改善につなげることができます。
このチュートリアルでは、Gas API、Next.js、ShadcnUIを使用してGas Tracker Appを構築する方法を学びます。このアプリケーションにより、dappユーザーはトランザクションの優先度に応じた推奨ガス価格にアクセスでき、ブロックチェーンブロックへの効率的なトランザクション取り込みをサポートします。
前提条件
有効なWeb3 APIキーおよびAPIキーシークレット
Node.jsおよびnpmまたはyarnのインストール
Next.jsおよびReactの基本的な知識
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=
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
次に、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");
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");
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からガス手数料データを取得します。
認証設定:環境変数として設定されたINFURA_API_KEYとINFURA_API_KEY_SECRETからBufferを作成します。このBufferはAPIリクエストのBasic認証用にbase64文字列(「Auth」という名前)に変換されます。
チェーンIDの指定:変数chainIdを1に設定します。これは通常、ブロックチェーンコンテキストにおけるEthereumメインネットを表します。
getData関数:ガス手数料データを取得する非同期関数です。
fetchを使用してInfura APIエンドポイントにGETリクエストを送り、指定したchainIdの推奨ガス手数料を取得します。
先ほど作成したAuthトークンを使用して、リクエストのAuthorizationヘッダーを設定します。
成功した場合、レスポンスをJSONとして解析し、事前に定義したインターフェースに沿ったGasFeesApiResponseとして返します。
ネットワークエラーやサーバーエラーなど、発生したエラーをコンソールに記録します。
チェーン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>
);
};
ここで行っていることを確認しましょう。
インポートとデータ取得:
コンポーネントは、ガス手数料データを取得するgetData関数と、先ほどインストールしたShadcn UIのCard、CardContent、CardHeader、CardTitleなどのUIコンポーネントをインポートします。
GasCardコンポーネント内で、getData関数を呼び出してガス手数料データを取得します。
ガス手数料見積もりの表示:
renderGasFeeEstimateCardという関数が定義されており、特定のガス手数料見積もり(GasFeeEstimate)とタイトル(title)のカードUIをレンダリングします。
この関数は、最大優先手数料、ガスあたりの最大手数料、推定待機時間などの詳細を表示するCardコンポーネントを構築します。
コンポーネント構造:
GasCardコンポーネントのJSX構造はreturn文に記述されています。グリッドレイアウトを使用して、低・中・高のガス手数料見積もりカードを表示し、データの有無に応じて条件付きで表示されます。
追加のカードには、推定ベース手数料、ネットワーク混雑状況、優先手数料の範囲(最新および過去のデータ)、優先手数料とベース手数料のトレンドなどの詳細情報が表示されます。
最後に残るステップは、GasCard.tsxをpage.tsxファイルにインポートすることです。これにより、すべてのデータがフロントエンドに表示されるようになります。
Gas APIを使い始める
InfuraのGas APIを活用することで、EVM互換ネットワークを扱う開発者にとって大きなメリットがあります。変動するガス市場のリアルタイムな情報を提供し、トランザクション手数料について適切な判断を下せるようになります。これは特に、トランザクションの速度とコスト効率の両方を最適化するうえで有効です。
このチュートリアルでは、Gas APIの使い始め方と、シンプルなGas Tracker Appの作成方法を解説しました。コードはこちらで確認できます:GasAPI-Template on GitHub
さらに多くの応用が可能です。カウントダウン付きで一定時間ごとにGasDataを更新する機能を追加したり、既存のアプリケーションにGasAPIを統合したりすることもできます。以下のリソースもぜひご参照ください。
Gas API ドキュメント:Infura Gas API Documentation
EventSea:GasAPIを活用したフルスタックイベントDapp:EventSea on GitHub
Happy Building! 🚀