난생 처음으로 해커톤, 그것도 Web3 해커톤에 참가하면서 느끼고 배운 점을 서술해보고자 한다.

우리 팀의 제출작

우리 팀은 해커톤과 별도로 검토 중이던 서비스 아이디어인 ‘온체인 데이터를 쉽게 보여주는 easy & lightweight Etherscan’ 의 아이디어를 발전시켜서, 온체인 데이터를 The Graph 프로토콜로 가져와 정제하여 온체인 데이터에 익숙하지 않은 사람에게 큐레이팅해 주는 타임라인 서비스 ChainFeed를 개발하였고, sponsor track - The Graph의 “Best new subgraph(s)” 부문 2등상을 수상하였다.

처음부터 The Graph 부문을 타겟으로 개발한 것은 아니었으나, 어쩌다 보니 The Graph의 GraphQL API를 사용할 수 있겠다 싶어 그 쪽으로 테크 스택을 발전시킨 것이 유효한 전략이었던 것으로 생각된다.

Tech Stack

  • DB - Supabase / PostgreSQL
  • Daemon - Typescript / Prisma / The Graph Client(GraphQL)
  • Frontend - React / Vite

최대한 트렌디하게~~(대책없이)~~ 구성한 테크 스택 되시겠다. 수상 욕심 없이 취미로 나가는 해커톤인 만큼 최대한 ‘이상적인’(그 말로는 뒤에 나온다) 스택을 구성하고자 했다.

단순히 온체인 데이터를 DB에 캐싱하여 프론트엔드에 전송하기만 하면 되는 서비스였기 때문에, Supabase로 백엔드 구현을 스킵하는 것이 좋은 효과를 낼 것이라고 생각하였다. 그러나 여기에는 몇 가지 함정이 존재하여 결과적으로는 별로 좋지 못한 선택이 되었다.

이종(heterogeneous) 스키마에 대한 고려

ChainFeed는 기본적으로 여러 종류의 온체인 이벤트를 프론트엔드에 전달하여 제공하는 서비스이기 때문에, 각각 서로 다른 스키마를 가지는 엔티티를 DB에 밀어넣고 끌어오는 작업을 반복하는 것이 주된 task가 된다. 이러한 경우에 PostgreSQL과 같은 RDB를 사용하게 되면 서로 다른 스키마를 가지는 엔티티를 같은 테이블에서 처리하는 것이 어렵기 때문에, 필연적으로 각 스키마별로 테이블을 만들어 처리하게 된다. 이는 DB 초기화 스크립트, 데몬, 프론트엔드에서 테이블마다 쿼리를 생성하게 되어 일정량의 개발 비용을 초래하였다.

처음으로 돌아가 DB를 다시 선택한다면 MongoDB Atlas를 선택했을 것 같다. 무료 SaaS 제품이라 MVP를 만들기에 부담이 적고, 스키마에 구애받지 않는 Document로 Typescript와 원활하게 데이터를 주고받을 수 있기 때문이다.

(사실 프로젝트 진행 중에도 MongoDB로의 전환을 몇 번씩 고민했으나 이미 DB 작업에 매몰된 양이 너무 많아서 Supabase로 강행하였다.)

외면받는 bigint 지원

먼저, 공식 Supabase JS client의 type generator는 BigInt 필드를 number로 취급하여 타입을 생성한다. 이는 ERC20 transfer amount와 같이 uint256 데이터를 다루기에 매우 부적합하다. Stack Overflow에 따르면 문자열로 캐스팅하여 가져온 뒤에 bigint로 캐스팅하는 방법이 있으나, 맘에 들지 않아 (데몬에만) Prisma를 사용하였다.

결과적으로 Prisma도 별반 다르지 않았는데, 분명히 bigint를 값으로 제공하였음에도 쿼리 빌더가 MAX_SAFE_INTEGER의 범위를 넘는 값을 전달받는 경우 ‘number 대신 bigint를 사용해야 함’이라는 이해하기 어려운 오류를 내뱉어 bigint의 사용을 포기하고 text로 숫자 값을 저장하는 방식으로 우회하였다.

Prisma의 자잘한 버그로 인한 개발 지연

그 외에도 Prisma는 몇 가지 자잘한 버그가 있어서 개발을 상당히 지연시켰다. 첫 번째로 Prisma 쿼리 빌더는 checked create input과 unchecked create input을 XOR<createInput, uncheckedCreateInput> 제네릭 타입을 통해 취사선택하여 받는 구조를 가지고 있는데, 불필요한 필드가 들어간 경우나 필드의 타입이 맞지 않는 경우 아주 불친절하거나 크게 오해할 수 있는 에러 메시지를 보게 되었다. 예를 들어 unchecked input을 제공할 때 타입을 실수한 경우 checked input으로 타입 추론이 옮겨져 checked input에만 존재하는 필드가 누락되었다고 에러를 표시하게 된다. 사용자는 unchecked input을 의도했는데 checked input으로 인식하고 있으니 헤멜 수밖에 없다. 더욱 압권인 것은 number 타입 필드의 값이 NaN일 때만 이러한 버그가 발생했다는 것인데, 이를 찾기까지 밤 11시부터 새벽 3시까지 총 4시간을 소모했으니 억울하지 않을 수가 없다. (그렇게 온종일 밤을 새서 나머지 기능을 구현할 수밖에 없었다…)

교훈

Tech stack에 신기술을 도입하는 것도 좋지만(대부분의 신기술은 이전 기술의 개선판이므로), 어떠한 점에서 개선이 되었고 강점을 보이는지 정확히 아는 것이 중요하다. 그러한 개선점이 나의 니즈와 잘 맞는지 알려면 내가 해당 tech stack을 사용하여 어떠한 문제를 풀려고 하는지 명확히 정의한 다음 면밀하게 분석해야 한다. 이러한 점에서 다소 ‘대책없이’ 신기술을 넣은 것이 아닌지 성찰이 필요해 보이는 해커톤이었다.

또한, 극히 제한된 시간 내에 코드를 작성하여 제출하는 것이 1순위인 해커톤의 특성상 빠른 개발 iteration이 중요할 것이다. 그러므로 어느 정도 sub-optimal한 해법이어도 ‘it works’이기만 하면 일단 허용하고 추후에 고치는 식의 개발 방법론이 유효하다 생각되는데, 나의 완벽주의적인 성격상 그러한 허점을 용납하지 못해서 optimal한 해법을 찾기 위해 시간을 필요 이상으로 소모하는 모습이 몇 번 나와 많이 아쉬웠다(그래도 모든 코드를 Rust 대신에 Typescript로 작성한 것이 그나마 이 면에서 유효한 선택이었다).

올해 Main Track 우승/준우승작

ETHSeoul Hackathon에는 main track / sponsor track으로 구분되는 두 가지의 수상항목이 있다. Main track은 말 그대로 해당 해커톤의 주된 주제의식을 잘 구현한 팀에게 주어지는 상이며, sponsor 트랙의 경우 해당 대회의 후원 팀들이 걸은 agenda를 잘 구현한 팀에게 주어지는 일종의 부상 개념으로 생각된다.

Wi.Fi

= Why Finance? DeFi의 mass adoption을 위한 서비스이다. DeFi에서 수익을 내기 위해 필요한 스왑-자산분배-LP 예치의 과정을 한곳에 모아서 처리할 수 있게 하고 간단한 클릭 몇번만으로 yield farming을 가능하게 하는 기능과, 여러 체인에 분산된 asset을 모아서 한 번에 모을 수 있는 기능 등 전반적으로 Toss와 비슷한 간편성 위주의 종합 앱을 추구하는 것으로 보인다. 개인적인 시각으로는 1Inch같은 DEX aggregator를 넘어선 DeFi 자체에 대한 aggregator로서 해석하고자 한다. 공개 발표를 진행한 작품 중에 가장 UI가 깔끔했다.

WalletMetrics

= Google Analytics for personal Web3 wallets. 자신이 소유한 지갑들의 DeFi 포지션이나 자산분석 등을 no-code UI로 수행 가능하다. (DYDX 포지션 분석 같은 일부 기능은 Figma 컨셉으로만 발표했음에도 수상하였다는 점이 특이한 점이다.)

Daily Routine

= Web3 challenging platform. 독서하기, 운동하기, 특정 행사 참여하기 등 미션을 스스로 설정하고 NEAR 토큰을 예치한 후에 미션 달성에 성공하면 예치한 토큰에 비례하는 보상을 얻게 된다. 또한 미션 달성 실패 시 일부 토큰을 잃게 되어 계속해서 미션을 달성할 수 있는 유인을 제공한다. 미션의 달성 여부는 사진을 찍어서 moderator에게 제출하면 되며 moderator는 거짓된 사진을 거부할 때 (간접적인) 인센티브를 받음으로서 프로토콜의 질서가 유지된다.

Solidity Copilot

GPT4 API를 사용하여 Solidity 스마트 컨트랙트의 기본적인 audit, 가스비 분석, 테스트 자동 생성 등의 일을 수행할 수 있는 VSCode extension이다.

Safura

= Web3 Kaspersky? ML을 사용하여 scam contract를 분류한 후, 자신이 일종의 EVM proxy node처럼 동작하여 사용자가 scam contract와 상호작용하려 하면 중간에서 차단해주는 보안 서비스이다. ML에는 3-layer-deep MLP를 사용했으며 약 85% 정도의 accuracy를 확보했다. 학습한 가중치를 ZK circuit으로 만들어 온체인에서 validity를 증명할 수 있다. (Main track에서 2개 동시수상 / sponsor track에서 1개 수상 총 3관왕을 달성한 진정한 승리자)

교훈

이들 프로젝트의 공통점을 들어보자면

  • 미려한 UI
  • 한 가지 명확한 목표에 집중
  • ZKP, AI, DeFi(이 친구는 뜬 지 좀 오래되었지만…)와 같은 트렌디한 테마를 하나 이상 잡고 있음

정도가 되겠다. 특히 AI와 ZKP가 중요한데, AI의 경우에는 main track 심사위원이 우리의 제출작품을 평가할 때마저 ‘AI를 사용해서 온체인 데이터를 분석한 뒤 큐레이션하는 것은 검토해 본 적이 없느냐’라고 지적할 만큼 핫한 토픽이었다고 생각된다. 그러한 주제를 잘 캐치해서 해커톤 컨텐츠에 접목하는 능력이 수상으로 이어지는 지름길이라는 생각이 들었다.

총평

전반적으로 첫 해커톤 치고는 나쁘지 않은(그렇다고 대박은 아니지만) 성과를 얻었다고 생각하며, 본인의 개발 실력에 대한 현주소와 장단점을 알 수 있어서 좋은 경험이 되었다고 생각한다. 날밤 새가면서 작성한 코드를 심사위원들 앞에서 설명하고 모든 것을 마치는 짜릿함이 있었지만, 체력 소모도 상당한 만큼 어느 정도의 재충전을 거쳐 다음 해커톤에 도전해보지 않을까 하는 생각이 든다.