Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at dbb610
20 changes: 20 additions & 0 deletions week-05/frontend-template/.next/app-build-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"pages": {
"/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/page.js"
],
"/layout": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/css/app/layout.css",
"static/chunks/app/layout.js"
],
"/_not-found/page": [
"static/chunks/webpack.js",
"static/chunks/main-app.js",
"static/chunks/app/_not-found/page.js"
]
}
}
16 changes: 16 additions & 0 deletions week-05/frontend-template/.next/build-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [
"static/development/_buildManifest.js",
"static/development/_ssgManifest.js"
],
"rootMainFiles": [],
"pages": {
"/_app": []
},
"ampFirstPages": []
}
1 change: 1 addition & 0 deletions week-05/frontend-template/.next/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "commonjs"}
1,013 changes: 1,013 additions & 0 deletions week-05/frontend-template/.next/react-loadable-manifest.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

{
"/_not-found/page": "app/_not-found/page.js",
"/page": "app/page.js"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST="[]"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
self.__BUILD_MANIFEST = {
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [],
"ampDevFiles": [],
"lowPriorityFiles": [],
"rootMainFiles": [],
"pages": {
"/_app": []
},
"ampFirstPages": []
};
self.__BUILD_MANIFEST.lowPriorityFiles = [
"/static/" + process.env.__NEXT_BUILD_ID + "/_buildManifest.js",
,"/static/" + process.env.__NEXT_BUILD_ID + "/_ssgManifest.js",

];
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"version": 3,
"middleware": {},
"functions": {},
"sortedMiddleware": []
}

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"pages":{},"app":{},"appUsingSizeAdjust":false,"pagesUsingSizeAdjust":false}
1 change: 1 addition & 0 deletions week-05/frontend-template/.next/server/pages-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"node": {},
"edge": {},
"encryptionKey": "I6TsLoCG0WPpwfWtVl1wwRSlwHwrZ0p4GyCXs4Vkrvc="
}
1 change: 1 addition & 0 deletions week-05/frontend-template/.next/static/chunks/polyfills.js

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
5 changes: 5 additions & 0 deletions week-05/frontend-template/.next/trace

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions week-05/frontend-template/.next/types/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "module"}
141 changes: 141 additions & 0 deletions week-05/frontend-template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Bay-17th dApp 프론트엔드 템플릿

Web3 dApp 개발을 위한 Next.js + wagmi + RainbowKit 스타터 템플릿입니다.

## 시작하기

### 1. 의존성 설치

```bash
npm install
```

### 2. WalletConnect Project ID 설정

1. [WalletConnect Cloud](https://cloud.walletconnect.com)에 접속
2. 회원가입 후 새 프로젝트 생성
3. `config/wagmi.ts` 파일에서 `YOUR_PROJECT_ID`를 발급받은 ID로 교체

```typescript
const WALLETCONNECT_PROJECT_ID = 'your-actual-project-id';
```

> **참고:** Project ID 없이도 개발 서버에서는 동작하지만, 프로덕션 배포 시 반드시 필요합니다.

### 3. 개발 서버 실행

```bash
npm run dev
```

브라우저에서 [http://localhost:3000](http://localhost:3000)을 열어 확인하세요.

## 파일 구조

```
frontend-template/
├── app/
│ ├── layout.tsx # 루트 레이아웃 (Provider 설정)
│ └── page.tsx # 메인 페이지
├── components/
│ └── WalletConnect.tsx # 지갑 연결 컴포넌트
├── config/
│ └── wagmi.ts # wagmi + RainbowKit 설정
├── package.json
├── tsconfig.json
└── next.config.mjs
```

## 주요 라이브러리

| 라이브러리 | 버전 | 설명 |
|-----------|------|------|
| wagmi | ^2.0.0 | React hooks for Ethereum |
| viem | ^2.0.0 | TypeScript Ethereum 라이브러리 |
| @rainbow-me/rainbowkit | ^2.0.0 | 지갑 연결 UI |
| @tanstack/react-query | ^5.0.0 | 데이터 페칭 상태 관리 |
| next | ^14.0.0 | React 프레임워크 |

## 컨트랙트 연동하기

### 1. 컨트랙트 읽기 (Read)

```typescript
import { useReadContract } from 'wagmi';

const { data, isLoading } = useReadContract({
address: '0x...', // 컨트랙트 주소
abi: contractABI, // ABI
functionName: 'getValue',
});
```

### 2. 컨트랙트 쓰기 (Write)

```typescript
import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi';

const { writeContract, data: hash } = useWriteContract();
const { isLoading, isSuccess } = useWaitForTransactionReceipt({ hash });

// 함수 호출
writeContract({
address: '0x...',
abi: contractABI,
functionName: 'setValue',
args: [42],
});
```

### 3. ABI 타입 안전하게 사용하기

```typescript
// ABI를 const로 선언하면 타입 추론이 자동으로 됩니다
const contractABI = [
{
name: 'getValue',
type: 'function',
stateMutability: 'view',
inputs: [],
outputs: [{ type: 'uint256' }],
},
] as const; // 중요: as const
```

## 참고 자료

- [wagmi-basics.md](/week-04/dev/wagmi-basics.md) - wagmi 상세 가이드
- [rainbowkit-guide.md](/week-05/dev/rainbowkit-guide.md) - RainbowKit 상세 가이드
- [wagmi 공식 문서](https://wagmi.sh)
- [RainbowKit 공식 문서](https://www.rainbowkit.com)
- [viem 공식 문서](https://viem.sh)

## Sepolia 테스트넷 ETH 받기

개발 및 테스트에 필요한 테스트넷 ETH는 아래 Faucet에서 받을 수 있습니다:

- [Alchemy Sepolia Faucet](https://sepoliafaucet.com)
- [Infura Sepolia Faucet](https://www.infura.io/faucet/sepolia)
- [QuickNode Sepolia Faucet](https://faucet.quicknode.com/ethereum/sepolia)

## 문제 해결

### Hydration 오류

`config/wagmi.ts`에서 `ssr: true` 옵션이 설정되어 있는지 확인하세요.

### WalletConnect 연결 안 됨

Project ID가 올바르게 설정되어 있는지 확인하세요.

### BigInt 타입 오류

컨트랙트에서 반환된 숫자는 BigInt입니다. 문자열로 변환하려면:

```typescript
const valueString = data?.toString();
```

## 라이선스

Bay-17th 학회 교육용
57 changes: 57 additions & 0 deletions week-05/frontend-template/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use client';

// ============================================================
// RainbowKit 스타일 import
// ============================================================
// RainbowKit의 UI 컴포넌트가 제대로 표시되려면
// 반드시 이 스타일시트를 import해야 합니다.
import '@rainbow-me/rainbowkit/styles.css';

import { RainbowKitProvider } from '@rainbow-me/rainbowkit';
import { WagmiProvider } from 'wagmi';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { config } from '@/config/wagmi';

// ============================================================
// React Query 클라이언트 설정
// ============================================================
// wagmi v2는 내부적으로 TanStack Query를 사용합니다.
// 이 클라이언트가 데이터 캐싱, 리페칭, 동기화를 담당합니다.
const queryClient = new QueryClient();

// ============================================================
// Root Layout
// ============================================================
// Next.js App Router의 루트 레이아웃입니다.
// 모든 페이지가 이 레이아웃을 공유합니다.
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body>
{/* ============================================================
Provider 순서가 중요합니다!
============================================================
WagmiProvider > QueryClientProvider > RainbowKitProvider
1. WagmiProvider: 가장 바깥. wagmi config를 전체 앱에 제공
2. QueryClientProvider: 데이터 페칭 상태 관리
3. RainbowKitProvider: 지갑 UI 및 연결 상태 관리
순서가 바뀌면 "Cannot find WagmiContext" 같은 오류 발생!
============================================================ */}
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
{children}
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
</body>
</html>
);
}
23 changes: 23 additions & 0 deletions week-05/frontend-template/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { WalletConnect } from '@/components/WalletConnect';
import { EthTransfer } from '@/components/EthTransfer';

// ============================================================
// 메인 페이지
// ============================================================
// 이 페이지는 서버 컴포넌트입니다.
// 클라이언트 전용 기능(지갑 연결 등)은 WalletConnect 컴포넌트에서 처리합니다.
export default function Home() {
return (
<main className="min-h-screen p-8 max-w-lg">
<h1 className="text-2xl font-bold mb-4">Bay-17th dApp</h1>

{/* 지갑 연결 컴포넌트 */}
<WalletConnect />

{/* ETH 전송 컴포넌트 */}
<div className="mt-4">
<EthTransfer />
</div>
</main>
);
}
Loading