The Graph 입문 가이드(2–1)

Boom Labs는 Web 3 개발자들을 온보딩시키고, 생태계를 활성화시키기 위해 교육을 비롯한 여러 활동들을 하고 있습니다. 저희 비전에 공감하여 동참하고자 하는 분들은 Boom Labs의 문을 두드려주세요!

Disclaimer: 이 글은 정보 전달을 위한 목적으로 작성되었으며, 특정 프로젝트에 대한 투자 권고, 법률적 자문 등 목적으로 하지 않습니다. 모든 투자의 책임은 개인에게 있으며, 이로 발생된 결과에 대해 어떤 부분에서도 Boom Labs는 책임을 지지 않습니다. 본문이 포괄하는 내용들은 특정 자산에 대한 투자를 추천하는 것이 아니며, 언제나 본문의 내용만을 통한 의사결정은 지양하시길 바랍니다.

1편에서 넘어온 글입니다.

TL;DR : Subgraph를 만들기 위해서는 아래의 요소들이 필요합니다.

  1. data source(Smart Contract),
  2. 인덱싱 할 data,
  3. 컨트랙트에서 정의한 event
  4. 특정 event가 emit 되었을 때 데이터를 받아서 가공할 resolver

Graph Cli를 이용해 init — codegen — deploy 까지 하면 서브그래프 배포가 됩니다.

서브그래프 만들기

The Graph를 이용해 블록체인의 데이터를 인덱싱하고 쿼리하기 위해서는 서브그래프라는 API를 만들어야 합니다.

서브그래프 개발을 위해 아래의 사전 지식들이 필요합니다. 이번 글에서 GraphQL에 대한 자세한 설명은 다루지 않기 때문에 GraphQL에 대해 더 공부하고 싶다면 graphql learn 사이트를 참고해보세요.

  • GraphQL 사용
  • Schema 설계

먼저, the Graph의 데이터 흐름에 대해 설명하고 넘어가겠습니다.

  1. dApp이 메인넷(ex. Ethereum)에 존재하는 데이터를 스마트 컨트랙트의 트랜잭션을 통해 생성/변경합니다.
  2. 스마트 컨트랙트의 트랜잭션이 처리되면서 N개의 이벤트(logs)가 emit 됩니다.
  3. The Graph 노드는 컨트랙트의 특정 이벤트를 listen하면서 서브그래프 개발자가 정의해놓은 mapping의 handler를 트리거 합니다.
  4. mapping은 WASM runtime으로 돌아가는 WASM module입니다. 블록체인의 이벤트에 대응하여 이벤트 데이터를 store에 저장합니다.
  5. store는 인덱스에 따라 데이터를 업데이트 합니다.
  6. dApp은 만들어진 GraphQL endpoint로 Graph Node에 데이터 쿼리 요청을 합니다. Graph Node는 요청 들어온 GraphQL 쿼리를 SQL로 변환해 노드의 로컬 postgres DB에서 데이터를 fetching 해서 응답합니다.
  7. 응답 데이터를 활용해 dApp은 화면을 랜더링 합니다.

서브그래프는 이벤트 데이터를 수집할 schema를 정의 하고, data flow에서 사용될 mapping, handler를 정의하는 API 입니다.

이제부터 하나씩 서브그래프의 요소들을 살펴보겠습니다.

  1. Manifest (subgraph.yaml) — 만들려고 하는 서브그래프가 인덱싱할 datasource(e.g. smart contract)를 정의하는 manifest 파일.
  2. Schema (schema.graphql) — 서브그래프 데이터 조회를 위해 정의할 데이터 모델 schema. GraphQL schema를 따릅니다. (GraphQL request body를 생각하시면 됩니다.)
  3. AssemblyScript Mappings (mapping.ts) — datasource에서 가져온 데이터를 schema로 정의한 entity로 변환합니다. 데이터를 어떻게 저장할지에 대한 로직을 구축합니다.

서브그래프는 한번 정의하면 변경되지 않습니다. 변경되지 않기 때문에 deterministic, reproducible한 쿼리를 생성할 수 있습니다. (서브그래프 내용을 수정하기 위해선 다시 배포해야 합니다.)

이제 manifest를 만들기 위해 Graph CLI를 설치하겠습니다. Graph CLI는 subgraph 코드를 만들거나 Graph Node에 배포하기 위해 필요한 CLI를 모아놓은 라이브러리입니다.

Javascript 기반이기 때문에 yarn 혹은 npm 으로 설치하시면 됩니다.

저는 yarn 으로 설치해보겠습니다.

yarn global add @graphprotocol/graph-cli

  • graph-cli는 global로 설치하는게 좋습니다. local에 설치할 경우 명령어가 작동하지 않을 수 있습니다.

시작은 graph init 커맨드로 시작합니다. init 은 새로운 subgraph 프로젝트를 세팅해줍니다.

  • graph init --product subgraph-studio 을 할 경우 Subgraph Studio 환경으로 세팅이 되며,
  • graph init --product hosted-service 를 할 경우 hosted service 환경으로 세팅이 됩니다.

Note: The Graph는 현재 Subgraph Studio와 Hosted Service, 2가지 타입을 제공합니다. Subgraph Studio는 완전히 탈중앙화된 서비스이며, Ethereum과 Rinkeby만 사용 가능합니다. Hosted Service는 The Graph 측에서 제공하는 서비스로서 Polygon, Aurora 등 EVM 호환 네트워크 위에서 사용가능한 서비스입니다. Hosted Service를 지원하는 네트워크들은 이 링크를 참고하세요. 다만, Hosted Service는 2023년에 종료될 예정입니다.

이번 글에서는, 폴리곤 mumbai 네트워크 위의 데이터를 조회할 것이기 때문에 hosted-service로 서브그래프를 만들어보겠습니다.

  1. 먼저 Hosted Service 사이트로 가서 Github 로그인을 합니다

2. ‘My Dashboard’ 메뉴로 가서, ‘Add subgraph’ 를 눌러줍니다. 적절한 subgraph name을 입력합니다. 저는 폴리곤의 DAI 토큰 데이터를 수집해보기 위해서 ERC20 Test이라고 지어보겠습니다. subtitle은 적절하게 지어줍니다. 이제 Create Subgraph를 누르면, 만든 서브그래프가 나옵니다.

3. 이제 graph-cli를 이용해 init을 합니다. 배포된 컨트랙트가 있다면 아래와 같이 입력합니다.

graph init \\
--product hosted-service
--from-contract <CONTRACT_ADDRESS> \\
<GITHUB_USER>/<SUBGRAPH_NAME> [<DIRECTORY>]
--network mumbai

(저는 CONTRACT_ADDRESS에 0x5A01Ea01Ba9A8DC2B066714A65E61a78838B1b9e 를 넣었습니다.)

참고로, 아직 컨트랙트를 배포하지 않았다면 Example subgraph 옵션을 사용해 서브그래프를 만들 수 있습니다.

graph init --from-example --product hosted-service <GITHUB_USER>/<SUBGRAPH_NAME> [<DIRECTORY>]

이제 서브그래프 프로젝트가 만들어졌으며, 아래와 같은 디렉토리 구조를 띌 것입니다.

root
-- abis
-- package.json
-- networks.json
-- subgraph.yaml
-- networks.json
-- yarn.lock
-- src
-- mapping.ts

4.subgraph.yaml 파일을 열면 아래와 같은 코드가 나옵니다. 하나씩 설명해보겠습니다.

specVersion: 0.0.4
description: DAI for Polygon
repository: <https://github.com/graphprotocol/example-subgraphs>
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum
name: DAI
network: mumbai
source:
address: "0x5A01Ea01Ba9A8DC2B066714A65E61a78838B1b9e"
abi: DAI
startBlock: 5885640
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
entities:
- Approval
- Transfer
abis:
- name: DAI
file: ./abis/DAI.json
eventHandlers:
- event: Approval(indexed address,indexed address,uint256)
handler: handleApproval
- event: Transfer(indexed address,indexed address,uint256)
handler: handleTransfer
file: ./src/dai.ts
  • specVersion : 버전에 대한 내용입니다. 건드릴 필요가 없습니다.
  • schema.file : schema를 정의할 graphql 파일 위치를 나타냅니다.
  • dataSources.kind : 네트워크 종류를 나타냅니다. EVM 호환 네트워크이면 ethereum 으로 입력합니다.
  • dataSources.name : 컨트랙트 이름을 적어줍니다.
  • dataSources.source: 컨트랙트의 주소, abi 이름, 데이터 인덱싱을 시작할 block number를 적어줍니다. 보통 컨트랙트의 creation 시점 block number를 적습니다.(적지않으면 genesis block부터 순회합니다.)
  • dataSources.mapping.kind/apiVersion/language : 건드릴 필요가 없습니다.
  • dataSources.mapping.entities: 온체인 데이터를 저장할 데이터 모델 이름을 적습니다. schema.graphql 파일에서 정의한 이름을 적으면 됩니다. 여러 entity를 적을 수 있습니다.
  • dataSources.mapping.abis: 컨트랙트의 abi 이름과 파일 경로를 적습니다.
  • dataSources.mapping.eventHandlers: 서브그래프가 수집할 이벤트들을 정의합니다. event는 컨트랙트에서 정의한 이벤트 형식을 따라야 합니다. (참고로, 솔리디티 이벤트 포맷과 일부 다릅니다. 솔리디티에서는 indexed 를 뒤에 적지만 여기서는 앞에 적어야 합니다. 각 데이터 타입 사이에서는 공백을 제거해야 합니다. 유일한 공백은 indexed DataType 같이 indexed 뒤에만 허용합니다.) handler에는 위에서 정의한 이벤트를 수집할 시 처리할 메소드 이름을 정의합니다.
  • dataSources.mapping.file : mapping 파일의 경로를 정의합니다. 보통 src 안에 위치합니다.

2–2글에서 이어집니다.

--

--