블록체인&Web3

The Graph Subgraph를 이용한 온체인 데이터 누적 수집

mmalmmizal 2025. 5. 14. 01:20

https://thegraph.com/studio/subgraph/pool-status/

Subgraphs

The Graph와 그 안에서 사용하는 서브그래프 (subgraph)는 블록체인 데이터를 효율적으로 조회하기 위한 탈중앙화된 인덱싱 프로토콜 

블록체인 특성 상 과거 데이터 누적, 시간 경과 기반 계산, 통계 집계에 부정확하다. 따라서 오프체인 인덱싱 시스템을 사용하도록 한다.

 

 

 

Subgraphs | Graph Explorer

Explore subgraphs published to The Graph Network.

thegraph.com

https://thegraph.com/studio/ 의 subgraph 생성 과정을 따라가는 글 

 

 

 

 

 

The Graph CLI (Command Line Interface)를 설치해준다.

npm install -g @graphprotocol/graph-cli

 


 

 

 

The Graph에서 서브그래프(subgraph)생성하고 배포하는 사용하는 CLI 명령어 흐름

graph init → graph codegen → graph build → graph deploy
graph init

 

네트워크, 서브그래프 이름, 컨트랙트 주소, 시작 블럭 등을 지정하게 된다. 
 
현재 upgradable contract를 사용하고 있어서 프록시 주소와 로직 주소가 다르다.  graph init 과정에선 abi를 받아와서 새로운 디렉터리와 파일 구조를 생성하기 때문에 로직 컨트랙트 주소로 graph init 한 후에 subgraph.yaml의 컨트랙트 주소를 proxy 컨트랙트로 변경하면 된다.
  • schema.graphql : GraphQL 타입 정의, 질의에서 사용
  • subgraph.yaml : 어떤 네트워크의 어떤 컨트랙트를 추적할지 정의
  • abis/ : ABI 
  • src/mapping.ts : 이벤트 처리 로직
//mapping.ts

import { Transfer } from '../generated/schema';
import { Transfer as TransferEvent } from '../generated/MyContract/MyContract';

export function handleTransfer(event: TransferEvent): void {
  let entity = new Transfer(event.transaction.hash.toHex());
  entity.from = event.params.from;
  entity.to = event.params.to;
  entity.value = event.params.value;
  entity.save();
}

여기서 TransferEvent는 스마트 컨트랙트 이벤트고 Transfer는 GraphQL로 저장될 DB 모델이다.

 

 

 

 

 

인증 토큰(Access Token) 등록 명령어

graph auth ***************

 

타입스크립트 타입 자동 생성

graph codegen

 

generated 폴더

generated/schema.ts에선 Transfer 같은 Entity 타입 정의 

generated/MyContract/MyContract.ts에선 ABI 기반의 컨트랙트 이벤트와 함수 타입 (ABI 기반) 정의 

 

 
graph build​

build 과정에선 서브그래프의 코드(schema.graphql, subgraph.yaml, mapping.ts 등)를 컴파일하고 오류가 없는지 확인한다.

그리고 build/ 디렉토리에 .wasm 파일과 schema.graphql을 포함한 결과물 생성한다.

 

 

graph deploy

 

배포를 거치고 난 이후 GraphQL API URL을 얻게 되는데, 프론트에서 쉽게 ApolloClient 등으로 쿼리할 수 있으며 이벤트 로그를 DB 없이 효율적으로 사용할 수 있다. 배포 과정에서 Internal error가 많이 난다면 참고 다시 시도하면 된다. 

 

내가 직접 배포한 서브그래프 

https://thegraph.com/studio/subgraph/pool-status/

 

My Dashboard | Subgraph Studio

Create Subgraphs and API keys.

thegraph.com

 

 

기존에 prisma와 사용하던 apollo client와 다른 클라이언트를 셋팅한다. 이 클라이언트로 graphql 쿼리를 사용할 예정이다. 

//The graph용 apolloclient
import { ApolloClient, InMemoryCache } from '@apollo/client';

export const graphClient = new ApolloClient({
  uri: 'https://api.studio.thegraph.com/query/111362/pool-status/0.0.3', //배포한  uri
  cache: new InMemoryCache(),
});

 

 

현재 나의 컨트랙트에서는 아래와 같은 이벤트가 발생된다.

 

event LiquidityAdded(address indexed _account, uint256 _liquidity);

event LiquidityRemoved(address indexed _account, uint256 _liquidity);

event TradedTokens(address indexed _account, uint256 _ethTraded, uint256 tokenTraded);

 

 

the graph 플레이그라운드에서 쿼리를 쉽게 수정, 생성할 수 있다.

https://api.studio.thegraph.com/query/111362/pool-status/version/latest

 

The GraphiQL

 

api.studio.thegraph.com

 //SoulBase/libs/ui/src/components/templates/PoolStatus.tsx 
  const GET_VOLUME = gql`
    query GetVolume($since: BigInt!) {
      tradedTokens_collection( where:{blockTimestamp_gt: $since}) {
        _account
        _ethTraded
        blockNumber
        blockTimestamp
        id
        tokenTraded
      }
    }
    `;

  
  const startTimestamp = 1715539200;
  const { data, loading, error } = useQuery(GET_VOLUME, {
    client: graphClient, // <-- 요게 핵심
    variables: { since: startTimestamp },
  });
  console.log(data, error);

 

 

TradedTokens라고 정의된 Entity컬렉션을 질의하는 쿼리, blockTimestamp$since보다 큰(=즉, $since 이후 발생한 거래) 데이터만 가져온다.