НОВОЕ: Helius приобретает Light Protocol
Как создать обозреватель портфеля Solana с помощью Next.js и DAS API от Helius
Блог/Разработка

Как создать обозреватель портфеля Solana с помощью Next.js и DAS API от Helius

Инженер по взаимодействию с разработчикамиOwen Venter в XOwen Venter в LinkedIn
Чтение: 6 мин

Цели

В этом руководстве мы создадим фронтенд-приложение, которое отображает содержимое кошелька Solana с помощью DAS API от Helius. Мы покажем разные типы токенов и подробную информацию о них, включая метаданные, сведения о коллекциях и цены взаимозаменяемых токенов.

В этом руководстве мы пошагово разберём процесс создания приложения, похожего на Galleria.

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

  • Ключ Helius API.
  • Знание React.
  • Опыт работы с Next.js.

Обзор используемых технологий

  • Next.js: React-фреймворк для создания приложений с серверным рендерингом.
  • DAS API от Helius: Комплексный API для доступа к данным токенов Solana.
  • Vercel: Платформа для хостинга приложений Next.js.
  • Tailwind CSS: CSS-фреймворк для стилизации, основанный на служебных классах.

Настройка проекта

DAS API

DAS API — это спецификация и система с открытым исходным кодом от Helius. API предоставляет простой интерфейс для взаимодействия с цифровыми активами в блокчейне Solana. Он поддерживает разные типы токенов, включая взаимозаменяемые токены, обычные NFT и сжатые NFT, а также предлагает такие возможности, как индексирование метаданных вне блокчейна.

Настройка ключа API

Чтобы получить ключ Helius API, откройте портал Helius для разработчиков. Вот как начать работу:

  1. Создайте аккаунт с помощью кошелька Solana, аккаунта Google или GitHub.
  2. После входа вам будет предложено создать ключ API.
  3. Храните этот ключ в безопасном месте: он понадобится для выполнения вызовов API.

Создание приложения Next.js

Шаг 1. Настройка проекта Next.js

Создайте новое приложение Next.js с Tailwind

Код
npx create-next-app@latest helius-portfolio --typescript --eslint

Используйте следующие параметры конфигурации:

Это позволит использовать Tailwind CSS для стилизации, а также новый App router.

Код
cd helius-portfolio

‍Шаг 2. Создание компонентов

Создайте папку components в каталоге app, чтобы сохранить упорядоченную структуру.

Компонент SearchBar (components/SearchBar.js):

Этот компонент обрабатывает ввод адресов кошельков. Он использует хук useState для управления состоянием адреса и useRouter для навигации после отправки формы. Форма стилизована с помощью классов Tailwind CSS и выглядит лаконично.

Компонент TokenCard (components/TokenCard.js):

Этот компонент предназначен для отображения информации о токене. Он условно отображает разные макеты для взаимозаменяемых и невзаимозаменяемых токенов и использует типы Token и Attribute из ../types/Token.

Компонент 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, и показать её на карточке.

Например, для cNFTs можно показать сведения о сжатии, а для активов с надписями — сведения о надписях. Подробнее о доступных данных можно узнать в документации 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

Для получения данных токенов мы используем метод searchAssets из DAS API. Этот метод позволяет задавать такие критерии, как адреса кошельков и типы токенов.

Создание папки lib:

  1. Создайте папку lib в каталоге app для вызова API.
  2. Создайте в ней файл 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 и взаимодействия с блокчейном Solana через DAS API.

‍

Подпишитесь на Helius

Следите за новостями разработки на Solana и получайте уведомления о наших публикациях

Увеличенное изображение