바이오메트릭 Crypto Wallet 만들기 (실제로 작동하는!)
Source: Dev.to
“왜 또 이렇게 했지?” 순간
그래서, 저는 모바일 암호화폐 지갑을 만들었습니다. 하지만 그냥 지갑이 아니라, 얼굴(또는 지문)으로 지갑을 생성하고 가스 수수료 없이 돈을 보낼 수 있는 지갑입니다. 멋지죠? 사실 어느 정도는 멋지지만, 동시에 그렇지 않기도 합니다.
잠시 되돌아볼게요.
몇 주 전, 저는 Lazorkit을 우연히 발견했습니다. 그들은 이렇게 대담한 아이디어를 냈습니다: 사람들에게 12단어 시드 구문을 외우게 하는 대신(솔직히 대부분의 사람들은 스크린샷을 찍고 휴대폰이 도난당하지 않기를 기도하죠), 생체 인증을 사용하면 어떨까? 즉, 하루에 50번씩 휴대폰을 잠금 해제할 때 쓰는 Face ID 같은 것을 말이죠.
도전 수락.
What I Built
앱은 매우 직관적입니다:
- “Create Wallet” 을 탭합니다.
- 휴대폰이 Face ID 또는 지문을 요청합니다.
- 바로 – Solana 지갑이 생성됩니다.
- SOL 없이도 USDC 토큰을 보낼 수 있습니다 (paymaster를 통한 가스‑없는 트랜잭션).
그게 전부입니다. 시드 구문도 없습니다. “종이에 적어 매트리스 밑에 숨겨라” 같은 절차도 없습니다. 오직 당신의 얼굴만 있으면 됩니다.
Tech Stack
- React Native (Expo SDK 54 사용)
- TypeScript (깨지기 전에 무엇이 문제인지 알 수 있어서)
- Solana blockchain (테스트용 Devnet)
- Lazorkit SDK (마법의 소스)
- WebAuthn passkeys (진짜 마법의 소스)
“오 크랩” 순간들 (또는 내가 배운 것)
1. 폴리필은 당신의 숨은 적
React Native는 웹 브라우저가 제공하는 모든 JavaScript 전역 객체를 가지고 있지 않습니다. Solana SDK는 Buffer와 crypto.getRandomValues() 같은 것이 그냥… 존재하기를 기대합니다. 실제로는 존재하지 않죠.
무작위성에 관한 난해한 오류를 두 시간 동안 디버깅한 뒤, 폴리필을 정확히 올바른 순서로 앱 최상단에 import 해야 한다는 것을 깨달았습니다:
// This order matters. Don't ask me why. I've been hurt before.
import 'react-native-url-polyfill/auto';
import { Buffer } from 'buffer';
global.Buffer = Buffer;
import 'react-native-get-random-values';
이 순서를 바꾸면 앱이 바로 터집니다. 재미있는 시간이에요.
2. 시뮬레이터는 거짓말쟁이
시뮬레이터에서는 생체 인증을 제대로 테스트할 수 없습니다. 가능은 하지만, 물 사진만 보고 수영장을 테스트하는 것과 같습니다. iOS 시뮬레이터의 “가짜 Face ID” 기능은 어느 정도 동작하지만, Lazorkit 포털로 딥링크하고 다시 돌아오는 과정은… 이상해집니다.
핵심 팁: 실제 기기를 사용하세요. 실제 하드웨어에서 테스트하세요. 이 점만은 꼭 기억하세요.
3. WebAuthn은 실제로 꽤 멋짐
아무도 말해주지 않은 사실: WebAuthn 패스키는 더 나은 UX를 제공하는 공개키 암호화일 뿐입니다. 지갑을 만들 때:
- 휴대폰이 키 쌍을 생성합니다.
- 개인 키는 기기의 Secure Enclave(지문 데이터가 저장되는 곳)에 그대로 남습니다.
- 공개 키는 Lazorkit 포털 서비스에 전달됩니다.
- 서명이 필요하면, 휴대폰이 Face ID로 개인 키를 잠금 해제합니다.
즉, 하드웨어 지갑을 가지고 있는 것과 같은데, 휴대폰 자체가 하드웨어 지갑인 셈입니다. 머리가 폭발합니다.
4. 가스 없는 트랜잭션은 사실 가스가 있음
반전: “가스 없는” 트랜잭션에도 가스 비용이 존재합니다. 다만 사용자가 직접 내는 것이 아니라, 페이마스터가 대신 냅니다.
작동 방식
- 트랜잭션을 생성합니다(예: 친구에게 1 USDC 전송).
- 페이마스터 서비스가 이를 보고 “좋아, SOL 수수료를 내가 낼게.” 라고 합니다.
- 페이마스터가 자신의 지갑으로 트랜잭션에 서명합니다.
- 사용자는 자신의 바이오메트릭 지갑으로 서명합니다.
- 트랜잭션이 완료되고, 사용자는 $0를 지불합니다.
함정: 페이마스터는 토큰 계정을 대신 생성해 주지 않습니다. 받는 사람이 이미 USDC 계정을 가지고 있지 않다면 트랜잭션이 실패합니다. 테스트 중에 이 때문에 고생했지만, 결국 자신에게 USDC를 보내면 된다는 걸 깨달았습니다.
5. 딥링크는 어두운 마법
바이오메트릭 인증을 동작시키려면 앱이 다음을 해야 합니다:
- Safari/Chrome을 열고
- Lazorkit 포털 페이지를 로드하고
- Face ID를 트리거하고
- 다시 앱으로 리다이렉트
이를 위해 app.json에 딥링크 설정이 필요합니다:
{
"scheme": "lazorkitstarter"
}
이 설정을 제대로 맞추는 데 세 번이나 시도했습니다. 특수 문자나 공백을 쓰면 안 됩니다. 간단하게: 소문자, 공백 없음, 특수 문자 없음. 앞으로의 당신이 현재의 당신에게 감사할 겁니다.
“잠깐, 이거 진짜 작동해?” 순간
폴리필, 딥 링크와 씨름하고 내 트랜잭션이 계속 실패하는 이유를 이해하려 애쓰면서 (스포일러: 테스트 USDC가 없었음), 결국 작동시켰다.
앱을 열고 **“Create Wallet”**을 탭한 뒤, 휴대폰의 Face ID를 확인하고 BAM – 나는 솔라나 지갑을 얻게 되었다.
시드 구문 없음. 마찰 없음.
마치 공상 과학 영화 같은 느낌이었지만, 사실 좋은 API 설계일 뿐이다.
튜토리얼 (당신을 좋아하기 때문에)
튜토리얼 1: 생체 인증을 이용한 지갑 생성 (~30 min)
- 폴리필 설정 (올바른 방법)
LazorKitProvider구성- 앱과 포털 간 딥 링크 연결
- 생체 인증 콜백 처리
튜토리얼 2: 가스 없는 USDC 트랜잭션 (~40 min)
@solana/web3.js로 Solana 트랜잭션 구축- 가스 없는 수수료를 위한 페이마스터 통합
- 올바른 블록해시 관리 (60초 후 만료되며, 하루를 망칠 수 있음)
- 오류 처리 및 검증
이 프로젝트는 누구를 위한 것인가?
다음 경우라면 이 프로젝트를 구축해야 합니다:
- React Native를 배우고 실제 프로젝트를 원한다면.
- Solana 모바일 개발에 관심이 있다면.
- WebAuthn 패스키가 어떻게 작동하는지 이해하고 싶다면.
- 시드 구문 없이 암호화 지갑을 사용하는 아이디어가 마음에 든다면.
다음 경우라면 이 프로젝트를 만들 않아야 합니다:
- 프로덕션 수준의 코드가 필요하다면 (이것은 Devnet 전용입니다).
- TypeScript를 싫어한다면.
- 테스트할 물리적 디바이스가 없다면.
물리적 iPhone 또는 Android 디바이스에서 테스트하기
- 폴리필에 알레르기가 있다면. (가벼운 농담이지만 – 앱을 실행하려면 실제 디바이스가 필요하고, 폴리필 환경은 안 됩니다.)
TL;DR
Face ID 인증과 가스 없는 트랜잭션을 지원하는 모바일 암호화 지갑을 만들었습니다. WebAuthn 패스키(시드 구문 없음!)를 사용하고 Solana Devnet에서 실행되며 실제로 동작합니다. 폴리필, 딥링크, 그리고 시뮬레이터가 왜 친구가 아닌지에 대해 너무 많이 배웠습니다.
모바일 개발이나 블록체인에 대해 배우고 있다면 한 번 시도해 보세요. 최소한 import 순서에 대해 강한 의견을 갖게 될 겁니다.
이거 만들었나요? 막혔나요? 버그를 찾았나요? 연락 주세요 – 왜 문제가 생겼는지 이야기하는 건 언제든 환영합니다.
P.S. 이걸 시도했는데 폴리필 순서 때문에 앱이 크래시 난다면, 제가 미리 알려줬다는 걸 기억하세요. 😅