티스토리 뷰

Github

 

dig-solidity/nft-indexer at main · piatoss3612/dig-solidity

Contribute to piatoss3612/dig-solidity development by creating an account on GitHub.

github.com


준비물

  • The Graph : 계정 생성
  • nvm, node, yarn (또는 npm) : 서브그래프 설정을 위한 환경
  • foundry : 이더리움 스마트 컨트랙트 개발환경

The Graph

 The Graph는 Ethereum 및 다른 블록체인과 호환되는 인덱싱 프로토콜로, 블록체인 데이터를 효율적으로 쿼리 할 수 있게 도와줍니다. 기본적으로 The Graph는 데이터를 읽기 쉽게 만드는 역할을 하며, 이를 통해 개발자들이 블록체인 데이터를 이용한 응용 프로그램을 쉽게 구축할 수 있습니다.

 

 SubgraphThe Graph 내에서 블록체인 데이터를 정의하고 구조화하는 방법을 제공합니다. Subgraph를 사용하면 특정 블록체인 이벤트에 대한 데이터를 추출하고 인덱스화하여, GraphQL을 사용하여 쉽게 쿼리 할 수 있습니다. 각 Subgraph는 특정 블록체인 프로젝트나 스마트 컨트랙트의 데이터를 처리하도록 설정될 수 있으며, 이 데이터는 The Graph 노드에 의해 자동으로 처리되고 업데이트됩니다.

 

예를 들어, DApp이 Ethereum에서 발생하는 특정 거래를 추적하고자 할 때, 개발자는 이 거래를 포함하는 Subgraph를 만들고 The Graph 프로토콜을 통해 이를 쿼리 할 수 있습니다. 이런 방식으로, Subgraph는 블록체인 데이터에 대한 강력하고 유연한 쿼리 기능을 제공하며, 개발자가 필요로 하는 특정 정보에 대한 접근을 용이하게 만듭니다.


Foundry 프로젝트

프로젝트 생성

$ forge init nft-indexer

OpenZeppelin 라이브러리 설치

$ forge install OpenZeppelin/openzeppelin-contracts --no-commit

MyNFT 컨트랙트 작성

 src 디렉터리 안에 MyNFT.sol 파일을 생성하고 붙여 넣기

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MyNFT is ERC721 {
    uint256 _nextTokenId;

    constructor() ERC721("MyNFT", "MNFT") {}

    function testMint() public {
        for (uint256 i = 0; i < 10; i++) {
            _mint(msg.sender);
        }
    }

    function _mint(address to) internal {
        uint256 tokenId = _nextTokenId++;
        _safeMint(to, tokenId);
    }
}

MyNFT 컨트랙트 배포 및 testMint 함수 호출 스크립트 작성

 script 디렉터리 안에 MyNFT .s.sol 파일을 생성하고 붙여 넣기

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Script, console} from "forge-std/Script.sol";
import {MyNFT} from "../src/MyNFT.sol";

contract MyNFTScript is Script {
    function run() public {
        vm.startBroadcast();
        MyNFT nft = new MyNFT();

        console.log("Deployed MyNFT at address: ", address(nft));

        nft.testMint();
    }
}

foundry.toml 파일에 rpc endpoint 추가

 sepolia 테스트 네트워크의 rpc url을 사용

[rpc_endpoints]
sepolia = "https://ethereum-sepolia-rpc.publicnode.com"

컨트랙트 배포

  • --account 플래그를 사용하는 방법 참고: https://piatoss3612.tistory.com/139
  • 또는 --private-key 플래그를 사용하여 프라이빗 키를 직접 사용하는 방법도 있다
$ forge script script/MyNFT.s.sol --rpc-url sepolia --account piatoss --sender 0x965b0e63e00e7805569ee3b428cf96330dfc57ef --broadcast -vvvv
...
== Logs ==
  Deployed MyNFT at address:  0x8E36a21AFeee005EA1A9e565c620f9A3BB3EfEE2

## Setting up 1 EVM.
==========================
Simulated On-chain Traces:

  [864194] → new MyNFT@0x8E36a21AFeee005EA1A9e565c620f9A3BB3EfEE2
    └─ ← [Return] 4091 bytes of code

  [299606] MyNFT::testMint()
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 0)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 1)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 2)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 3)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 4)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 5)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 6)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 7)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 8)
    ├─ emit Transfer(_from: 0x0000000000000000000000000000000000000000, _to: 0x965B0E63e00E7805569ee3B428Cf96330DFc57EF, _tokenId: 9)
    └─ ← [Stop]

Subgraph 생성

대시보드에서 Create a subgraph 선택

subgraph 이름을 정하고 Create Subgraph 클릭

@graphprotocol/graph-cli 설치하기

Foundry 프로젝트 안에 subgraph 초기화하기

$ graph init --studio mynft
  • Protocol : ethereum 선택
  • Subgraph slug : mynft
  • Directory to create the subgraph in : subgraph
  • Ethereum network : sepolia
  • Contract address : 방금 배포한 MyNFT의 주소
  • Failed to fetch ABI -> Do you want to retry가 뜨면 n 선택 (이더스캔을 통해서 컨트랙트를 verify 한 경우 자동으로 넘어감)
    • ABI file (path) : ./out/MyNFT.sol/MyNFT.json
    • Start Block : 컨트랙트가 배포된 블록 번호
    • Contract Name : MyNFT
    • Index contract events as entities: true

subgraph를 초기화하고 나면 Foundry 프로젝트 안에 subgraph 디렉터리가 생성되어 있음.

인증 및 subgraph 배포

$graph auth --studio <YOUR_AUTHENTICATION_CODE>
$ cd subgraph
$ graph codegen && graph build
$ graph deploy --studio mynft
Which version label to use? (e.g. "v0.0.1"): v0.0.1
  Skip migration: Bump mapping apiVersion from 0.0.1 to 0.0.2
  Skip migration: Bump mapping apiVersion from 0.0.2 to 0.0.3
  Skip migration: Bump mapping apiVersion from 0.0.3 to 0.0.4
  Skip migration: Bump mapping apiVersion from 0.0.4 to 0.0.5
  Skip migration: Bump mapping apiVersion from 0.0.5 to 0.0.6
  Skip migration: Bump manifest specVersion from 0.0.1 to 0.0.2
  Skip migration: Bump manifest specVersion from 0.0.2 to 0.0.4
✔ Apply migrations
✔ Load subgraph from subgraph.yaml
  Compile data source: MyNFT => build/MyNFT/MyNFT.wasm
✔ Compile subgraph
  Copy schema file build/schema.graphql
  Write subgraph file build/MyNFT/abis/MyNFT.json
  Write subgraph manifest build/subgraph.yaml
✔ Write compiled subgraph to build/
  Add file to IPFS build/schema.graphql
                .. QmQuQmn2XZkLdp1fUbtwK243u2a9tXeECq7ApL5AFnPgVZ
  Add file to IPFS build/MyNFT/abis/MyNFT.json
                .. QmYSi7MXvTp3WXFfCkNrut4xG89XdybGnXgxrtCTDkmEqx
  Add file to IPFS build/MyNFT/MyNFT.wasm
                .. Qmca3KqTveeDTNFhefXsowHCUsisBNcoj5JnkpkAk6ScWW
✔ Upload subgraph to IPFS

Build completed: QmUqCdVQTPu548HVux8Tp3J2DXGNSn7N5Gk3H9Nmmiemk4

Deployed to https://thegraph.com/studio/subgraph/mynft

Subgraph endpoints:
Queries (HTTP):     https://api.studio.thegraph.com/query/71401/mynft/v0.0.1

 배포에 성공하면 SYNCED라고 초록색 줄이 뜸


이벤트 인덱싱

node.js 프로젝트 생성

$ cd ..
$ mkdir indexer
$ cd indexer
$ yarn init -y
$ touch index.js

package.json 수정

{
  "name": "indexer",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "node index.js"
  }
}

라이브러리 설치

$ yarn add graphql graphql-request

index.js 작성

  • 스키마는 subgraph 디렉터리의 schema.graphql을 참고.
  • 쿼리문은 GraphQL 쿼리문으로 작성.
const { gql, request } = require("graphql-request");

const MY_NFT_QUERY_URL =
  "https://api.studio.thegraph.com/query/71401/mynft/version/latest";

const main = async () => {
  const query = gql`
    {
      transfers(first: 5) {
        from
        to
        tokenId
      }
    }
  `;
  const response = await request(MY_NFT_QUERY_URL, query);

  console.log(response);
};

main();

인덱싱

$ yarn start
yarn run v1.22.21
$ node index.js
{
  transfers: [
    {
      from: '0x0000000000000000000000000000000000000000',
      to: '0x965b0e63e00e7805569ee3b428cf96330dfc57ef',
      tokenId: '0'
    },
    {
      from: '0x0000000000000000000000000000000000000000',
      to: '0x965b0e63e00e7805569ee3b428cf96330dfc57ef',
      tokenId: '1'
    },
    {
      from: '0x0000000000000000000000000000000000000000',
      to: '0x965b0e63e00e7805569ee3b428cf96330dfc57ef',
      tokenId: '2'
    },
    {
      from: '0x0000000000000000000000000000000000000000',
      to: '0x965b0e63e00e7805569ee3b428cf96330dfc57ef',
      tokenId: '3'
    },
    {
      from: '0x0000000000000000000000000000000000000000',
      to: '0x965b0e63e00e7805569ee3b428cf96330dfc57ef',
      tokenId: '4'
    }
  ]
}
Done in 0.76s.

결론

 

 요금이 어떤 식으로 차징 되는지는 모르겠으나 일단 graphql 쿼리문을 사용해 이벤트를 인덱싱하는 경우는 카운팅이 되지 않는 것 같습니다. 따라서 비용 부담이 크지 않을 것으로 보이네요.

 

그러나 영리적인 목적으로 무언가를 사용할 때 따라오는 제약들이 있듯이 어딘가에 제약이 걸려있을 것으로 예상됩니다. 해커톤이나 포트폴리오용 프로젝트에서는 마음껏 사용해도 될 듯합니다.

 

 무엇보다 특정 컨트랙트에 대한 데이터를 온체인 상에서 쿼리 할 때 보다  빠르고 쉽게 인덱싱할 수 있다는 것이 굉장히 큰 메리트로 보입니다. 저는 자주 애용할 것 같습니다.

'블록체인' 카테고리의 다른 글

분산 데이터베이스와 분산 원장  (0) 2023.09.04
최근에 올라온 글
최근에 달린 댓글
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Total
Today
Yesterday
글 보관함