Skip to main content

React 지갑 커넥터 만들기

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

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

Prerequisites

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

Set up a React project

React 프로젝트가 없다면 Vite로 새 프로젝트를 생성합니다:

npm create vite@latest my-wallet-app -- --template react-ts
cd my-wallet-app

이어서 DApp Connector API 패키지를 설치합니다:

npm install @midnight-ntwrk/dapp-connector-api

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

  • Midnight 지갑 연결 흐름
  • DApp Connector API 사용법
  • React 애플리케이션에서 지갑 상태를 관리하는 모범 사례
1

Define TypeScript interfaces

먼저 컴포넌트에 필요한 타입을 정의합니다. 이 인터페이스를 통해 타입 안전성을 확보하고 컴포넌트 간 데이터 구조를 명확히 합니다.

src 디렉토리에 types.ts 파일을 생성하고 다음 코드를 추가합니다:

export interface WalletCardProps {
isConnected: boolean;
walletAddress: string | null;
onConnect: () => void;
onDisconnect: () => void;
}

WalletCardProps 인터페이스는 WalletCard 컴포넌트가 받는 데이터의 구조를 정의합니다. 연결 상태, 지갑 주소, 연결/연결 해제용 콜백 함수가 포함됩니다.

2

Create the WalletCard component

다음으로 지갑 연결 상태를 표시하고 연결/연결 해제 버튼을 제공하는 WalletCard 컴포넌트를 만듭니다.

src 디렉토리에 WalletCard.tsx를 생성하고 다음 코드를 추가합니다:

import React from "react";
import type { WalletCardProps } from "./types";

const WalletCard: React.FC<WalletCardProps> = ({
isConnected,
walletAddress,
onConnect,
onDisconnect,
}) => {
return (
<div>
<div>
<h2>Connection Status</h2>
<div>
{isConnected ? "Connected" : "Disconnected"}
</div>
</div>

<div>
{isConnected && walletAddress ? (
<>
<p>Wallet Address:</p>
<p title={walletAddress}>{walletAddress}</p>
</>
) : (
<p>Please connect your wallet to proceed.</p>
)}
</div>

<div>
{isConnected ? (
<button onClick={onDisconnect}>Disconnect Wallet</button>
) : (
<button onClick={onConnect}>Connect Wallet</button>
)}
</div>
</div>
);
};

export default WalletCard;

이 컴포넌트는 지갑 연결의 화면 표시를 담당합니다. 현재 연결 상태를 보여주고, 연결되면 주소를 표시하며, 상태에 맞는 동작 버튼을 렌더링합니다.

3

Integrate the DApp Connector API

이제 DApp Connector API로 지갑 연결 로직을 관리하는 App 컴포넌트를 작성합니다.

src 디렉토리의 App.tsx를 생성하거나 열고, 기존 코드를 다음으로 교체합니다:

import React, { useState } from 'react';
import WalletCard from './WalletCard';
import '@midnight-ntwrk/dapp-connector-api';
import type { InitialAPI } from '@midnight-ntwrk/dapp-connector-api';

const App: React.FC = () => {
const [isConnected, setIsConnected] = useState<boolean>(false);
const [walletAddress, setWalletAddress] = useState<string | null>(null);

const handleConnect = async () => {
console.log('Connect button clicked');
let isConnected = false;
let address = null;

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

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

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

// 선택 사항: 서비스 URI 구성 가져오기
const serviceUriConfig = await connectedApi.getConfiguration();
console.log('Service URI Config:', serviceUriConfig);

// 연결이 설정되었는지 확인
const connectionStatus = await connectedApi.getConnectionStatus();
if (connectionStatus) {
isConnected = true;
console.log("Connected to the wallet:", address);
}
} catch (error) {
console.log("An error occurred:", error);
}

setIsConnected(isConnected);
setWalletAddress(address);
};

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

return (
<div>
<header>
<h1>Midnight Wallet Connector</h1>
</header>
<main>
<WalletCard
isConnected={isConnected}
walletAddress={walletAddress}
onConnect={handleConnect}
onDisconnect={handleDisconnect}
/>
</main>
</div>
);
};

export default App;

지갑 연결 과정을 단계별로 살펴보겠습니다:

  1. 지갑 접근: DApp Connector API는 window.midnight.{walletProvider}를 통해 지갑을 노출합니다. 여기서는 window.midnight.mnLace로 Midnight Lace 지갑에 접근합니다.
  2. 네트워크 연결: connect() 메서드에 네트워크 ID를 전달하여 호출합니다. 로컬 개발에는 'undeployed', Preview 테스트넷에는 'preview', PreProd 네트워크에는 'preprod'를 사용합니다.
  3. 주소 조회: 네트워크에 연결한 뒤 getShieldedAddresses() 메서드로 지갑의 shielded 주소를 가져옵니다.
  4. 상태 확인: getConnectionStatus()로 연결 여부를 확인합니다.

handleConnect 이벤트 핸들러가 이 모든 단계를 처리하고, 결과에 따라 컴포넌트 상태를 업데이트합니다. 사용자가 Connect Wallet 버튼을 클릭하면 Lace 지갑에서 연결 승인 팝업이 나타납니다.

4

Set up the entry point

React 애플리케이션의 진입점을 설정합니다. src 디렉토리의 main.tsx를 생성하거나 열고, 기존 코드를 다음으로 교체합니다:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);

마지막으로 프로젝트 루트의 index.html을 생성하거나 열고, 기존 코드를 다음으로 교체합니다:

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Midnight Wallet Connector</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
5

Run your application

진입점 설정을 마쳤으면 개발 서버를 시작합니다:

npm run dev

브라우저에서 로컬 개발 URL(보통 http://localhost:5173)에 접속합니다.

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

Connect Wallet

승인하면 애플리케이션에 연결 상태와 지갑의 shielded 주소가 표시됩니다.

Connected Wallet

Troubleshooting

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

Wallet not detected

window.midnight가 undefined인 경우:

  • 브라우저에 Midnight Lace 지갑 확장 프로그램이 설치되어 있고 활성화되어 있는지 확인합니다.
  • 확장 프로그램 설치 또는 활성화 후 페이지를 새로고침합니다.
  • 브라우저 콘솔에서 확장 프로그램 관련 에러를 확인합니다.

Connection fails

연결에 실패하는 경우:

  • connect() 메서드의 네트워크 ID가 지갑에 설정된 네트워크 ID와 일치하는지 확인합니다.
  • Lace 지갑이 잠금 해제 상태이고 동기화가 완료되었는지 확인합니다.
  • 브라우저 콘솔에서 구체적인 에러 메시지를 확인합니다.
  • DApp Connector API 패키지가 올바르게 설치되었는지 확인합니다.

Next steps

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

  • 코인 전송: 다른 주소로 토큰을 전송하는 폼을 구현합니다.
  • 메시지 서명: 지갑으로 임의 메시지에 서명할 수 있는 입력 기능을 추가합니다.
  • 잔액 표시: 다양한 자산별 토큰 잔액을 표시합니다.
  • 트랜잭션 기록: 트랜잭션 내역을 조회하고 표시합니다.
  • 멀티 네트워크 지원: 여러 Midnight 네트워크 간에 전환할 수 있는 네트워크 선택기를 추가합니다.

Reference