이 레포가 무엇을 하는 물건인가.
은행 앱에서 '거래 내역'을 누르면 날짜·금액·상대방이 보인다. 블록체인에도 모든 거래가 기록되지만, 날것 그대로는 16진수와 주소의 나열일 뿐이다. Solana Explorer는 이 날것을 받아 "누가 누구에게 얼마를 보냈고, 어떤 프로그램의 어떤 기능을 호출했는지"를 사람의 말로 풀어 준다. Solana판 '등기소 열람 + 번역기'인 셈이다.
Solana Explorer(저장소명 solana-foundation/explorer)는 Solana 재단이 운영하는 공식 블록 익스플로러다. 주소(지갑·프로그램·토큰 민트)를 넣으면 잔액·소유 토큰·거래 이력을, 트랜잭션 서명을 넣으면 그 거래가 호출한 명령들을, 슬롯 번호를 넣으면 블록 내용을 보여 준다. 누구나 회원가입 없이 온체인 데이터를 들여다볼 수 있는 read-only 조회 도구다.
차별점은 단순 표시가 아니라 "해석(inspect)"에 있다. 트랜잭션 한 건에는 System·Token·Serum·Mango·Pyth 같은 수십 종 프로그램의 명령이 섞여 들어가는데, Explorer는 각 프로그램의 IDL과 디코더를 동원해 "이건 토큰 전송", "이건 스왑"처럼 사람이 읽을 수 있는 카드로 변환한다. 그래서 코드 관점에서는 "온체인 바이트를 UI로 번역하는 거대한 파서 모음"이라고 봐도 된다.
mainnet-beta, 개발·테스트용 devnet·testnet, 그리고 직접 지정하는 custom이 있다. Explorer는 우상단에서 이 클러스터를 바꿔 가며 조회한다.트렌딩 이유 · 경쟁 대비 장점.
블록 익스플로러는 이미 Solscan·SolanaFM 등 상용 강자가 있다. 그런데도 이 레포가 주목받는 이유는 세 가지다. 첫째, Solana 재단의 공식 레퍼런스라 "Solana의 데이터를 어떻게 다뤄야 하는가"의 표준 구현으로 통한다. 둘째, 코드가 통째로 오픈소스(이 레포)라 web3 프론트엔드를 배우려는 사람에게 최고의 실전 교재다. 셋째, 기술 스택이 Next.js 16 + React 19 + @solana/kit로 매우 최신이라, "지금" 권장되는 방식이 코드에 그대로 담겨 있다.
| 비교 항목 | 일반 익스플로러 | Solana Explorer |
|---|---|---|
| 소스 공개 | 대부분 비공개 | 전체 오픈소스 — 학습·자체 호스팅 가능 |
| 명령 해석 | 주요 프로그램 위주 | 20+ 프로토콜 + IDL 동적 파싱(codama) |
| SDK 버전 | 레거시 web3.js 중심 | 레거시 + @solana/kit(신형) 병행 |
| 검증 기능 | 제한적 | Verified Build 대조 · 토큰 4중 교차검증 |
| 위치 | 서드파티 | 재단 공식 — 신뢰의 기준점 |
블록체인 데이터는 공개돼 있어도, RPC가 돌려주는 건 base58 주소와 바이트 배열뿐이다. 트랜잭션 하나에 어떤 프로그램의 어떤 기능이 호출됐는지, 토큰이 진짜인지 사칭인지, 빌드가 소스와 일치하는지는 날것만 봐서는 알 수 없다. 직접 파싱하려면 프로그램마다 IDL과 디코더를 구해야 한다.
프로그램별 전용 디코더 카드(System·Token·Serum·Mango·Pyth…)에, codama로 IDL을 동적 파서로 변환하는 범용 경로를 더했다. 토큰은 Jupiter·RugCheck·CoinGecko·Bluprynt 4곳으로 교차검증해 배지를 달고, 빌드는 OSEC 레지스트리로 온체인 해시를 대조한다. 도메인은 SNS/ANS로 풀어 .sol 이름을 보여 준다.
'온체인 번역기'를 떠받치는 기술들.
Solana Explorer는 파이썬 한 줄 없는 100% TypeScript 프론트엔드다. Next.js 16 App Router로 서버·클라이언트 렌더링을 함께 쓰고, 블록체인 접근은 레거시 web3.js와 신형 @solana/kit을 의도적으로 병행한다. 데이터 페칭은 SWR, 가벼운 상태는 Jotai, UI는 Radix/shadcn + Tailwind로 구성한 전형적인 모던 스택이다.
| 레이어 | 기술 | 역할 |
|---|---|---|
| 프레임워크 | Next.js 16.2 (App Router) | 라우팅·SSR·서버 라우트 핸들러(app/api/) · parallel route |
| 언어·런타임 | React 19 + TypeScript 5.7 | Node ^22 · 패키지 매니저 pnpm 10.17 |
| 블록체인(레거시) | @solana/web3.js 1.98 | Connection 기반 계정·트랜잭션 조회(기존 코드) |
| 블록체인(신형) | @solana/kit 6.5 | createSolanaRpc · 신규/리팩토링 권장 SDK(web3.js v2 계열) |
| 프로그램 클라이언트 | @solana-program/* | token·token-2022·system·stake·memo 등 모듈식 클라이언트 |
| IDL·디코딩 | @coral-xyz/anchor 0.30 + codama | Borsh 디코더 · IDL → 동적 파서 자동 생성 |
| 메타데이터·NFT | Metaplex umi + spl-account-compression | 토큰 메타데이터 · 압축 NFT(cNFT) DAS 조회 |
| 도메인 | Bonfida SNS + onsol ANS | .sol 및 멀티 TLD 이름 해석 |
| 데이터 페칭 | SWR 2.2 | RPC 응답 캐싱 · useSWRImmutable + 자체 캐시 리듀서 |
| 상태관리 | Jotai 2.15 | atom 단위 경량 전역 상태 |
| UI·스타일 | Tailwind 3.4 + Radix/shadcn + CVA | 유틸리티 CSS · 접근성 컴포넌트 · 변형(variant) 관리 |
| 검증·직렬화 | superstruct + borsh + buffer-layout | RPC 응답 런타임 스키마 검증 · 바이트 디코딩 |
| 테스트 | Vitest 3.2 + Playwright + Storybook | 유닛·브라우저 · E2E · 컴포넌트 카탈로그 |
| 배포·모니터링 | Vercel + Sentry + BotId | explorer.solana.com 호스팅 · 에러 추적 · 봇 차단 |
Connection 객체로 RPC를 호출한다. @solana/kit은 그 후속(v2 계열)으로, 트리쉐이킹·타입 안전·모듈성을 강화한 신형 SDK다. Explorer는 기존 코드를 한 번에 갈아엎지 않고 새 코드는 kit, 옛 코드는 web3.js로 두 SDK를 공존시킨다 — 대형 코드베이스의 점진적 마이그레이션 실례다.features/(기능)·entities/(도메인 모델)·shared/(공용)로 폴더를 나누고, AGENTS.md에 그 규칙을 못 박아 두었다. 기능이 수십 개로 늘어도 관련 코드가 한 폴더에 모이는 게 장점.주소 하나를 넣으면 화면까지 어떤 길을 거치는가.
사용자가 주소·서명·슬롯을 입력하면 대략 이렇게 흐른다: ① URL 라우팅 → ② 클러스터/RPC 결정 → ③ RPC 조회(SWR 캐시) → ④ 응답 검증(superstruct) → ⑤ 디코딩·파싱 → ⑥ 기능별 카드 렌더. 전체 그림 한 장:
가장 영리한 부분. RPC URL을 그대로 쓰지 않고 배포 환경에서는 api를 explorer-api로 바꿔 자체 RPC 인스턴스로 보낸다. 또 브라우저용과 서버용 환경변수를 분리해, 클라이언트는 NEXT_PUBLIC_*_RPC_URL, 서버(SSR·API route)는 *_RPC_URL(public 접두사 없음)을 쓴다.
// RPC URL 결정의 핵심(요지)
const modifyUrl = (url) => {
if (location.hostname === 'localhost') return url; // 로컬: 공용 RPC 그대로
return url.replace('api', 'explorer-api'); // 배포: 자체 RPC로
};
// clusterUrl(): 브라우저용 NEXT_PUBLIC_*_RPC_URL ?? modifyUrl(기본)
// serverClusterUrl(): SSR/API용 *_RPC_URL ?? modifyUrl(기본)
클러스터 enum은 MainnetBeta · Testnet · Devnet · Simd296 · Custom 5종인데, 특히 Simd296은 실험용 surfnet을 가리키는 별도 엔트리다. 표준 3종 외에 실험망과 커스텀까지 한 enum으로 다루는 게 포인트.
ClusterProvider가 useReducer로 상태(cluster·customUrl·status·clusterInfo)를 들고, URL 쿼리스트링 ?cluster=devnet을 useSearchParams로 파싱한다. 클러스터가 바뀌면 @solana/kit의 createSolanaRpc로 연결한 뒤 4개 RPC를 동시에 호출해 네트워크 메타 정보를 한 번에 채운다.
const rpc = createSolanaRpc(transportUrl);
const [firstBlock, epochSchedule, epochInfo, genesisHash] =
await Promise.all([
rpc.getFirstAvailableBlock().send(),
rpc.getEpochSchedule().send(),
rpc.getEpochInfo().send(),
rpc.getGenesisHash().send(),
]);
커스텀 URL은 아무 때나 허용하지 않는다 — localStorage의 enableCustomUrl 플래그가 켜졌거나 화이트리스트 도메인일 때만 받는다. 임의 RPC 주입을 막는 안전장치다.
트랜잭션 해석의 심장. Anchor의 BorshInstructionCoder·BorshEventCoder로 명령·이벤트를 디코딩하고, Anchor Self-CPI 태그(1d9acb512ea545e4)를 감지해 내부 호출을 구분한다. IDL이 있으면 codama가 그 IDL을 동적 파서로 변환해, 전용 카드가 없는 프로그램도 자동으로 풀어낸다.
Explorer는 "보여 주기"에 그치지 않고 진위 확인까지 한다. utils/verified-builds.tsx는 OSEC 레지스트리(verify.osec.io)로 온체인 프로그램 해시가 공개 소스와 일치하는지 대조해 Verified/NotVerified 배지를 단다. 토큰은 app/api/verification/*에서 Jupiter·RugCheck·CoinGecko·Bluprynt 4곳을 교차검증한다. 매일 cron 워크플로가 verified-programs.json을 자동 갱신해 PR을 연다.
App Router + FSD에서 어디가 무슨 일을 하나.
| 경로 | 역할 |
|---|---|
app/address/[address]/ | 이 레포의 간판 화면. 27개 하위 탭으로 계정의 온갖 면을 보여 준다. |
app/features/ | FSD 기능 슬라이스 24개. 검색·시뮬레이션·토큰 검증 등 "기능"이 한 폴더씩. |
app/entities/ | 도메인 모델 20개. account·nft·domain·instruction-parser 등 "명사"들. |
app/providers/cluster.tsx | 클러스터 전환과 RPC 연결의 중심. @solana/kit으로 메타 적재. |
app/utils/anchor.tsx | Borsh·codama 기반 명령 디코딩 — 트랜잭션 해석의 심장. |
app/api/ | 서버 라우트 핸들러 15개. 도메인·메타데이터 프록시·토큰 검증 등 서버 작업. |
AGENTS.md | 레포 자체의 개발 규약(FSD 강제·경로 별칭·신규는 kit). AI 협업 문서 예시. |
이 레포에서 배울 만한 것 + 어디를 보면 되는지.
대형 코드베이스를 한 번에 갈아엎지 않고, 새 코드는 @solana/kit, 옛 코드는 web3.js로 굴리는 실제 사례. "레거시를 어떻게 끌고 가면서 신기술을 도입하나"라는 현업의 영원한 숙제에 대한 답이 코드에 있다. providers/cluster.tsx(kit)와 providers/accounts/(web3.js)를 나란히 읽어 보자.
기능이 24개·엔티티가 20개로 늘어도 무너지지 않는 폴더 구조. features/entities/shared 경계를 ESLint(boundaries 플러그인)로 강제하고 경로 별칭(@features @entities)으로 상대경로를 금지한 게 핵심. AGENTS.md와 eslint.config.mjs를 함께 보면 "규칙을 코드로 강제하는" 방식이 보인다.
같은 계정을 여러 컴포넌트가 동시에 요청해도 한 번만 네트워크를 타게 묶고, useSWRImmutable로 불변 데이터를 캐시하는 패턴. RPC가 비싸고 잦은 환경에서 캐싱 전략이 왜 중요한지 체감할 수 있다. providers/cache.tsx와 각 providers/accounts/*부터.
RPC가 돌려주는 JSON은 신뢰할 수 없는 외부 입력이다. validators/의 superstruct 스키마로 런타임에 형태를 보증한 뒤에만 쓰는 방어적 설계를 배울 수 있다. TypeScript 타입은 컴파일 타임에 사라지므로, 진짜 안전은 런타임 검증에서 온다는 교훈.
app/ 폴더의 디렉토리 구조가 곧 URL이 되고, page.tsx는 화면, route.ts는 서버 API가 된다. Explorer는 app/api/의 라우트 핸들러로 도메인 해석·메타데이터 프록시 같은 서버 전용 작업(CORS 우회·키 숨김)을 처리한다.그냥 쓰려면 / 직접 빌드하려면 무엇이 필요한가.
| 항목 | 요구사항 |
|---|---|
| 그냥 쓰기 | 브라우저만 있으면 됨 — explorer.solana.com 접속 |
| 소스 빌드 | Node ^22 + pnpm 10.17 · pnpm install --frozen-lockfile |
| 실행 | pnpm dev(개발) · pnpm build → pnpm start(운영) |
| RPC 설정 | NEXT_PUBLIC_MAINNET_RPC_URL 등 환경변수(미설정 시 공용 RPC 사용) |
| 테스트 | pnpm test(Vitest) · pnpm test:e2e(Playwright) · pnpm sb(Storybook) |
| 배포 | Vercel 권장(Sentry·BotId·next.config 연동). GPU·서버 DB 불필요 |
환경변수 없이 띄우면 Solana 공용 RPC(api.mainnet-beta.solana.com)를 쓰는데, 이건 rate limit이 빡빡해 조금만 트래픽이 몰려도 막힌다. 자체 호스팅한다면 유료/전용 RPC 엔드포인트(Helius·QuickNode·Triton 등)를 *_RPC_URL로 넣어야 실사용이 가능하다. README의 법적 Disclaimer(OFAC·수출통제 면책)도 읽어 두자.
난이도별로 손에 익히는 단계.
클론해서 pnpm dev로 띄운 뒤, 우상단에서 클러스터를 devnet으로 바꿔 아무 트랜잭션이나 열어 본다. URL이 ?cluster=devnet으로 바뀌는 걸 보고, 같은 화면이 클러스터에 따라 어떻게 달라지는지 관찰하자.
git clone https://github.com/solana-foundation/explorer
cd explorer && pnpm install
pnpm dev # http://localhost:3000
아무 트랜잭션 페이지에서 명령(instruction) 카드를 펼쳐, System·Token 같은 프로그램이 어떻게 사람 말로 풀려 나오는지 본다. Inspector 화면(components/inspector/)에 raw 메시지를 붙여 넣어 디코딩되는 과정도 실험해 보자.
app/utils/cluster.ts의 modifyUrl·clusterUrl·serverClusterUrl을 따라 읽으며, localhost와 배포 환경에서 RPC 주소가 어떻게 달라지는지 정리한다. console.log를 찍어 실제로 어떤 URL로 요청이 나가는지 확인해 보자.
app/components/instruction/의 기존 카드(예 system) 하나를 본떠, 임의 프로그램의 명령을 예쁘게 보여 주는 카드를 새로 만들어 본다. IDL이 있는 프로그램이라면 codama 동적 파서 경로가 이미 처리하는지도 비교해 보자.
Helius 등에서 무료 devnet RPC 키를 받아 NEXT_PUBLIC_DEVNET_RPC_URL에 넣고, 자기 계정으로 Vercel에 배포해 본다. Sentry·BotId 환경변수 없이도 뜨는지, next.config.mjs의 래퍼들이 어떻게 동작하는지 확인하는 게 목표다.
한 주씩 따라가는 계획.
| 주차 | 주제 | 학습 자료 |
|---|---|---|
| 1주차 | Solana 기본 개념(계정·트랜잭션·프로그램·렌트) | Solana 공식 문서 · Explorer로 실제 데이터 보기 |
| 2주차 | Next.js 16 App Router + React 19 | Next.js 문서 · app/layout.tsx·app/api/ |
| 3주차 | @solana/web3.js vs @solana/kit 비교 | 두 SDK 문서 · providers/cluster.tsx 정독 |
| 4주차 | SWR 데이터 페칭 + 캐시 전략 | SWR 문서 · providers/cache.tsx |
| 5주차 | Anchor·IDL·codama로 온체인 데이터 디코딩 | Anchor 책 · utils/anchor.tsx·entities/idl/ |
| 6주차 | FSD 아키텍처 + superstruct 런타임 검증 | AGENTS.md·eslint.config.mjs·validators/ |
본문에 나온 용어 빠른 참조.
| 용어 | 의미 |
|---|---|
| 블록 익스플로러 | 블록체인의 거래·계정·블록을 웹에서 조회·해석하게 해 주는 도구. |
| 클러스터 | Solana 네트워크 인스턴스. mainnet-beta / devnet / testnet / custom. |
| RPC | 블록체인 노드에 데이터를 묻는 통신 규약·엔드포인트. getAccountInfo 등. |
| @solana/kit | web3.js의 후속 신형 Solana JS SDK. createSolanaRpc 사용. |
| IDL | Solana 프로그램의 명세(JSON). 명령을 사람 말로 디코딩하는 열쇠. |
| Anchor | Solana 스마트컨트랙트 프레임워크. Borsh 직렬화 + IDL 배포. |
| codama | IDL을 읽어 동적 파서/클라이언트를 생성하는 도구. 범용 디코딩 경로. |
| SWR | "오래된 캐시 먼저, 뒤에서 갱신"하는 React 데이터 페칭 라이브러리. |
| FSD | 코드를 도메인 기능 단위로 자르는 프론트엔드 아키텍처(features/entities). |
| superstruct | 외부 데이터의 형태를 런타임에 검증하는 스키마 라이브러리. |
| cNFT | 압축 NFT. 머클트리로 비용을 줄인 NFT. DAS API로 조회. |
| SNS / ANS | Solana 도메인 이름 서비스. .sol 등 사람이 읽는 주소를 해석. |
| Verified Build | 온체인 프로그램 해시가 공개 소스와 일치하는지 OSEC로 대조. |