如何构建Solana区块浏览器克隆(第1部分 - 交易历史)

  • QuickNode
  • 发布于 2025-01-30 17:52
  • 阅读 24

本文介绍了如何构建一个简单的Solana Explorer克隆,涵盖了从基础概念到实际代码实现的多个步骤,包括环境设置、组件创建和用户界面构建。文章详细列出了所需的技术栈和示例代码,使读者能够快速上手并实现自己的Solana交易历史查询功能。

概述

Solana Explorer 提供了丰富的 Solana 区块链信息:交易历史和详细信息、代币余额、NFT 元数据等等。在我们看来,浏览 Solana Explorer 是理解 Solana 的最佳方式之一,但构建一个 Solana Explorer 将使你的知识提升到一个新的水平!在这个三部分系列中,我们将介绍构建 Solana Explorer 简单克隆所需的步骤!

在我们的第一篇指南中,我们将介绍交易。如果你正在构建一个 dApp,你可能希望与你的用户分享交易历史。一些可能的用例包括:

  • NFT 平台可能想要向用户展示 NFT 销售历史

  • DAO 可能想要展示投票结果历史

  • 交易所可能想要显示用户的买卖历史

  • 非营利组织可能想要跟踪捐赠日志

你将做什么

在这个指南中,你将使用 Solana Scaffold 和 Wallet Adapter 创建一个 Solana Explorer 框架。你将利用该框架构建一个简单的 web 应用,获取一个钱包的交易历史并在你的网站上显示该历史。

示例输出:交易日志

你将需要什么

为了跟随本指南,你需要完成我们关于 如何使用 Solana Wallet Adapter 和 Scaffold 将用户连接到你的 dApp 的指南。为什么?我们将基于现有的代码进行构建。

在开始之前,请确保你已遵循该指南中的说明并完成以下步骤:

  1. 从你的项目目录安装并启动 Solana Scaffold。

  2. 更新你的 RPC 终端。

  3. ./src/components/ 中创建 template.tsx(我们将把它作为我们的起始点)。

来自 如何使用 Solana Wallet Adapter 和 Scaffold 将用户连接到你的 dApp 的指南 的最终代码将作为本指南的起点。你应该在本地代码编辑器中拥有 来自此 GitHub 仓库的最终代码,你的 localhost:3000 应该呈现以下视图:

当前本地主机

设置你的环境

让我们开始将我们的模板升级到最新版本的 Solana Web 3。我们将使用 yarn 来初始化我们的项目并安装必要的包。如果你更喜欢使用 npm,也可以这样做:

npm update @solana/web3.js@1
## 或
yarn upgrade @solana/web3.js@1

创建交易日志组件

从你的项目目录复制你的组件模板,并将其命名为 TransactionsLog.tsx

cp ./src/components/template.tsx ./src/components/TransactionsLog.tsx

TransactionsLog.tsx 现在应该在你的组件文件夹中存在。用你选择的代码编辑器打开它。

更新依赖项

首先将你的函数组件重命名为 TransactionLog。替换:

export const Template: FC = () => {

export const TransactionLog: FC = () => {

对于该组件,我们需要额外的导入。将模板中现有的导入替换为以下内容:

import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { PublicKey, ParsedTransactionWithMeta } from '@solana/web3.js';
import { FC, useEffect, useState } from 'react';
import { notify } from "../utils/notifications";

创建状态变量

TransactionLog 函数组件内部,使用 useState 声明两个状态变量:

  1. transactionHistory - 这里存储我们 Solana 查询的解析交易结果

  2. transactionTable - 这里存储一个包含我们将在 web 应用中显示的输出表的 JSX 元素

我们将这两个值都设置为 null 开始:

    const { connection } = useConnection();
    const { publicKey } = useWallet();
    const [transactionHistory, setTransactionHistory] = useState<ParsedTransactionWithMeta[]>(null);
    const [transactionTable, setTransactionTable] = useState<JSX.Element>(null);

创建 Solana 查询

接下来,在你的 TransactionLog 函数组件内部创建 getTransactions,一个将为给定钱包获取解析交易并将该交易数据数组设置为 transactionHistory 变量的函数:

     async function getTransactions(address, numTx) {
        const pubKey = new PublicKey(address);
        //查找最近的交易
        let transactionList = await connection.getSignaturesForAddress(pubKey, {limit:numTx});
        //解析交易以获取最近交易的签名
        let signatureList = transactionList.map(transaction=>transaction.signature);
        //获取每笔交易的解析详情
        let transactionDetails = await connection.getParsedTransactions(signatureList, {maxSupportedTransactionVersion:0});
        //更新状态
        setTransactionHistory(transactionDetails);
    }

有关如何在 Solana 上获取交易日志的更多信息,请访问我们的 指南:如何获取 Solana 上的交易日志

接下来,创建一个函数,将我们的解析交易数据组装成一个漂亮的表格。以下是我们使用的函数,其中包含一些自定义样式和格式,你可以根据需要进行修改,以包括对你重要的信息。

构建 UI

getTransactions 之后添加以下 buildTransactionTable 函数:

    function buildTransactionTable() {
        if(transactionHistory && transactionHistory.length !== 0) {
            let header = (
                <thead className="text-xs text-gray-700 uppercase bg-zinc-50 dark:bg-gray-700 dark:text-gray-400">
                    <tr>
                        <th className="px-6 py-3">交易签名</th>
                        <th className="px-6 py-3">槽</th>
                        <th className="px-6 py-3">日期</th>
                        <th className="px-6 py-3">结果</th>
                    </tr>
                </thead>
                )
            let rows = transactionHistory.map((transaction, i)=>{
                let date = new Date(transaction.blockTime*1000).toLocaleDateString();
                return (
                    <tr  key={i+1} className="bg-white border-b bg-zinc-800 dark:border-zinc-700">
                        <td className="px-6 py-3">
                                {/* 一些交易返回多个签名--我们只想要第一个 */}
                                {transaction.transaction.signatures[0]}
                        </td>
                        <td className="px-6 py-3">{transaction.slot.toLocaleString("en-US")}</td>
                        <td className="px-6 py-3">{date}</td>
                        <td className="px-6 py-3">{transaction.meta.err ? '失败' : '成功'}</td>
                    </tr>)
            })
            setTransactionTable(
                <table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
                    {header}
                    <tbody>{rows}</tbody>
                </table>)
        }
        else {
            setTransactionTable(null);
        }
    }

关于这个函数的几点注意事项:

  • 我们首先检查确保已找到 transactionHistory,并且至少找到 1 条记录。

  • Header 定义了我们将在其中查找的字段。

  • Rows 将为 transactionHistory 中的每个 transaction 创建一个表格行 <tr>。里面,我们为每个将要显示的数据块创建一个 <td> 元素。

  • 我们将状态变量 transactionTable 设置为包含我们的 headerrows<table>

触发查询和表格渲染

现在我们需要创建一个 React 钩子 useEffect 来在我们的应用找到交易时调用 buildTransactionTable。将其添加到你的状态变量声明下方,getTransactions 函数上方:

    useEffect(() => {
        if (publicKey && transactionHistory) {
            buildTransactionTable();
        }
      }, [publicKey, connection, transactionHistory])

这实际上将监测 publicKeyconnectiontransactionHistory 的变化,并根据新参数刷新我们的表格。

buildTransactionTable 函数后创建一个 onClick 函数以启动我们的搜索:

    const onClick = async () => {
        if (!publicKey) {
            console.log('error', '钱包未连接!');
            notify({ type: 'error', message: '错误', description: '钱包未连接!' });
            return;
        }
        try {
            await getTransactions(publicKey.toString(),15);
        } catch (error: any) {
            notify({ type: 'error', message: `无法找到交易!`, description: error?.message });
            console.log('error', `查找交易时出错! ${error?.message}`);
        }
    };

我们的函数首先检查我们是否有连接的 publicKey,并执行简单的 try/catch 尝试使用我们的 getTransactions 函数搜索该公钥。我们在示例中搜索 15 条交易,但你可以根据你希望返回的交易数量设置搜索值。

最后,更新你的返回语句以包含一个启动 onClick 的按钮和一个渲染我们表格的 <div>

    return(<div>
        <div className="text-center">
        <button
                className="px-8 m-2 btn animate-pulse bg-gradient-to-r from-[#9945FF] to-[#14F195] center hover:from-pink-500 hover:to-yellow-500 ..."
                onClick={onClick}
            >
                <span>获取交易</span>
        </button>
        </div>

    {/* 在这里渲染结果 */}
        <div>{transactionTable}</div>
    </div>)

如果你正在跟随,最终文件应如下所示 这个

创建 Explorer 视图和页面

干得不错!但在我们去查看我们的工作之前,我们需要告诉我们的应用程序在哪里显示它。我们需要做几个事情才能在 Next.js 中使我们的组件可见:

  • 创建 Explorer 视图

  • 创建 Explorer 页面

为我们的 Solana Explorer 克隆创建 Explorer 视图

从你的项目目录中创建一个新文件夹:explorer,并在其中创建一个新文件 index.tsx

mkdir ./src/views/explorer
echo > ./src/views/explorer/index.tsx

打开 ./src/views/explorer/index.tsx 并粘贴以下代码:

import { FC, useEffect } from "react";
import { useWallet, useConnection } from '@solana/wallet-adapter-react';
import useUserSOLBalanceStore from '../../stores/useUserSOLBalanceStore';
import { TransactionLog } from "../../components/TransactionsLog";
{/* import { GetTokens } from "../../components/GetTokens"; */}

export const ExplorerView: FC = ({ }) => {
  const wallet = useWallet();
  const { connection } = useConnection();

  const balance = useUserSOLBalanceStore((s) => s.balance)
  const { getUserSOLBalance } = useUserSOLBalanceStore()

  useEffect(() => {
    if (wallet.publicKey) {
      console.log(wallet.publicKey.toBase58())
      getUserSOLBalance(wallet.publicKey, connection)
    }
  }, [wallet.publicKey, connection, getUserSOLBalance])

  return (
<div className="md:hero mx-auto p-4">
      <div className="md:hero-content flex flex-col">
        <h1 className="text-center text-5xl font-bold text-transparent bg-clip-text bg-gradient-to-tr from-[#9945FF] to-[#14F195]">
          快速查看 Explorer
        </h1>
        <div className="text-center">
          {wallet && wallet.publicKey && <p>已连接到:{(wallet.publicKey.toString())}</p>}
          {wallet && <p>SOL 余额:{(balance || 0).toLocaleString()}</p>}
        </div>
        <div className="text-center">
          <TransactionLog/>
          {/* <GetTokens/> */}
        </div>
      </div>
    </div>
  );
};

对于此视图,我们实际上从 ./src/views/home/index.tsx 借用了相当多的代码,该代码在 Wallet Connect 上获取用户的钱包余额。在下面,我们调用 <TransactionLog/> 来处理和显示我们的交易搜索。

如果你完成了我们之前的指南以创建 Get Token Accounts 组件,你也可以将其添加到此处:只需将 import { GetTokens } from "components/GetTokens"; 添加到你的导入中并在 <TransactionLog/> 之后包含 <GetTokens/>

Solana Scaffold 从公共文件 ./src/views/index.tsx 导出所有视图。打开它,并添加此行以导出 ExplorerView

export { ExplorerView } from "./explorer";

创建发布我们视图的 Explorer 页面

从你的项目目录中创建一个新页面 explorer.tsx

echo > ./src/pages/explorer.tsx

将以下代码粘贴到 explorer.tsx 中:

import type { NextPage } from "next";
import Head from "next/head";
import { ExplorerView } from "../views";

const Explorer: NextPage = (props) => {
  return (
    <div>
      <Head>
        <title>Solana Scaffold</title>
        <meta
          name="description"
          content="基本功能"
        />
      </Head>
      <ExplorerView />
    </div>
  );
};

export default Explorer;

这是将要渲染的实际页面,/explorer/

好了!你完成了!让我们回顾一下我们所做的,以确保我们都已同步。以下是你应该创建的新文件的摘要:

  • ./src/components/TransactionsLog.tsx - 新组件,通过查询 solana 作出反应,并在成功结果上呈现表格

  • ./src/views/explorer/index.tsx - 华人可查看用于托管我们的交易日志(以及未来其他组件)的新视图

  • ./src/pages/explorer.tsx - 用于显示我们的视图 ./explorer/ 的新页面

让我们看看它的实际效果! 输入:

npm run dev
## 或
yarn dev

然后访问 http://localhost:3000/explorer。你是否看到类似的内容?

检查点 1:交易日志

不错,对吧?是的,干得棒!

结论

你刚刚构建了一个 dApp,它将查询用户的钱包,找到他们的交易历史,并在 dApp 上呈现该历史。相当强大,不是吗?但如果我们想深入了解给定交易呢?我们将在本系列的下一篇指南中涵盖这一点。

准备好迈出下一步了吗?查看我们的 指南:Solana Explorer 克隆第 2 部分 - 交易详情

我们❤️反馈!

我们将发布几个后续指南,以进一步构建这个 Solana Explorer 克隆。如果你想第一个了解这些或对本指南有任何反馈或问题,请 告诉我们。随时通过 Twitter 或我们的 Discord 社区服务器与我们联系。我们很乐意听取你的意见!

  • 原文链接: quicknode.com/guides/sol...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。