Running through Camilia's workshop with (sometimes) translation into Japanese.
Camila さんによるチュートリアル記事
を やってみました。たまに翻訳してここに載せます。
あと、今この記事はサンフランシスコのホテルの中で書いているのですが、もしかしたら英語圏の知人が読んでくれるかもしれないので、たまに英語も併記します(最初だけ)
Note:この記事は開発者向けです
Note: This article is for developers who builds a subgraph using Graph Hosted Service. I don't mention about GRT token in this article. I know it's very important to ensure economic security of The Graph Network and the integrity of data being queried, but I'm not familiar with it, so I'll talk about only developing a subgraph.
グラフネットワークの経済的な安全性と、クエリデータの完全性を確保するために、
The Graph は ERC-20 の独自トークン (グラフトークン(GRT)) を持っていますが、
この私の記事にはその 独自トークンのことは一切出てきません 。
Graph のサステナブルなエコシステムを保つために重要な存在ですが、私はその辺は詳しくないので、あくまで開発の話だけ します。
詳細)
What is The Graph
You can see what The Graph is in the official document here.
The Graph とは、公式ドキュメントより
The Graph は、Ethereum をはじめとするブロックチェーンのデータをインデックス化してクエリするための分散型プロトコルです。 これにより、直接クエリすることが困難のデータのクエリが容易に可能になります。
要するに、Developer にとっての The Graph は、
- GraphQL を使用してさまざまなブロックチェーンからのデータにインデックスを付けてクエリを実行するためのプロトコル
- ブロックチェーンにデプロイされたスマートコントラクトから情報をクエリする手段を可能にする、web3 スタックの API レイヤー
- それらの API は「サブグラフ」と呼ばれ、みんなからデプロイされたサブグラフは subgraph explorer から見ることができる
という感じです。(本当はもっと色々あるんだけど今回は省略)
pict:Reprinted from 公式ドキュメントより
サブグラフ
サブグラフ(Developer が作る API 的なやつ)には、以下が定義されています:
- the data source (smart contracts)
- データソース(スマートコントラクト)
- the data that should be indexed
- インデックスされる必要のあるデータ
- the events you want to listen for
- listen したいイベント
- resolvers to execute when specified events are emitted which transform the raw data from the blockchain and save it to The Graph Node.
- 指定したイベントが発火したときに実行されるリゾルバー。ブロックチェーンからの生データを良い感じに変換して The Graph ノードに保存してくれる人。
補足)名前空間の衝突
(As I'm familiar with Microsoft tech stack, I thought The Graph has something to do with Microsoft Graph, which has nothing to do with it. I guess it's came from GraphQL.)
とくに私みたいなマイクロソフト系技術スタックに慣れていると「グラフ? Microsoft Graph のことか?」ってなるかもしれませんが、(私はなった)、 まtttttttったく別のもの です。ほぼ同じ名前ですが全く別のサービスです。マイクロソフト全然関係ないです。GraphQL から来た名前です。
How to get started
クイックスタートは公式サイトに書いてあります
Workshop チュートリアル
Camila さんの公開している、サブグラフ作成のチュートリアルを進めてみました
このチュートリアルで作成されるサブグラフを実際に叩いてみるには:
手順 1. Hosted Service
The Graph の Hosted Service にサインアップ
2. Add subgraph
“My Dashboard” から "Add subgraph" 。
作成時、私はここで「Graph Explorer で隠す (検索結果に表示しない)」トグルを on にしました。
3. Install The Graph CLI
The Graph CLI をインストールします
npm install -g @graphprotocol/graph-cli
4. Initialize your subgraph via the CLI command
次は既存のコントラクトからサブグラフを初期化します。
今回は、このチュートリアルの作者さんのお気に入りの NFT プロジェクト FameLadySquad (FLS) のアドレス 0xf3E6DbBE461C6fa492CeA7Cb1f5C5eA660EB1B47
を指定しています
Etherscan で見る:
https://etherscan.io/address/0xf3e6dbbe461c6fa492cea7cb1f5c5ea660eb1b47
graph init --from-contract 0xf3E6DbBE461C6fa492CeA7Cb1f5C5eA660EB1B47 \ --contract-name Token --index-events
5. Define your schema using the GraphQL interface definition language
作成されたプロジェクトの中身を見てみます。
(↑ .gitignore
は git 管理用に私が後から追加したものです。)
サブグラフのスキーマは、schema.graphql
というファイルに書いてあります。
今回は (このチュートリアル作者の Camila さんのお気に入り NFT プロジェクトである) Fame Lady Squad のサブグラフを作るので、それらのプロパティに合わせるため、
この schema.graphql
ファイルを以下のものに置き換えます。(既存の Approval とか ApprovalForAll とかもう要らないので、全部上書きで)
type Lady @entity {
id: ID!
tokenID: BigInt!
tokenURI: String!
owner: User
name: String
faceExpression: String
hairStyle: String
skinColor: String
eyeColor: String
}
type User @entity {
id: ID! # wallet address
Ladies: [Lady!] @derivedFrom(field: "owner")
}
もし既存のを消さなかったらどうなるの?
もし既存の(いらないプロパティ)を消さなかったらどうなるのか
消さなかったらデプロイ後のスキーマがこうなります
でも欲しいのは Lady と User だけなので、それ以外を消します。
すると(デプロイ後の画面で)こうなります
各プロパティについて
↑ FameLadySquad には いくつかの種類の trait (特性) がある。この trait の組み合わせによって作られているコレクション
(The pict above: Reprinted from "The Complete Guide to Getting Started With The Graph" written by Camila)
メタデータ
メタデータはこちらから見れます(生 json)
https://ipfs.io/ipfs/QmTngWTnURuyiz1gtoY33FKghCiU2uQusXpnUc36QJNKsY/1002
{"name": "Fame Lady #1002", "description": "Fame Lady Squad is the first ever generative all-female avatar collection on the Ethereum blockchain. Yes, we are THE community who took over a project to write our own story. This is NFT history. This is HERstory. FLS are 8888 distinctive Ladies made up of millions of fierce trait combinations. Community = Everything. Commercial IP rights of each Lady NFT belong to its owner.", "image": "ipfs://QmRRRcbfE3fTqBLTmmYMxENaNmAffv7ihJnwFkAimBP4Ac/1002.png", "attributes": [{"trait_type": "Skin", "value": "Olive"}, {"trait_type": "Background", "value": "White"}, {"trait_type": "Face Expression", "value": "Pokerface"}, {"trait_type": "Eyebrows", "value": "Stylish"}, {"trait_type": "Eyes", "value": "Pink"}, {"trait_type": "Nose Piercing Lower", "value": "Silver Ring"}, {"trait_type": "Body", "value": "Small Chain"}, {"trait_type": "Clothes", "value": "Green Dress"}, {"trait_type": "Hair", "value": "Straight Black"}, {"trait_type": "Elf Ear", "value": "Elf"}]}
6. graph codegen
cd .\fame-lady-tutorial\
graph codegen
これを実行すると、mappings.ts
の中に AssemblyScript を書いてくれます
7. .yaml
ファイルを編集
subgraph.yaml
ファイルで、以下のものを定義します:
- listen (監視) したい event。
- イベントリスナー的な。
- 逆に、(
subgraph.yaml
内の)dataSources.mapping.eventHandlers
からは listen したくないイベントはすべて削除します。 - それぞれのイベントでは、
mappings.ts
で定義したhandler
関数がそれぞれ紐づいています
- インデクサーがインデックス付けを開始する必要のある最初のブロック。
- 省略した場合、サブグラフはいちばん最初のブロックからイベントの検索を開始します
- 書く場合、Etherscan でトランザクションの最初のページまで行って、
transaction ID
をクリックしてブロックナンバーを探しましょう
- 情報をクエリするエンティティの名前。
-
dataSources.mapping.entities
で定義したスキーマにあわせて、あなたのエンティティの名前をアップデートします
-
specVersion: 0.0.2
schema:
file: ./schema.graphql
features:
- ipfsOnEthereumContracts
dataSources:
- kind: ethereum
name: Token
network: mainnet
source:
address: "0xf3E6DbBE461C6fa492CeA7Cb1f5C5eA660EB1B47"
abi: Token
startBlock: 12813031
mapping:
kind: ethereum/events
apiVersion: 0.0.5
language: wasm/assemblyscript
entities:
- Lady
- User
abis:
- name: Token
file: ./abis/Token.json
eventHandlers:
- event: Transfer(indexed address,indexed address,indexed uint256)
handler: handleTransfer
file: ./src/mapping.ts
8. Write mappings in AssemblyScript
最後に、AssemblyScript でマッピングを記述します。
これにより、ブロックチェーン(イーサリアム)から読み取られた生データが、スキーマで定義されたエンティティに変換されます。
この Fame Lady の例)
ブロックチェーンから取得する生データは、ERC-721 実装に標準で付属している getter メソッドで取ってきます。
つまり、このブロックチェーンから直接取ってこれるデータは tokenID
と owner
だけです。
でも私たちの定義したスキーマでは以下も欲しいです:
hairStyle
skinClolor
eyeColor
faceExpression
tokenID
を使い、メタデータがどこにストアされているか見るために、IPFS ハッシュが必要となります。これにアクセスしたら、このデータを変数に保存してから、この変数を The Graph ノードに保存して、クエリできるようにする必要があります。
src 下に mappning.ts を作ります
import {
Transfer as TransferEvent
} from "../generated/Token/Token";
import { Lady, User } from "../generated/schema";
import { log, ipfs, json, JSONValue } from "@graphprotocol/graph-ts";
const ipfsHash = "QmTngWTnURuyiz1gtoY33FKghCiU2uQusXpnUc36QJNKsY";
export function handleTransfer(event: TransferEvent): void {
let lady = Lady.load(event.params.tokenId.toString());
if (lady == null) {
lady = new Lady(event.params.tokenId.toString());
lady.tokenID = event.params.tokenId;
lady.tokenURI = "/" + event.params.tokenId.toString();
let metadata = ipfs.cat(ipfsHash + lady.tokenURI);
if (metadata) {
const value = json.fromBytes(metadata).toObject();
if (value) {
const name = value.get("name");
if (name) {
lady.name = name.toString();
}
}
let attributes: JSONValue[];
let ladyAttributes = value.get("attributes");
if (ladyAttributes) {
attributes = ladyAttributes.toArray();
for (let i = 0; i < attributes.length; i++) {
let item = attributes[i].toObject();
let trait: string;
let traitName = item.get("trait_type");
if (traitName) {
trait = traitName.toString();
let value: string;
let traitValue = item.get("value");
if (traitValue) {
value = traitValue.toString();
if (trait == "Hair") {
lady.hairStyle = value;
}
if (trait == "Skin") {
lady.skinColor = value;
}
if (trait == "Eyes") {
lady.eyeColor = value;
}
if (trait == "Face Expression") {
lady.faceExpression = value;
}
}
}
}
}
}
}
lady.owner = event.params.to.toHexString();
lady.save();
let user = User.load(event.params.to.toHexString());
if (!user) {
user = new User(event.params.to.toHexString());
user.save();
}
}
9. Authenticate with your deploy key
デプロイの準備をします。
↓ "My Dashboard" にある、アクセストークンの場所(オレンジのバーでで隠してあるところ)
"My Dashboard" からアクセストークンを持ってきて、これをターミナルで叩きます
graph auth https://api.thegraph.com/deploy/ <アクセストークン>
10: Deploy your subgraph
デプロイします
npm run deploy
エラー?
もし
subgraph validation error: [The feature 'ipfsOnEthereumContracts' is used by the subgraph but it is not declared in the manifest.]
というエラーがでたら、
英語の原文 の subgraph.yaml
では
features:
- ipfsOnEthereumContracts
が書かれていませんが、書いてください。(この私の記事に書いたコードは追記済みです)
すべてのソースコード