MetaMask SDK를 Next.js와 함께 구현하는 방법

Next.js에서 MetaMask로 '지갑 연결' 버튼을 통합하는 방법을 알아보세요. 이 튜토리얼에서는 설정, MetaMask SDK 사용법, ShadcnUI를 활용한 UI 생성을 다룹니다...

6분 읽기
MetaMask SDK를 Next.js와 함께 구현하는 방법

web3에서 지갑(wallet)은 사용자가 블록체인 네트워크와 상호작용할 수 있도록 해주는 디지털 애플리케이션을 의미합니다. 지갑은 사용자와 블록체인의 탈중앙화 세계를 연결하는 다리 역할을 합니다. 이메일과 비밀번호 조합 또는 OAuth 서비스를 인증에 활용하는 기존 웹 애플리케이션과 달리, web3 앱은 지갑 소유권과 연결된 개인 키(private key)를 기반으로 사용자를 인증합니다. "Connect Wallet" 버튼은 이 인증 과정을 시작하는 역할을 합니다.

이 튜토리얼에서는 MetaMask 지갑과의 인증 과정을 시작하는 "Connect Wallet" 버튼을 Next.js 앱에 구현해 보겠습니다.

사전 요구사항:

  • 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 hook: 먼저 MetaMask SDK의 기능에 접근할 수 있게 해주는 useSDK hook에 집중합니다. 이 hook은 MetaMask와 상호작용하기 위한 SDK 객체, 지갑 연결 여부를 확인하는 connected 불리언(boolean), 연결 상태를 확인하는 connecting 불리언, 그리고 사용자의 계정 주소에 접근하기 위한 account를 제공합니다.

2. Connect 및 disconnect 함수: connect와 disconnect, 두 가지 핵심 함수가 설정됩니다. connect 함수는 SDK를 사용하여 MetaMask 지갑과의 연결을 시도하는 비동기 작업입니다. 연결이 성공하면 useSDK hook의 connected 및 account 값이 업데이트됩니다. 반면 disconnect 함수는 sdk.terminate()를 호출하여 지갑 연결을 해제하는 데 사용됩니다.

3. UI 요소: 구현에는 버튼과 팝오버(popover), 두 가지 UI 요소가 포함됩니다. 컴포넌트의 렌더링은 연결 상태에 따라 변경됩니다. 연결된 경우 형식화된 계정 주소와 연결 해제 옵션을 보여주는 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에서 필요한 컨텍스트를 제공하기 위해 @metamask/sdk-react에서 가져온 MetaMaskProvider 컴포넌트로 ConnectWalletButton을 감쌉니다.

  • 지갑 아이콘: 지갑 아이콘을 가져오기 위해 SVG 이미지를 React 컴포넌트로 변환하는 도구인 SVGR을 사용했습니다.

전체 지갑 주소가 NavBar에서 너무 많은 공간을 차지하지 않도록, lib 폴더 내의 utils.ts 파일을 수정할 것입니다. 이를 통해 주소가 더 간결한 형식으로 표시됩니다.

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를 시작하는 방법에 대한 입문이었지만, 이를 활용하여 훨씬 더 많은 것을 할 수 있으며 풀스택 애플리케이션에서도 사용할 수 있습니다. 이 프로젝트의 코드는 이 저장소에서 확인할 수 있습니다.

다음 리소스도 확인해 보시길 권장합니다:

즐거운 개발 되세요. 🚀

AI가 번역했습니다. 오류가 있을 수 있습니다. 항상 정보를 확인하시기 바랍니다.

번역 평가하기