The Graph 数据查询
The Graph 数据查询
本页内容正在整理中,欢迎贡献。
概述
直接通过 RPC 查询历史链上数据效率极低。The Graph 是去中心化的区块链数据索引协议,允许开发者定义 Subgraph(子图)来索引合约事件,并通过 GraphQL API 高效查询。Uniswap、Aave、ENS 等主流协议都使用 The Graph。
主要内容
核心概念
| 概念 | 说明 |
|---|---|
| Subgraph | 定义索引哪些合约事件、如何存储数据的配置 |
| Indexer | 运行节点索引 Subgraph 数据的节点运营商 |
| GraphQL API | 查询已索引数据的接口 |
| Hosted Service | The Graph 的托管服务(开发测试用) |
| Subgraph Studio | 发布 Subgraph 的管理平台 |
使用现有 Subgraph
许多协议已发布公开 Subgraph,可直接查询:
// 查询 Uniswap V3 数据const UNISWAP_V3_SUBGRAPH = "https://gateway.thegraph.com/api/YOUR_API_KEY/subgraphs/id/...";
const query = ` { pools(first: 10, orderBy: totalValueLockedUSD, orderDirection: desc) { id token0 { symbol } token1 { symbol } totalValueLockedUSD volumeUSD } }`;
const response = await fetch(UNISWAP_V3_SUBGRAPH, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query }),});const { data } = await response.json();使用 urql 或 Apollo Client
npm install urql graphql# 或npm install @apollo/client graphql// 使用 urql(轻量级,推荐)import { createClient, cacheExchange, fetchExchange } from "urql";
const client = createClient({ url: "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3", exchanges: [cacheExchange, fetchExchange],});
// React Hook 方式import { useQuery } from "urql";
const TOKENS_QUERY = ` query GetTopTokens($first: Int!) { tokens(first: $first, orderBy: totalValueLockedUSD, orderDirection: desc) { id symbol name totalValueLockedUSD volumeUSD } }`;
function TopTokens() { const [{ data, fetching, error }] = useQuery({ query: TOKENS_QUERY, variables: { first: 10 }, });
if (fetching) return <p>加载中...</p>; if (error) return <p>错误: {error.message}</p>;
return ( <ul> {data.tokens.map((token: any) => ( <li key={token.id}>{token.symbol} - TVL: ${Number(token.totalValueLockedUSD).toFixed(0)}</li> ))} </ul> );}创建自定义 Subgraph
1. 安装 Graph CLI
npm install -g @graphprotocol/graph-cligraph init --studio my-subgraph2. Subgraph Manifest(subgraph.yaml)
specVersion: 0.0.5schema: file: ./schema.graphqldataSources: - kind: ethereum name: MyToken network: mainnet source: address: "0x合约地址" abi: MyToken startBlock: 18000000 # 合约部署区块 mapping: kind: ethereum/events apiVersion: 0.0.7 language: wasm/assemblyscript entities: - Transfer abis: - name: MyToken file: ./abis/MyToken.json eventHandlers: - event: Transfer(indexed address,indexed address,uint256) handler: handleTransfer file: ./src/mapping.ts3. GraphQL Schema(schema.graphql)
type Transfer @entity { id: ID! from: Bytes! to: Bytes! value: BigInt! blockNumber: BigInt! timestamp: BigInt!}
type Account @entity { id: Bytes! # address transfersFrom: [Transfer!]! @derivedFrom(field: "from") transfersTo: [Transfer!]! @derivedFrom(field: "to") balance: BigInt!}4. 映射处理器(src/mapping.ts)
import { Transfer as TransferEvent } from "../generated/MyToken/MyToken";import { Transfer, Account } from "../generated/schema";import { BigInt } from "@graphprotocol/graph-ts";
export function handleTransfer(event: TransferEvent): void { // 保存 Transfer 记录 const transfer = new Transfer( event.transaction.hash.concatI32(event.logIndex.toI32()) ); transfer.from = event.params.from; transfer.to = event.params.to; transfer.value = event.params.value; transfer.blockNumber = event.block.number; transfer.timestamp = event.block.timestamp; transfer.save();}5. 部署 Subgraph
graph codegen && graph buildgraph auth --studio YOUR_DEPLOY_KEYgraph deploy --studio my-subgraph查询过滤与分页
{ # 过滤:查询某地址的转账 transfers( where: { from: "0x地址" } orderBy: timestamp orderDirection: desc first: 20 skip: 0 ) { id from to value timestamp }}深入阅读
- The Graph 官方文档
- Subgraph Studio
- Graph Explorer —— 浏览公开 Subgraph
- 数据索引概述