本文介绍了如何构建一个 Solana Explorer 的 cloned 组件,来展示用户质押的 Solana 账户和委托的详细信息。通过提供详细的实现步骤和代码示例,读者可以学习到如何获取钱包的质押账户并在前端展示出来,适合有一定开发基础的读者。
Solana Explorer 提供了关于 Solana 区块链的大量信息:交易历史和详情、代币余额、NFT 元数据等等。在我们看来,浏览 Solana Explorer 是了解 Solana 的最佳途径之一,但构建一个 Solana Explorer 可以让你的知识提升到一个新的层次!在本系列三部分中,我们将介绍创建 Solana Explorer 简单克隆所需的步骤!
在本指南中,我们将提取一个钱包的委托账户,以显示用户有多少 $SOL 被委托以及与哪些验证者进行委托。
在本指南中,你将使用我们之前如何构建 Solana Explorer 克隆(第 2 部分:交易详情)中构建的 Solana Explorer 示例。你将利用这个框架制作一个新的组件,允许用户查看他们的 Staked Solana 账户和委托的表格。
安装 Nodejs(版本 16.15 或更高)
具备 TypeScript 经验,并安装 ts-node
基本的 HTML/CSS 知识
具有 Solana 交易的经验(指南:如何在 Solana 上获取交易日志)
具有 Solana Scaffold 的经验(指南:如何通过 Solana 钱包适配器和 Scaffold 连接用户到你的 dApp)
要按照本指南操作,你需要完成我们的如何构建 Solana Explorer 克隆(第 2 部分:交易详情)指南。为什么?因为我们会在那里的代码上进行构建。
“如何构建 Solana Explorer 克隆(第 2 部分:交易详情)”指南中的最终代码可以在这个 QuickNode Github 仓库中找到。那篇指南将作为这篇指南的起点。确保你已经遵循那篇指南中的说明并完成了所有步骤。
快速开始*: 如果你没有机会完成第二篇指南,这里有一个简单的方法可以直接开始。在你的终端中,创建一个项目目录并克隆样本:*
mkdir solana-explorer-demo
cd solana-explorer-demo
git clone https://github.com/quiknode-labs/technical-content.git .
cd solana/explorer-clone-part-3/starter
yarn install
echo > .env
然后使用你的 QuickNode RPC 更新 .env:
REACT_APP_SOLANA_RPC_HOST=https://example.solana-devnet.quiknode.pro/000000/
REACT_APP_NETWORK=devnet
然后在终端中输入 yarn dev。
你的 https://localhost:3000/explorer 应该呈现以下视图:
好的!让我们开始吧。
让我们基于我们的交易工具构建一个组件,以允许用户点击交易以获取更多关于该交易的详情。好消息是我们已经具备了实现此功能的工具。
在你的项目目录中,复制你的组件模板并命名为 StakingDetail.tsx:
cp ./src/components/template.tsx ./src/components/StakingDetail.tsx
StakingDetail.tsx 现在应该存在于你的 src/components 文件夹中。用代码编辑器打开它。
首先将你的函数组件重命名为 StakingDetail。替换
export const Template: FC = () => {
为
export const StakingDetail: FC = () => {
对于这个组件,我们需要以下导入。用这些替换你模板中的现有导入:
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { AccountInfo, LAMPORTS_PER_SOL, ParsedAccountData, PublicKey } from '@solana/web3.js';
import { FC, useEffect, useState } from 'react';
import { notify } from "../utils/notifications";
这些导入应该是你在 TransactionLog 和 TransactionDetail 中已经使用过的。由于这个组件的组成与我们之前的组件相似,我们将一次性分享完整代码并逐步讲解一些重要部分:
import { useConnection, useWallet } from '@solana/wallet-adapter-react';
import { AccountInfo, LAMPORTS_PER_SOL, ParsedAccountData, PublicKey } from '@solana/web3.js';
import { FC, useEffect, useState } from 'react';
import { notify } from "../utils/notifications";
const STAKE_PROGRAM_PK = new PublicKey('Stake11111111111111111111111111111111111111');
const WALLET_OFFSET = 44;
const DATA_SIZE = 200;
export const StakeDetail: FC = () => {
const { connection } = useConnection();
const { publicKey } = useWallet();
const [stakeAccounts, setStakeAccounts] = useState<
Array<{
pubkey: PublicKey;
account: AccountInfo<ParsedAccountData|Buffer>;
}>
>();
const [stakeCard, setStakeCard] = useState<JSX.Element>();
useEffect(() => {
if (stakeAccounts) {
buildView();
}
}, [stakeAccounts]);
async function getStakeAccounts(wallet: string) {
const stakeAccounts = await connection.getParsedProgramAccounts(
STAKE_PROGRAM_PK, {
filters: [\
{\
dataSize: DATA_SIZE, // 字节数\
},\
{\
memcmp: {\
offset: WALLET_OFFSET, // 字节数\
bytes: wallet, // base58 编码字符串\
},\
},\
]
}
);
setStakeAccounts(stakeAccounts);
}
function buildView() {
if(stakeAccounts.length > 0) {
let header =
<thead className="text-xs text-gray-700 uppercase bg-zinc-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<td className="px-6 py-3">#</td>
<td className="px-6 py-3">Stake Wallet</td>
<td className="px-6 py-3">余额 (SOL)</td>
<td className="px-6 py-3">年龄 (纪元)</td>
<td className="px-6 py-3">委托</td>
</tr>
</thead>;
let rows = (stakeAccounts.map((account,i)=>{
const epcohStart = Number(account.account.data.parsed?.info.stake.delegation.activationEpoch);
const epochCurrent = Number(account.account.rentEpoch);
const epochAge = epochCurrent - epcohStart;
return (
<tr key={i+1} className="bg-white border-b bg-zinc-800 dark:border-zinc-700">
<td className="px-6 py-3">{i+1}</td>
<td className="px-6 py-3">{account.pubkey.toString()}</td>
<td className="px-6 py-3">{'◎ ' + (account.account.lamports/LAMPORTS_PER_SOL).toFixed(2)}</td>
<td className="px-6 py-3">{epochAge}</td>
<td className="px-6 py-3">{account.account.data.parsed?.info.stake.delegation.voter}</td>
</tr>)
}
));
let table = (
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
{header}
<tbody>{rows}</tbody>
</table>);
setStakeCard(table)
}
else {
setStakeCard(<>未找到委托账户</>);
}
}
const onClick = async () => {
if (!publicKey) {
console.log('error', '钱包未连接!');
notify({ type: 'error', message: 'error', description: '钱包未连接!' });
return;
}
try {
// 示例:主网钱包用 publicKey.toString() 替换为 'AhbkRLfEuL5zV5gbooQzcDP7dZLBWK5En3mPVixs34yb'
// 示例:开发网钱包用 publicKey.toString() 替换为 'Cxcfw2GC1tfEPEuNABNwTujwr6nEtsV6Enzjxz2pDqoE'
await getStakeAccounts(publicKey.toString());
} catch (error: any) {
notify({ type: 'error', message: `无法找到委托账户!`, description: error?.message });
console.log('error', `查找委托账户时出错! ${error?.message}`);
}
};
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>{stakeCard}</div>
</div>
)
}
下面是这个函数组件中发生的事情:
干得好!现在我们需要在我们的 Explorer 视图中调用 StakeDetails。为此,导航到 src/views/explorer/index.tsx,这是我们当前在网站上显示的视图 /explorer/。
将 StakeDetails 导入到你的视图中。在第 7 行,添加:
import { StakeDetail } from "components/StakingDetail";
在你的返回语句中调用 TransactionLogs 和 GetTokens 组件(我们的在第 35 行):
<div className="text-center">
<TransactionLog/>
<GetTokens/>
<StakeDetail/>
</div>
因为我们正在向我们的 ExplorerView 添加内容,而该视图已经在我们的 Explorer 页面中调用,所以我们不需要创建新的页面来显示这些结果。
干得不错!你应该可以开始了。继续运行你的代码。在你的终端中输入:
yarn dev
注意:如果你没有委托账户,你可以通过对你的 StakeDetail 组件进行小的修改来测试你的代码。
打开 explorer-clone-part-3/starter/src/components/StakingDetail.tsx 并替换第 92 行:
await getStakeAccounts(publicKey.toString());
为
await getStakeAccounts('AhbkRLfEuL5zV5gbooQzcDP7dZLBWK5En3mPVixs34yb'); // 对于主网标准版
// 或者
await getStakeAccounts('Cxcfw2GC1tfEPEuNABNwTujwr6nEtsV6Enzjxz2pDqoE'); // 对于开发网
这些是已知的委托账户,如果你在连接的钱包中没有委托账户,这将确保你的查询正常工作。
恭喜你!如果你在这个系列中一路跟随,你应该已经拥有一个功能完整的 Solana Explorer,能够返回用户的代币账户、交易历史、交易详情和委托账户。
在本系列的此时,你应该对创建新的组件和视图展示有关 Solana 的任何类型信息感到自信。想继续构建你所学到的内容吗?尝试向网站添加一些你自己的自定义组件。以下是一些可能激发你创意的资源:
添加用户的 NFT 画廊(指南:如何使用 QuickNode 的 NFT-API 在 Solana 上构建 NFT 画廊)
添加一个 搜索栏 以导航其他钱包
使用动态路由启用可点击的代币铸造详情(指南:如何构建 Solana Explorer 克隆(3 部分中的 2 部分):使用动态路由的交易详情)
有想法、问题,还是想展示你的创作?在 Discord 上告诉我们或者通过 Twitter 与我们联系,共享你所创建的内容。
如果你对本指南有任何反馈或问题,请告诉我们。我们非常乐意听取你的意见!
- 原文链接: quicknode.com/guides/sol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!