用 Subgraph Studio 创建子图

用 Subgraph Studio 创建子图

发布时间:2021.07.08
原文作者:The Graph 基金会
译者:The Graph 社区成员


子图是 The Graph 的一个核心组成部分。它们允许任何开发人员使用从以太坊、IPFS 和其他区块链等去中心化网络中索引的数据来构建和部署高性能和可发现的 API。子图开发者定义哪些数据将从区块链上被索引,以及如何存储和通过 API 层提供。许多应用程序建立并使用子图来驱动其生产应用程序。

今天推出的 Subgraph Studio 使开发者能够无权限地在子图上进行部署和策展,以赚取查询费,The Graph 上的策展是以太坊上第一批以这种规模上线的策展市场之一。

在本指南中,您将学习如何使用 Graph CLI 和 Subgraph Studio 构建您的第一个子图。你将建立的子图将用于索引和查询 Zora 智能合约的数据。Zora 是一个 NFT 市场。Zora 有一个开发者网站,上面有他们的智能合约地址的链接,以及一个官方子图。

你将学习如何通过对 Zora 智能合约的数据进行索引,建立、测试和发布一个类似于 The Graph 的去中心化网络的子图。

按照这个指南,使用 Subgraph Studio 在去中心化网络上构建和发布子图。

前提条件

1、 要在本教程中取得成功,你应该具备以下条件:

2、 在你的机器上安装了 Node.js
Metamask 钱包
开始

要想开始,请访问 Subgraph Studio,网址是https://thegraph.com/studio

在这里,点击连接钱包,选择一个钱包地址进行认证。一旦你通过认证,你应该能够点击创建子图来创建一个新的子图。

在这里,给子图一个名字,然后点击继续。

接下来,你会看到你的子图的视图,使你能够添加可选的元数据,如子图描述和图像,以及查看一些有用的信息,如子图的部署密钥、slug 和状态。

现在你的子图项目已经在 Studio 中创建,你可以继续进入你的本地开发环境并打开你的终端。

接下来,进入或创建一个空目录,使用 NPM 安装 Graph CLI。

npm install -g @graphprotocol/graph-cli

一旦 Graph CLI 被安装,你可以用 Graph CLI init 命令初始化一个新的子图。

graph init --contract-name Token --index-events --product subgraph-studio --from-contract 0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7

然后,将出现以下提示:

✔ 子图名称

✔ 创建子图的目录

✔ 以太坊网络 - mainnet

✔ 合同地址 - 0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7

✔ 从 Etherscan 获取 ABI

✔ 合同名称-Token

这将根据作为 --from-contract 参数传入的合同地址生成一个基本子图。通过使用这个合同地址,CLI 将在你的项目中初始化一些东西以使你开始工作(包括获取 ABI 并将其保存在 ABI 目录中)。

通过传入 --index-events 标志,CLI 将根据合同发出的事件,在 schema.graphql 以及 hide/mapping.ts 中自动为我们填充一些代码和配置。

子图代码库由几个文件组成:

  • subgraph.yaml:一个包含子图清单的 YAML 文件。一个子图的主要配置和定义都在 subgraph.yaml 中。

  • schema.graphql:一个 GraphQL 模式,它定义了你的子图所存储的数据,以及如何通过 GraphQL 查询它。

  • AssemblyScript 映射:AssemblyScript 代码,将 Ethereum 中的事件数据转换为模式中定义的实体(例如本教程中的 mapping.ts)。

你要处理的 subgraph.yaml 中的条目是:

  • dataSources.source:智能合约的地址,子图源,以及你所使用的智能合约的 ABI。地址是可选的;省略它可以索引所有合约的匹配事件。

  • dataSources.source.startBlock (可选):数据源开始索引的块的编号。在大多数情况下,我们建议使用创建合同的区块,如果不是,那么索引人将从创世区块开始。

  • dataSources.mapping.entities : 数据源写入存储的实体。每个实体的模式在 schema.graphql 文件中定义。

  • dataSources.mapping.abis:一个或多个命名的 ABI 文件,用于源合约以及你在映射中与之互动的任何其他智能合约。

  • dataSources.mapping.eventHandlers:列出该子图反应的智能合约事件,以及映射中的处理程序--本例中为 ./hide/mapping.ts--将这些事件转化为存储中的实体。

界定实体:

通过 The Graph,你在 schema.graphql 中定义实体类型,Graph Node 将生成顶层字段,用于查询该实体类型的单个实例和集合。每个应该成为实体的类型都需要用 @entity 指令来注释。

我们要索引的实体 / 数据是 Token 和 User。这样,我们就可以对用户创建的 Token 以及用户本身进行索引。

要做到这一点,用以下代码更新 schema.graphql:

type Token @entity {  id: ID!  tokenID: BigInt!  contentURI: String!  metadataURI: String!  createdAtTimestamp: BigInt!  creator: User!  owner: User!}  
type User @entity {  id: ID!  tokens: [Token!]! @derivedFrom(field: "owner")  created: [Token!]! @derivedFrom(field: "creator")}

通过 @derivedFrom 的关系:

反向查询可以通过 @derivedFrom 字段在实体上定义。这在实体上创建了一个可以被查询的虚拟字段,但不能通过映射 API 手动设置。相反,它是从另一个实体上定义的关系派生出来的。对于这样的关系,存储关系的两边很少有意义,当只有一边被存储而另一边被派生时,索引和查询性能都会更好。

对于一对多的关系,关系应该总是存储在 " 一 " 边,而 " 多 " 边应该总是被导出。以这种方式存储关系,而不是在 " 多 " 边存储一个实体数组,将使索引和查询子图的性能大大提升。一般来说,应该尽可能地避免存储实体的数组。

现在我们已经为我们的应用程序创建了 GraphQL 模式,我们可以在本地生成实体,开始在 CLI 创建的映射中使用:

  graph codegen

为了使智能合约、事件和实体的工作变得简单和类型安全,Graph CLI 从子图的 GraphQL 模式和数据源中包含的合约 ABI 的组合中产生 AssemblyScript 类型。

用实体和映射更新子图

现在你可以更新 subgraph.yaml 中的主配置,以使用你刚刚创建的实体,并配置它们的映射关系。

要做到这一点,首先用 User 和 Token 实体更新 dataSources.mapping.entities 字段。

entities:  - Token  - User

接下来,更新 dataSources.mapping.eventHandlers,只包括以下两个事件处理程序:

eventHandlers:  - event: TokenURIUpdated(indexed uint256,address,string)    handler: handleTokenURIUpdated  - event: Transfer(indexed address,indexed address,indexed uint256)    handler: handleTransfer

这些事件处理程序将把 Ethereum 事件映射到本地项目中的一个函数。在该函数中,我们将能够与 Graph 节点进行交互并写入该节点。

最后,更新配置,添加 startBlock:

source:  address: "0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7"  abi: Token  startBlock: 11565020

最终的 subgraph.yaml 文件应该看起来像这样:

specVersion: 0.0.2schema:file: ./schema.graphqldataSources:- kind: ethereum/contract name: Token network: mainnet source:   address: "0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7"   abi: Token   startBlock: 11565020 mapping:   kind: ethereum/events   apiVersion: 0.0.4   language: wasm/assemblyscript   entities:     - Token     - User   abis:     - name: Token       file: ./abis/Token.json   eventHandlers:     - event: TokenURIUpdated(indexed uint256,address,string)       handler: handleTokenURIUpdated     - event: Transfer(indexed address,indexed address,indexed uint256)       handler: handleTransfer   file: ./hide/mapping.ts

汇编脚本映射

接下来,我们可以配置 AssemblyScript 映射来处理 subgraph.yaml 中定义的事件。

为了生成我们需要的代码,我们可以从 Graph CLI 运行 codegen 命令:

graph codegen

这个命令在一个名为 generated 的文件夹中创建了一些辅助代码,它将给我们提供类型安全以及允许我们与 Graph Node 以及智能合约本身互动的功能。

接下来,打开 hide/mappings.ts,为我们在 subgraph.yamleventHandlers 中定义的事件映射编写映射逻辑。

这些映射是用 AssemblyScript 编写的,它的语法与 TypeScript 非常相似。这些映射允许我们从 The Graph 节点读取数据,并将数据保存到 The Graph 节点。你也可以通过直接与区块链互动,从智能合约中读取数据。

此时有两种 API 可以使用:Graph TypeScript 库(@graphprotocol/graph-ts)和由 graph codegen 从子图文件生成的代码。

@graphprotocol/graph-ts 库提供了以下 API:

  • 一个用于处理智能合约、事件、区块、交易和区块链价值的 API。
  • 存储 API,用于从 Graph Node 存储中加载和保存实体。
  • 日志 API,用于将信息记录到 Graph Node 输出和 Graph Explorer 中。
  • IPFS API,用于从 IPFS 加载文件。
  • JSON API,用于解析 JSON 数据。
  • 用于使用加密功能的密码学 API。
  • 在不同的类型系统(如 Ethereum、JSON、GraphQL 和 AssemblyScript)之间进行转换的低级基元。

用以下代码更新 hide/mappings.ts:

import {TokenURIUpdated as TokenURIUpdatedEvent,Transfer as TransferEvent,Token as TokenContract} from "../generated/Token/Token"  
import {Token, User} from '../generated/schema'  
export function handleTransfer(event: TransferEvent): 
void {let token = Token.load(event.params.tokenId.toString());
if (!token) { token = new Token(event.params.tokenId.toString());      token.creator = event.params.to.toHexString(); 
token.tokenID = event.params.tokenId; 
token.createdAtTimestamp = event.block.timestamp;  
 let tokenContract = TokenContract.bind(event.address); 
 token.contentURI = tokenContract.tokenURI(event.params.tokenId); token.metadataURI = tokenContract.tokenMetadataURI(event.params.tokenId);}
 token.owner = event.params.to.toHexString();token.save();  
let user = User.load(event.params.to.toHexString());
if (!user) { user = new User(event.params.to.toHexString()); 
user.save();}}  
export function handleTokenURIUpdated(event: TokenURIUpdatedEvent): 
void {let token = Token.load(event.params._tokenId.toString());
token.contentURI = event.params._uri;token.save();}

当一个令牌被创建或从一个部分转移到另一个部分时,handleTransfer 函数将被调用。

当令牌所有者更新令牌的内容 URI 时,handleTokenURIUpdated 函数将被调用。

部署和测试子图

现在,子图已经完成,它已经准备好被部署到工作室进行测试。

在部署之前,我们首先需要进行认证。要做到这一点,把 DEPLOY KEY 复制到你的剪贴板上。接下来,打开你的 CLI 并运行以下命令:

graph auth --studio

当提示时,粘贴你的 DEPLOY KEY。

现在你可以使用 deploy 命令来部署你的子图了:

graph deploy --studio (子图名)

当提示你输入版本标签时,为子图选择一个版本。

一旦子图被部署,工作室应该更新一个新的用户界面,允许你在 GraphQL 面板上测试查询,以及查看日志和其他细节。

现在,子图已经成功部署,我们可以开始查询数据了。

要做到这一点,你可以对用户和令牌以及用户和令牌之间的关系数据运行 GraphQL 查询。为了测试它,让我们运行下面的查询。这个查询将返回一个 NFT 数据数组,包括每个令牌的内容 URI、令牌 ID、内容 URI 和元数据 URI。

  {  tokens {    id    tokenID    contentURI    metadataURI  }}

你也可以传入参数以返回不同的选择集,如过滤器和全文搜索。例如,让我们按照项目的创建日期排序,并以降序返回。

  {  tokens(    orderBy:createdAtTimestamp,    orderDirection: desc  ) {    id    tokenID    contentURI    metadataURI  }}

在这一点上,子图只被部署到工作室,可以被认为是一个测试或暂存环境。接下来的步骤是部署到测试网或主网。

要部署到一个网络,点击 "发布" 按钮。这里,你将被提示选择你想部署到哪个网络。

让我们通过切换到 Rinkeby 测试网并在那里发布子图来测试一下。请确保你的 MetaMask 钱包连接到了正确的网络。

要部署到 rinkeby,你的钱包里需要有一些测试令牌。如果你没有,请到https://faucet.rinkeby.io/,先获得一些。

一旦你的钱包中收到了测试令牌,请尝试将子图发布到 Rinkeby 网络。

接下来应该会提示你批准天然气价格来发布子图。

一旦子图被成功发布,你应该看到确认,以及在 Graph Explorer 中查看它的链接。

当你点击在 Graph Explorer 中查看的链接时,你应该看到你的子图的一个新的视图,具有模拟查询以及索引的能力。

在你的子图上进行策展 !

现在你已经建立并发布了你的子图,你也可以通过用 GRT 在你的子图上发出信号来获得奖励。要在你的子图上发出信号,你可以使用测试 The Graph 令牌(GRT)。要获得测试令牌,你可以加入 The Graph Discord 服务器,在🚰-testnet-faucet 频道中申请令牌。当你准备好了,你可以在主网的子图上发出信号。

在这里https://thegraph.com/blog/curation-live了解更多关于策展的信息。

如果你有任何关于构建子图的问题,请跳到 The Graph Discord询问其他开发者,或者在 The Graph 论坛上发帖,开始讨论。

关于 The Graph

The Graph 是去中心化网络的索引和查询层。开发者构建并发布开放的 API,称为子图,应用程序可以使用 GraphQL 进行查询。The Graph 目前支持 Ethereum、IPFS 及 POA 的数据索引,并即将支持更多底层网络。到目前为止,已经有超过 8000 个子图被超过 10000 个活跃的开发者部署,应用于 Uniswap、Synthetix、Aragon、Gnosis、Balancer、Livepeer、DAOstack、AAVE、Decentraland 等。

如果你是一个构建应用程序或 Web3 应用程序的开发人员,你可以使用子图来索引和查询区块链的数据。The Graph 允许应用程序在用户界面中高效、高性能地展示数据,并允许其他开发人员也使用你的子图。您可以部署子图或在 Graph 浏览器中查询现有的子图。

The Graph 非常欢迎您成为 The Graph 网络的索引人、策展人或委托人。通过在 Graph Discord 中进行自我介绍来加入 Graph 社区进行技术讨论,加入 Graph 的电报聊天,或在 Twitter 上关注 Graph。

The Graph 基金会负责监督 The Graph 网络。The Graph 基金会由技术委员会监督。Edge & Node 为 The Graph 基金会提供服务。

The Graph 的 测试网中有来自 90 多个不同国家的 2000 多名 策展人和来自 50 多个国家的 200 多名索引人。The Graph 社区分布在全球范围内,有来自全球 99 个不同国家的 4500 多名 GRT 持有者。任何持有 GRT 的人都可以进行委托。今天,The Graph 网络上有超过 5000 名委托人和 200 多名索引人。