Open13
The Graph 入門
ピン留めされたアイテム
Developer 視点の The Graph まとめ
- Indexer を自作しなくて済むので嬉しい
- 「コントラクトのイベント」=>「GraphQL のスキーマ」の変換をする関数を書けばよしなに永続化される
- ドキュメントを読むとコントラクトのイベントの他にも発火点はありそうだった
- GraphQL のスキーマからある程度のボイラープレートは生成してくれるので開発者体験としても良い
- https://thegraph.com/explorer/ から適当にユーザー登録する
- SubGraph を作成する
yarn add -D @graphprotocol/graph-cli
yarn graph init --studio test
yarn ごと入るやつだった
コントラクトは Loot
yarn graph auth
cd test
yarn codegen
yarn build
yarn deploy
デプロイした
同期中
普通に考えると結構時間かかりそう
ちゃんとログ出ててすごい
2000ブロックずつ sync しているっぽい
進捗グラフは GraphQL の Subscription で更新されている
subgraph.yaml
specVersion: 0.0.2
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum/contract
name: Loot
network: mainnet
source:
address: "0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7"
abi: Loot
mapping:
kind: ethereum/events
apiVersion: 0.0.4
language: wasm/assemblyscript
entities:
- Approval
- ApprovalForAll
- OwnershipTransferred
- Transfer
abis:
- name: Loot
file: ./abis/Loot.json
eventHandlers:
- event: Approval(indexed address,indexed address,indexed uint256)
handler: handleApproval
- event: ApprovalForAll(indexed address,indexed address,bool)
handler: handleApprovalForAll
- event: OwnershipTransferred(indexed address,indexed address)
handler: handleOwnershipTransferred
- event: Transfer(indexed address,indexed address,indexed uint256)
handler: handleTransfer
file: ./src/mapping.ts
subgraph.yaml
に設定を書くらしい
この設定だと ./src/mapping.ts
で export している関数 (e.g. handleTransfer) とコントラクトの Event をマッピングしている
kind
使ってたりして、k8s の マニフェストぽさを感じる
サンプルの ./src/mapping.ts
はこんな感じ
import { BigInt } from "@graphprotocol/graph-ts";
import {
Loot,
Approval,
ApprovalForAll,
OwnershipTransferred,
Transfer,
} from "../generated/Loot/Loot";
import { ExampleEntity } from "../generated/schema";
export function handleApproval(event: Approval): void {
// Entities can be loaded from the store using a string ID; this ID
// needs to be unique across all entities of the same type
let entity = ExampleEntity.load(event.transaction.from.toHex());
// Entities only exist after they have been saved to the store;
// `null` checks allow to create entities on demand
if (entity == null) {
entity = new ExampleEntity(event.transaction.from.toHex());
// Entity fields can be set using simple assignments
entity.count = BigInt.fromI32(0);
}
// BigInt and BigDecimal math are supported
entity.count = entity.count + BigInt.fromI32(1);
// Entity fields can be set based on event parameters
entity.owner = event.params.owner;
entity.approved = event.params.approved;
// Entities can be written to the store with `.save()`
entity.save();
// Note: If a handler doesn't require existing field values, it is faster
// _not_ to load the entity from the store. Instead, create it fresh with
// `new Entity(...)`, set the fields that should be updated and save the
// entity back to the store. Fields that were not set or unset remain
// unchanged, allowing for partial updates to be applied.
// It is also possible to access smart contracts from mappings. For
// example, the contract that has emitted the event can be connected to
// with:
//
// let contract = Contract.bind(event.address)
//
// The following functions can then be called on this contract to access
// state variables and other data:
//
// - contract.balanceOf(...)
// - contract.getApproved(...)
// - contract.getChest(...)
// - contract.getFoot(...)
// - contract.getHand(...)
// - contract.getHead(...)
// - contract.getNeck(...)
// - contract.getRing(...)
// - contract.getWaist(...)
// - contract.getWeapon(...)
// - contract.isApprovedForAll(...)
// - contract.name(...)
// - contract.owner(...)
// - contract.ownerOf(...)
// - contract.supportsInterface(...)
// - contract.symbol(...)
// - contract.tokenByIndex(...)
// - contract.tokenOfOwnerByIndex(...)
// - contract.tokenURI(...)
// - contract.totalSupply(...)
}
export function handleApprovalForAll(event: ApprovalForAll): void {}
export function handleOwnershipTransferred(event: OwnershipTransferred): void {}
export function handleTransfer(event: Transfer): void {}
コメントにある通り、コントラクトのメソッドを呼び出すことができる
const loot = Loot.bind(event.address)
loot.balanceOf(...)
entity.save()
を呼び出すと The Graph 上にデータが永続されて、その内容を GraphQL で query できる
サンプルだと次のような形
ExampleEntity
はスキーマから自動生成されたクラス
GraphQL の mutation の抽象化(具体化?)と言えそう