Skip to main content

Next.js 지갑 커넥터 만들기

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

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

Prerequisites

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

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.0을 사용합니다. 자세한 내용은 DApp Connector API 문서를 참조하세요.

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

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

Create the wallet connection component

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

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

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

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

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

const handleConnect = async () => {
try {
// window 객체를 통해 Midnight Lace 지갑에 접근
const wallet: InitialAPI = await window.midnight!.mnLace;

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

// 지갑에서 shielded 주소 가져오기
const addresses = await connectedApi.getShieldedAddresses();
const address = addresses.shieldedAddress;

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

if (connectionStatus) {
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.mnLace로 지갑에 접근하고, 네트워크에 연결한 뒤, shielded 주소를 가져옵니다.
  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 Midnight Lace 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