Skip to main content

Create a Next.js wallet connector

For the complete documentation index, see llms.txt

이 가이드에서는 DApp Connector API를 활용하여 Midnight 지갑(예: Lace)에 연결하는 Next.js 애플리케이션을 만들어 봅니다. 연결 상태를 보여주는 지갑 연결 버튼을 구현하며, 이를 바탕으로 더 복잡한 DApp을 개발할 수 있습니다.

코드 예시는 핵심 기능에 집중하기 위해 CSS 스타일링을 포함하지 않습니다. Tailwind, styled-components, CSS 모듈 등 원하는 스타일링 도구를 자유롭게 적용하시면 됩니다.

Prerequisites​

시작하기 전에 다음 사항을 준비하세요:

  • TypeScript 및 JavaScript 기본 지식
  • React 및 Next.js 기초에 대한 이해
  • Node.js와 npm 설치
  • 브라우저에 Midnight 지갑 확장 프로그램, 예를 들어 Lace 설치

Set up a Next.js project​

Next.js 프로젝트가 없다면 다음 명령으로 새 프로젝트를 생성합니다:

npm create-next-app@latest <project-name>

설정 프롬프트에서 다음과 같이 선택합니다:

  • TypeScript: Yes
  • ESLint: Yes
  • Tailwind CSS: Yes (선택 사항이나 권장)
  • App Router: Yes
  • 기타 옵션: 원하는 대로 선택

이어서 프로젝트 디렉토리로 이동한 뒤 DApp Connector API 패키지를 설치합니다:

cd <project-name>
npm install @midnight-ntwrk/dapp-connector-api
note

이 가이드는 DApp Connector API v4.0.1을 사용합니다. 자세한 내용은 DApp Connector API 문서를 참조하세요.

이 튜토리얼을 마치면 다음 내용을 이해할 수 있습니다:

  • Next.js 애플리케이션에 지갑 연결을 통합하는 방법
  • 지갑 작업 시 클라이언트 컴포넌트와 서버 컴포넌트의 차이
  • Next.js에서의 지갑 상태 관리
  • Next.js에서 DApp Connector API를 사용하는 모범 사례
1

Create the wallet connection component​

지갑 연결을 처리하는 클라이언트 사이드 컴포넌트를 만듭니다. 지갑 API는 브라우저 환경에서만 사용할 수 있으므로, Next.js의 "use client" 디렉티브로 클라이언트 사이드 실행을 지정해야 합니다.

버튼이 지갑에 구애받지 않도록 먼저 app/lib/selectWallet.ts를 만듭니다. 지갑은 window.midnight 아래에 Initial API를 설치하는데, 각각 고정된 이름이 아니라 새로 생성된 UUID를 키로 씁니다. window.midnight.mnLace 같은 하드코딩한 키는 현재 Lace 릴리스에서 undefined로 해석되고 다른 지갑을 놓치므로, 대신 Object.values(window.midnight)로 항목을 읽으세요. 이는 React wallet connector guide가 쓰는 것과 같은 패턴입니다.

import type { InitialAPI } from "@midnight-ntwrk/dapp-connector-api";

export const listWallets = (): InitialAPI[] => {
const injected = window.midnight;
return injected ? Object.values(injected) : [];
};

export const selectWallet = (): InitialAPI => {
const wallets = listWallets();

if (wallets.length === 0) {
throw new Error("No Midnight wallet found. Please install a Midnight wallet extension.");
}

return wallets[0];
};

selectWallet 함수는 설치된 첫 번째 지갑을 반환하며, 이는 이 예제를 연결 흐름에 집중시킵니다. 지갑이 둘 이상 있을 때, DApp Connector API 명세는 여러분이 대신 고르지 말고 사용자가 고르게 할 것을 기대합니다. 명세는 또한 각 지갑의 apiVersion을 확인하고 여러분 DApp이 지원하지 않는 버전의 지갑은 건너뛸 것을 기대합니다. listWallets로 선택지를 렌더링하고, 각 지갑의 name과 icon은 XSS를 막기 위해 안전하게 렌더링하세요.

그런 다음 app/components/ConnectWalletButton.tsx를 생성합니다:

"use client"; // 클라이언트 사이드 렌더링을 위한 Next.js 디렉티브

import { useState } from "react";
import "@midnight-ntwrk/dapp-connector-api";
import { selectWallet } from "../lib/selectWallet";

export default function ConnectWalletButton() {
const [connected, setConnected] = useState(false);
const [walletAddress, setWalletAddress] = useState<string | null>(null);

const handleConnect = async () => {
try {
// window.midnight를 열거 - mnLace를 하드코딩하지 말 것
const wallet = selectWallet();

// 지정된 네트워크에 연결 (로컬 개발의 경우 'undeployed' 사용)
const connectedApi = await wallet.connect("preprod");

// 표시용으로는 unshielded 주소를 우선; shielded는 필요할 때만 요청
const { unshieldedAddress } = await connectedApi.getUnshieldedAddress();
const address = unshieldedAddress;

// 연결이 설정되었는지 확인
const connectionStatus = await connectedApi.getConnectionStatus();

if (connectionStatus.status === "connected") {
setConnected(true);
setWalletAddress(address);
console.log("Connected to wallet:", address);
}
} catch (error) {
console.log("Failed to connect:", error);
}
};

const handleDisconnect = () => {
setConnected(false);
setWalletAddress(null);
};

return (
<nav className="flex items-center w-full p-4">
<div className="ml-auto flex flex-col items-end gap-2">
{connected && walletAddress && (
<div className="text-sm text-gray-600">
{walletAddress.slice(0, 8)}...{walletAddress.slice(-6)}
</div>
)}
<button
type="button"
onClick={connected ? handleDisconnect : handleConnect}
className="px-4 py-2 rounded-lg bg-black text-white hover:bg-gray-800 transition-colors"
>
{connected ? "Disconnect" : "Connect Wallet"}
</button>
</div>
</nav>
);
}

이 컴포넌트의 지갑 연결 흐름은 다음과 같습니다:

  1. 클라이언트 사이드 렌더링: "use client" 디렉티브를 통해 브라우저에서 실행되므로 지갑 API에 접근할 수 있습니다.
  2. 상태 관리: React의 useState 훅으로 연결 상태와 지갑 주소를 관리합니다.
  3. 연결 로직: handleConnect 함수가 window.midnight를 열거해 지갑을 선택하고, 네트워크에 연결한 뒤, unshielded 주소를 가져옵니다.
  4. 사용자 피드백: 지갑 주소를 축약하여 표시하고, 연결/연결 해제 동작을 제공합니다.
2

Add the component to your layout​

지갑 버튼을 애플리케이션 레이아웃에 추가하여 모든 페이지에서 표시되도록 합니다.

app/layout.tsx를 다음과 같이 수정합니다:

import type { Metadata } from "next";
import "./globals.css";
import ConnectWalletButton from "./components/ConnectWalletButton";

export const metadata: Metadata = {
title: "Midnight Wallet Connector",
description: "Connect to a Midnight wallet",
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<ConnectWalletButton />
<main className="container mx-auto px-4 py-8">
{children}
</main>
</body>
</html>
);
}

ConnectWalletButton 컴포넌트가 모든 페이지 상단에 표시됩니다. Next.js의 레이아웃 시스템을 활용하면 모든 라우트에 공통 UI 요소를 간편하게 배치할 수 있습니다.

3

Create a welcome page​

지갑 연결을 안내하는 간단한 랜딩 페이지를 만듭니다.

app/page.tsx의 내용을 다음으로 교체합니다:

export default function Home() {
return (
<div className="flex flex-col items-center justify-center min-h-[60vh] text-center">
<h1 className="text-4xl font-bold mb-4">
Welcome to Midnight
</h1>
<p className="text-lg text-gray-600 mb-8 max-w-2xl">
Connect your Lace wallet to get started with privacy-preserving
decentralized applications on the Midnight Network.
</p>
<div className="bg-gray-100 p-6 rounded-lg max-w-xl">
<p className="text-sm text-gray-700">
Click the "Connect Wallet" button in the top right corner to authorize
this application to access your Midnight Lace wallet.
</p>
</div>
</div>
);
}
4

Run your application​

Next.js 개발 서버를 시작합니다:

npm run dev

브라우저를 열고 http://localhost:3000으로 이동합니다.

Connect Wallet을 클릭하면 Midnight Lace 지갑 확장 프로그램에서 연결 승인을 요청합니다.

Connect Wallet

지갑에서 인증 방식 선택 화면이 나타납니다:

  • Always: 영구 인증입니다. 브라우저를 닫아도 인증 상태가 유지되므로, 이후 방문 시 다시 연결할 필요가 없습니다.
  • Only once: 일회성 인증입니다. 애플리케이션을 방문할 때마다 다시 연결을 승인해야 합니다.

Authorize Connection

승인하면 버튼이 "Disconnect"로 바뀌고 축약된 지갑 주소가 표시됩니다.

Connected Wallet

5

Verify the connection​

지갑이 애플리케이션에 올바르게 연결되었는지 확인하는 방법입니다:

  1. 브라우저에서 Midnight Lace 지갑 확장 프로그램을 엽니다.
  2. 오른쪽 상단의 지갑 이름을 클릭하고 Settings를 선택합니다.
  3. Authorized DApps로 이동합니다.

http://localhost:3000이 인증된 애플리케이션 목록에 표시되어야 합니다.

Authorized DApps

애플리케이션 옆의 trash 아이콘을 클릭하면 언제든지 접근 권한을 해제할 수 있습니다.

Troubleshooting​

자주 발생하는 문제와 해결 방법을 안내합니다.

"window is not defined" error​

Next.js는 기본적으로 서버에서 컴포넌트를 렌더링하는데, 지갑 API는 브라우저 환경에서만 사용할 수 있어서 발생하는 에러입니다.

해결 방법: 지갑 컴포넌트 파일 상단에 "use client" 디렉티브가 있는지 확인하세요.

Wallet not detected​

브라우저가 window.midnight에 접근할 수 없는 경우로, Midnight Lace 지갑 확장 프로그램이 사용 불가능한 상태입니다.

해결 방법:

  • Midnight Lace 지갑 확장 프로그램이 설치되어 있고 활성화 상태인지 확인합니다.
  • 확장 프로그램 설치 후 페이지를 새로고침합니다.
  • 브라우저 콘솔에서 확장 프로그램 관련 에러를 확인합니다.
  • 서버 사이드 렌더링이 아닌 브라우저 환경에서 테스트 중인지 확인합니다.

Connection fails​

지갑 연결 시도가 실패하는 경우로, 네트워크 설정이나 지갑 상태 등 여러 원인이 있을 수 있습니다.

해결 방법:

  • 올바른 네트워크 ID를 사용하고 있는지 확인합니다. 로컬 개발에는 'undeployed', Preprod 환경에는 'preprod'를 사용합니다.
  • Lace 지갑의 잠금이 해제되어 있는지 확인합니다.
  • 브라우저 콘솔에서 구체적인 에러 메시지를 확인합니다.
  • DApp Connector API 패키지가 올바르게 설치되었는지 확인합니다.

Next steps​

Next.js 지갑 커넥터가 완성되었으므로, 다음과 같은 기능을 추가하여 애플리케이션을 확장해 보세요:

  • 보호된 라우트 만들기: Next.js 미들웨어로 지갑 연결이 필요한 페이지에 대한 접근을 제한합니다.
  • 코인 전송: 다른 주소로 토큰을 전송하는 폼을 구현합니다.
  • 잔액 표시: 대시보드 페이지에 토큰 잔액을 표시합니다.
  • 트랜잭션 기록: 트랜잭션 내역을 조회하고 표시하는 페이지를 만듭니다.

Reference​