
如何使用 Next.js 和 Helius 的 DAS API 构建 Solana 资产组合查看器
目标
在本教程中,我们将使用 Helius 的 DAS API 构建一个前端应用,用于显示 Solana 钱包中的资产。我们将展示多种代币类型及其详细信息,包括元数据、系列信息和同质化代币价格。
本教程将拆解必要步骤,指导你构建一个类似 Galleria 的应用。
前置条件
- Helius API 密钥。
- 熟悉 React。
- 具备 Next.js 使用经验。
所用技术概览
- Next.js:用于构建服务端渲染应用的 React 框架。
- Helius 的 DAS API:用于访问 Solana 代币数据的综合 API。
- Vercel:用于托管 Next.js 应用的平台。
- Tailwind CSS:用于样式设计的实用工具优先 CSS 框架。
设置项目
DAS API
DAS API 是由 Helius 提供的开源规范和系统。该 API 提供了一个简单的接口,用于与 Solana 区块链上的数字资产交互。它支持多种代币类型,包括同质化代币、普通 NFT 和压缩 NFT,并提供链下元数据索引等功能。
设置 API 密钥
要获取 Helius API 密钥,请访问 Helius 开发者门户。你可以按以下步骤开始:
- 使用 Solana 钱包、Google 账号或 GitHub 账号创建账户。
- 登录后,系统会提示你创建 API 密钥。
- 请妥善保管此密钥,因为我们将使用它发起 API 调用。
构建 Next.js 应用
第 1 步:设置 Next.js 项目
使用 Tailwind 创建新的 Next.js 应用
npx create-next-app@latest helius-portfolio --typescript --eslint使用以下配置:
这样,我们既可以使用 Tailwind CSS 设置样式,也可以使用新的 App router。
cd helius-portfolio第 2 步:创建组件
在 app 目录中创建一个 components 文件夹,以保持项目结构清晰。
SearchBar 组件(components/SearchBar.js):
此组件负责处理用户输入的钱包地址。它使用 useState hook 管理地址状态,并使用 useRouter 在表单提交后进行导航。表单使用 Tailwind CSS 类设置样式,界面简洁美观。
TokenCard 组件(components/TokenCard.js):
此组件用于显示代币信息。它会根据同质化代币和非同质化代币有条件地渲染不同布局,并使用来自 ../types/Token 的 Token 和 Attribute 类型。
SearchBar 组件:
components/searchBar.ts
import { useRouter } from "next/navigation";
import React, { useState } from "react";
export default function SearchBar() {
const router = useRouter();
const [address, setAddress] = useState("");
function handleSubmit(event: React.FormEvent) {
event.preventDefault();
router.push(`/${address}`);
}
return (
setAddress(e.target.value)}
className="border-2 border-gray-300 rounded-md w-full text-center px-4 py-2 mb-4 flex-grow text-black"
/>
Search
);
}TokenCard 组件:
此组件会解析来自 API 的代币数据,并在每张代币卡片上显示相关信息。
在下面的示例中,我们会显示每种同质化代币的图片、符号、数量和价值等基本信息。对于非同质化代币,我们会显示图片、名称、描述和属性。你可以提取 API 提供的任意信息,并将其显示在卡片上。
例如,可以显示 cNFT 的压缩相关信息,或铭刻资产的铭文信息。要进一步了解可以使用的具体信息,请查看 DAS 文档。
"use client";
import React from "react";
import { Token, Attribute } from "../types/Token";
interface TokenCardProps {
token: Token;
tokenType: string;
}
const TokenCard = ({ token, tokenType }: TokenCardProps) => {
return (
{/* Other token information */}
{tokenType === "fungible" ? (
{token.content.metadata.symbol}
{/* {token.content.metadata.description} */}
Amount:{token.token_info.balance}
{token.token_info.price_info?.total_price ? (
Value: ${token.token_info.price_info.total_price}
) : null}
) : (
{token.content.metadata.name}
{token.content.metadata.description}
{token.content.metadata?.attributes?.map(
(attribute: Attribute, index: number) => (
{attribute.trait_type}: {attribute.value}
)
)}
)}
);
}
export default TokenCard;第 3 步:从 DAS 获取数据
我们将使用 DAS API 的 searchAssets 方法获取代币数据。此方法非常灵活,允许我们指定钱包地址和代币类型等条件。
创建 lib 文件夹:
- 在 app 目录中创建一个
lib文件夹,用于 API 调用。 - 在其中创建一个
searchAssets.ts文件。
API 调用函数(lib/searchAssets.ts):
- 此函数根据钱包地址获取代币。
- 它会处理潜在错误并记录响应,以便调试
interface Tokens {
items: any[];
}
const fetchTokens = async (walletAddress: string): Promise => {
const url = `https://mainnet.helius-rpc.com/?api-key=`;
console.log(
`Starting search for tokens for wallet address: ${walletAddress}`
);
try {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "my-id",
method: "searchAssets",
params: {
ownerAddress: walletAddress,
tokenType: "all",
displayOptions: {
showCollectionMetadata: true,
},
},
}),
});
const data = await response.json();
console.log(
`Data returned for wallet address ${walletAddress}:`,
data.result
);
return { items: data.result };
} catch (error) {
console.error("Error fetching tokens:", error);
return { items: [] };
}
};
export default fetchTokens;设置代币类型
- 我们需要为 DAS API 的响应设置一个类型。使用 TypeScript 时,这是一项良好实践。你可以创建一个名为 types 的文件夹,并创建一个名为
token.ts的文件
export interface ApiResponse {
total: number;
limit: number;
cursor?: string;
items: Token[];
}
export interface Token {
interface: string;
id: string;
content: Content;
authorities: Authority[];
compression: Compression;
grouping: Grouping[]; // or any[]
royalty: Royalty;
creators: Creator[]; // or any[]
ownership: Ownership;
supply: Supply | null | number;
mutable: boolean;
burnt: boolean;
token_info: TokenInfo;
mint_extensions: MintExtensions;
inscription: Inscription;
spl20?: Spl20;
}
export interface Content {
$schema: string;
json_uri: string;
files: any[];
metadata: Record;
links: Record;
}
export interface Authority {
address: string;
scopes: string[];
}
export interface Compression {
eligible: boolean;
compressed: boolean;
data_hash: string;
creator_hash: string;
asset_hash: string;
tree: string;
seq: number;
leaf_id: number;
}
export interface Grouping {
group_key: string;
group_value: string;
collection_metadata: CollectionMetadata;
}
export interface Royalty {
royalty_model: string;
target: string | null;
percent: number;
basis_points: number;
primary_sale_happened: boolean;
locked: boolean;
}
export interface Creator {
address: string;
share: number;
verified: boolean;
}
export interface Ownership {
frozen: boolean;
delegated: boolean;
delegate: null | string;
ownership_model: string;
owner: string;
}
export interface Supply {
print_max_supply: number;
print_current_supply: number;
edition_nonce: number;
}
export interface TokenInfo {
symbol: string;
balance: number;
supply: number;
decimals: number;
token_program: string;
associated_token_address: string;
price_info: PriceInfo;
}
export interface Inscription {
order: number;
size: number;
contentType: string;
encoding: string;
validationHash: string;
inscriptionDataAccount: string;
}
export interface Spl20 {
p: string;
op: string;
tick: string;
amt: string;
}
export interface File {
uri: string;
cdn_uri: string;
mime: string;
}
export interface Metadata {
attributes: Attribute[];
description: string;
name: string;
symbol: string;
}
export interface Attribute {
value: string;
trait_type: string;
}
export interface CollectionMetadata {
name: string;
symbol: string;
image: string;
description: string;
external_url: string;
}
export interface PriceInfo {
price_per_token: number;
total_price: number;
currency: string;
}
export interface MintExtensions {}第 4 步:显示代币信息
我们会将 API 响应分为同质化代币和非同质化代币,并使用 Token Card 组件显示这些代币。用户可以通过切换按钮在两种代币类型之间切换。
在搜索页面中集成组件
- 搜索页面(pages/index.ts)
- 落地页包含一个搜索栏,用户可以在其中输入钱包地址。
- 页面使用 Tailwind CSS 设置样式,设计简洁且支持响应式布局。
"use client";
import React from "react";
import SearchBar from "./components/searchBar";
export default function Home() {
return (
Solana Portfolio Viewer
{"Built with Helius's DAS API"}
);
}设置代币页面
我们将使用 Next.js 的动态路由处理各个钱包地址。这样可以简化导航和 URL 分享,提升用户体验。
创建一个名为 [wallet] 的目录,方括号用于启用动态路由。完成后,创建一个名为 page.tsx 的文件,其中将包含所有动态加载页面的业务逻辑。
设置代币页面(pages/[wallet]/page.tsx):
此页面显示与 URL 中钱包地址关联的代币。它会发起 API 调用来获取代币数据,并使用 Token Card 组件显示这些数据。
"use client";
import React, { useState, useEffect } from "react";
import fetchTokens from "../lib/searchAssets";
import TokenCard from "../components/tokenCard";
import { Token, Attribute } from "../types/Token";
interface Tokens {
items: Token[];
}
interface PageProps {
params: {
wallet: string;
};
}
export default function Page({ params }: PageProps) {
const [tokens, setTokens] = useState(null);
const [tokenType, setTokenType] = useState("fungible");
useEffect(() => {
fetchTokens(params.wallet).then(setTokens).catch(console.error);
}, [params.wallet]);
console.log("tokens", tokens);
const fungibleTokens = tokens
? tokens.items.filter(
(token) =>
token.interface === "FungibleToken" ||
token.interface === "FungibleAsset"
)
: [];
const nonFungibleTokens = tokens
? tokens.items.filter(
(token) =>
token.interface !== "FungibleToken" &&
token.interface !== "FungibleAsset"
)
: [];
const displayedTokens =
tokenType === "fungible" ? fungibleTokens : nonFungibleTokens;
return (
Portfolio Viewer
{params.wallet}
setTokenType("fungible")}
>
Fungible Tokens
setTokenType("nonFungible")}
>
Non-Fungible Tokens
{displayedTokens.length > 0 ? (
{displayedTokens.map((token) => (
))}
) : (
Loading...
)}
);
}完成所有设置后,你的项目目录应如下所示:
第 5 步:设置应用样式
我们将使用 Tailwind CSS 作为样式框架。其实用工具优先的方法让我们可以快速为组件设置样式,同时确保设计一致且支持响应式布局。你可以使用 Tailwind 按照自己的需求自定义应用。
第 6 步:测试应用
运行 Next.js 应用,在本地进行测试:
npm run dev输入不同的钱包地址进行测试,并确保显示的数据正确无误。
部署
我们将使用 Vercel 部署应用。Vercel 提供免费托管以及实用的分析与洞察功能,是托管 Next.js 应用的理想选择。你可以前往 https://vercel.com/ 进行设置。
总结
恭喜你完成本教程!希望本教程能为你提供有价值的信息。
DAS API 是一款功能强大且速度极快的工具,让你能够从链上检索代币数据。
这个资产组合查看器充分展示了该 API 的能力。
希望你能以这个基础网站为起点,打造出更出色的产品。如果有任何问题,欢迎加入我们的 Discord,直接向我们提问!
你可以在这里找到完整代码:https://github.com/helius-labs/galleria
延伸学习资源
要深入了解 Next.js、Solana 区块链和 API 集成,请查看以下资源:
本指南为使用 Next.js 构建区块链应用,以及通过 DAS API 与 Solana 区块链交互奠定了坚实基础。
相关文章
订阅 Helius
及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新


