Как внедрить MetaMask SDK с Nextjs

Узнайте, как интегрировать кнопку «Connect Wallet» с MetaMask в Next.js. Этот туториал охватывает настройку, использование MetaMask SDK и создание UI с ShadcnUI для ...

6 мин чтения
Как внедрить MetaMask SDK с Nextjs

В web3 термин «кошелёк» обозначает цифровое приложение, позволяющее пользователям взаимодействовать с блокчейн-сетями. Кошельки служат мостом между пользователями и децентрализованным миром блокчейна. В отличие от традиционных веб-приложений, использующих комбинации email и пароля или OAuth-сервисы для аутентификации, web3-приложения аутентифицируют пользователей на основе владения кошельком и связанными с ним приватными ключами. Кнопка «Connect Wallet» инициирует этот процесс аутентификации.

В этом руководстве мы реализуем кнопку «Connect Wallet» в приложении Next.js, которая запускает процесс аутентификации с кошельком MetaMask.

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

  • Знакомство с Next.js и React.

  • Установленные Node.js и npm/yarn.

  • Расширение MetaMask, установленное в вашем браузере.

Это лишь базовые требования для данного руководства — лучший способ научиться — начать и осваивать всё по ходу.

Настройка проекта Next.js:

Для настройки проекта Next.js необходимо установить Node.js на вашем компьютере. После установки Node.js вы можете создать новое приложение Next.js, открыв терминал и выполнив следующую команду:

npx create-next-app@latest

Мы увидим следующие запросы:

npx create-next-app@latest
✔ What is your project named? … next-metamask-template
✔ 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 и устанавливает все необходимые зависимости. Перейдите в вашу папку.

cd next-metamask-template

и выполните команду npm run dev — она запускает приложение Next.js в режиме разработки, и вы можете просмотреть своё приложение, перейдя по адресу http://localhost:3000 в браузере.

Создание пользовательского интерфейса

Мы добавим в наше приложение библиотеку компонентов. Давайте установим 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
Копировать

Из библиотеки компонентов ShadcnUI мы будем использовать два компонента: Button и Popover.

Также мы будем использовать @metamask/sdk-react — подробнее об этом можно прочитать в документации MetaMask.

Установим SDK:

npm i @metamask/sdk-react

Мы создадим новый компонент NavBar.tsx и добавим кнопку «Connect Wallet» и SDK. Изначально наш компонент должен выглядеть следующим образом:

"use client";

import Link from "next/link";

import WalletIcon from "../public/icons/WalletIcon";

import { Button } from "./ui/button";

import { useSDK, MetaMaskProvider } from "@metamask/sdk-react";
import { formatAddress } from "../lib/utils";
import {
  Popover,
  PopoverTrigger,
  PopoverContent,
} from "@/components/ui/popover";

export const ConnectWalletButton = () => {
  const { sdk, connected, connecting, account } = useSDK();

  const connect = async () => {
    try {
      await sdk?.connect();
    } catch (err) {
      console.warn(`No accounts found`, err);
    }
  };

  const disconnect = () => {
    if (sdk) {
      sdk.terminate();
    }
  };

  return (
    <div className="relative">
      {connected ? (
        <Popover>
          <PopoverTrigger>
            <Button>{formatAddress(account)}</Button>
          </PopoverTrigger>
          <PopoverContent className="mt-2 w-44 bg-gray-100 border rounded-md shadow-lg right-0 z-10 top-10">
            
              Disconnect
            
          </PopoverContent>
        </Popover>
      ) : (
        <Button disabled={connecting} onClick={connect}>
          <WalletIcon className="mr-2 h-4 w-4" /> Connect Wallet
        </Button>
      )}
    </div>
  );
};
Копировать

Разберём, что мы сделали:

1. Хук useSDK: В первую очередь мы сосредоточимся на хуке useSDK, который открывает доступ к функциям MetaMask SDK. Этот хук предоставляет объект SDK для взаимодействия с MetaMask, булево значение connected для проверки подключения кошелька, булево значение connecting для отслеживания статуса подключения и account для доступа к адресу аккаунта пользователя.

2. Функции подключения и отключения: Реализация включает две ключевые функции: connect и disconnect. Функция connect — это асинхронная операция, которая пытается установить соединение с кошельком MetaMask через SDK. При успешном подключении она обновляет значения connected и account из хука useSDK. Функция disconnect, в свою очередь, используется для отключения кошелька путём вызова sdk.terminate().

3. Элементы UI: В нашей реализации используются два элемента UI — кнопка и popover. Отображение компонента меняется в зависимости от статуса подключения. При активном подключении отображается компонент Popover с отформатированным адресом аккаунта и опцией отключения. Если подключение отсутствует — показывается кнопка «Connect Wallet», которая блокируется во время выполняющейся попытки подключения.

Теперь добавим код для NavBar:

export const NavBar = () => {
  const host =
    typeof window !== "undefined" ? window.location.host : "defaultHost";

  const sdkOptions = {
    logging: { developerMode: false },
    checkInstallationImmediately: false,
    dappMetadata: {
      name: "Next-Metamask-Boilerplate",
      url: host, // using the host constant defined above
    },
  };

  return (
    <nav className="flex items-center justify-between max-w-screen-xl px-6 mx-auto py-7 rounded-xl">
      <Link href="/" className="flex gap-1 px-6">
        <span className="hidden text-2xl font-bold sm:block">
          <span className="text-gray-900">Template</span>
        </span>
      </Link>
      <div className="flex gap-4 px-6">
        <MetaMaskProvider debug={false} sdkOptions={sdkOptions}>
          <ConnectWalletButton />
        </MetaMaskProvider>
      </div>
    </nav>
  );
};

export default NavBar;
Копировать

Разберём, что мы сделали:

  1. Переменная host: Эта переменная определяет адрес хоста текущего окна для использования в параметрах SDK. Она включает условную проверку для определения того, выполняется ли код в браузерной среде.

  2. Параметры SDK: Это параметры конфигурации для MetaMask SDK, задающие настройки логирования и проверки установки, а также включающие метаданные о dapp.

  3. Компонент NavBar: NavBar содержит ссылку на главную страницу и включает компонент ConnectWalletButton. Для предоставления необходимого контекста из MetaMask SDK он оборачивает ConnectWalletButton в компонент MetaMaskProvider, импортированный из @metamask/sdk-react.

  • Иконка кошелька: для получения иконки кошелька мы использовали SVGR — инструмент, преобразующий SVG-изображения в React-компоненты.

Чтобы полный адрес кошелька не занимал слишком много места в NavBar, внесём изменения в файл utils.ts в папке lib. Это обеспечит отображение адреса в более компактном формате.

import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}
Копировать

Добавьте следующие строки:

export const formatBalance = (rawBalance: string) => {
  const balance = (parseInt(rawBalance) / 1000000000000000000).toFixed(2);
  return balance;
};

export const formatChainAsNum = (chainIdHex: string) => {
  const chainIdNum = parseInt(chainIdHex);
  return chainIdNum;
};

export const formatAddress = (addr: string | undefined) => {
  return `${addr?.substring(0, 8)}...`;
};
Копировать

Перечисленные функции — formatBalance, formatChainAsNum и formatAddress — предназначены для импорта и использования во всём dApp с целью единообразного форматирования и отображения данных блокчейна пользователям.

В компоненте NavBar мы импортируем их следующим образом:

import { formatAddress } from "../lib/utils";

И используем здесь на кнопке:

Теперь остаётся только импортировать NavBar.tsx в наш компонент layout.tsx.

Если мы запустим сервер разработки, то увидим внесённые изменения в нашем приложении.

Заключение

MetaMask SDK — действительно удобный инструмент, меняющий подход к разработке DApp. Он позволяет пользователям легко подключаться к браузерному расширению MetaMask и MetaMask Mobile.

Это было введение в работу с MetaMask SDK, однако его возможности этим не ограничиваются — SDK можно использовать и в fullstack-приложениях. Код этого проекта можно найти в репозитории здесь.

Также рекомендую ознакомиться со следующими ресурсами:

Удачной разработки. 🚀

Переведено ИИ. Может содержать ошибки. Пожалуйста, всегда проверяйте информацию.

Оцените перевод