Por muitos anos, o desenvolvimento de aplicativos descentralizados (DAPP) sofreu com a acessibilidade de dados, consultar uma informação específica ou usar dados diretamente persistidos na blockchain costumava ser um desafio até que uma equipe de três desenvolvedores decidiu construir um protocolo de indexação de dados para Web3 que permitiria aos desenvolvedores criar DAPPs, totalmente alimentados por uma infraestrutura pública conhecida hoje como The Graph.
Sumário
1 . O que é o protocolo The Graph
9 . Conclusão
O que é o protocolo The Graph
Como mencionado anteriormente, o Protocolo The Graph é um protocolo descentralizado para indexação e consulta de dados blockchains.
O que é necessário
Para aproveitar ao máximo este tutorial e acompanhá-lo, leia a primeira parte desta série aqui . Acesse o site do The Graph, crie uma conta, selecione hosted services como opção de implantação e crie um novo projeto de subgráfico da seguinte forma:
Configuração do projeto
Crie um novo diretório para guardar o projeto.
mkdir ongama-nft-subgraph && cd ongama-nft-subgraph
Crie uma pasta no diretório do projeto chamada abi onde você pode adicionar a abi do contrato NFT (NFT.json
) gerado na primeira parte desta série após executar truffle compile
Em seguida, instale a CLI Graph:
npm install -g @graphprotocol/graph-cli
Como já implantamos nosso Contrato Inteligente NFT na testnet (Mumbai), podemos executar o seguinte comando para inicializar o projeto:
graph init --from-contract <CONTRACT_ADDRESS> \
[--network <ETHEREUM_NETWORK>] \
[--abi <FILE>] \
<GITHUB_USER>/<SUBGRAPH_NAME> [<DIRECTORY>]
Vamos pegar o endereço do contrato da implantação que fizemos na primeira parte deste artigo, o comando init deve ser o seguinte:
graph init --from-contract 0x0b689AC2f5e1D925A0441cE4B3E949f3A15bD0f4 --protocol ethereum \
--network testnet --contract-name NFT --index-events
? Product for which to initialize › hosted-service
? Subgraph name › your-username/your-subgraph-project-name
? Directory to create the subgraph in › your-subgraph-project-name
? Ethereum network › mumbai
? Contract address › 0x0b689AC2f5e1D925A0441cE4B3E949f3A15bD0f4
? ABI file (path) ./abi/NFT.json
? Contract Name · NFT
Este comando irá gerar um projeto subgrafo básico com base no endereço do contrato passado como argumento para --from-contract
. Ao usar esse endereço de contrato, a CLI inicializará algumas coisas em seu projeto para você começar (incluindo buscar as abis
e salvá-las no diretório abis).
Ao passar --index-events
, a CLI preencherá automaticamente algum código para nós tanto em schema.graphql quanto em src/mapping.ts com base nos eventos emitidos do contrato.
A base de código do subgrafo consiste em alguns poucos arquivos:
- subgraph.yaml: um arquivo YAML contendo a configuração principal e a definição do subgrafo
- schema.graphql: um esquema GraphQL que define quais dados são armazenados para seu subgrafo e como consultá-los via GraphQL
- AssemblyScript Mappings: código AssemblyScript que converte os dados do evento na Ethereum para as entidades definidas em seu esquema (por exemplo, mapping.ts neste tutorial)
Configuração do projeto 2
specVersion: 0.0.2
schema:
file: ./schema.graphql
dataSources:
- kind: ethereum
name: NFT
network: mumbai
source:
address: "0xB08347548b9DC9B1211D37913CE0f305FF477AcE"
abi: NFT
startBlock: 25957921
mapping:
kind: ethereum/events
apiVersion: 0.0.5
language: wasm/assemblyscript
entities:
- User
- NFT
- Activity
abis:
- name: NFT
file: ./abis/NFT.json
eventHandlers:
- event: Minted(indexed address,uint256,uint256,string)
handler: handleNFTCreation
- event: PriceUpdate(indexed address,uint256,uint256,uint256)
handler: handleNFTPriceUpdate
file: ./src/mapping.ts
Como podemos ver, o arquivo subgraph.yaml define o seguinte:
name
: define o nome do contrato, nesta configuração temos NFT como nome do contrato.network
: especificamos Mumbai, pois é o nome da rede de teste da Polygon.dataSources.source
: o endereço do contrato inteligente, as fontes do subgrafo e a abi do contrato inteligente a ser usado. Nesse caso, temos 0xB08347548b9DC9B1211D37913CE0f305FF477AcE.dataSources.source.startBlock
(opcional): o número do bloco a partir do qual a fonte de dados inicia a indexação. Estamos indexando do bloco número 25957921.dataSources.mapping.entities
: as entidades que a fonte de dados grava no armazenamento. O esquema para cada entidade é definido no arquivo schema.graphql. Vamos definir as entidades User, NFT & Activity dentro do arquivo de esquema.dataSources.mapping.abis
: um ou mais arquivos ABI nomeados para o contrato de origem, bem como quaisquer outros contratos inteligentes com os quais você interage a partir dos mapeamentos.dataSources.mapping.eventHandlers
: lista os eventos de contratos inteligentes aos quais este subgrafo reage e os manipuladores no mapeamento — ./src/mapping.ts no exemplo — que transformam esses eventos em entidades no armazenamento. Nosso contrato suporta apenas dois eventos que especificamos na seção eventHandlers.
Definição de Schema
As entidades/dados que iremos indexar são NFT
, Activity
e User
. Desta forma podemos indexar as informações dos NFTs, suas atividades e usuários associados a eles.
Vamos atualizar schema.graphql com o seguinte código:
type User @entity {
id: ID!
creations: [NFT!] @derivedFrom(field: "creator")
collections: [NFT!] @derivedFrom(field: "owner")
}
type NFT @entity {
id: ID!
owner: User!
creator: User!
price: BigInt!
tokenID: BigInt!
tokenUri: String!
txHash: Bytes!
actitity: [Activity!] @derivedFrom(field: "nft")
}
type Activity @entity {
id: ID!
nft: NFT
type: ActivityType!
from: User
to: User
txHash: Bytes!
price: BigInt
timestamp: BigInt!
}
enum ActivityType {
MINT
PRICE_UPDATE
}
O ponto de exclamação à direita (!) é usado para denotar um campo não-anulável e @derivedFrom
cria um campo virtual na entidade que pode ser consultado, mas não pode ser definido manualmente por meio da API de mapeamentos. Em vez disso, é derivado do relacionamento definido na outra entidade.
Para relacionamentos um-para-muitos, o relacionamento sempre deve ser armazenado no lado 'um' e o lado 'muitos' sempre deve ser derivado. Podemos gerar as entidades localmente para começar a usar nos mappings
criados executando este comando:
graph codegen
Depois de executar o comando acima, a Graph CLI gera tipos de AssemblyScript a partir de uma combinação do esquema GraphQL do subgrafo e das ABIs de contrato incluídas nas fontes de dados.
Implementação de Mapping
Agora, vamos atualizar src/mappings.ts adicionando a implementação de nossos dois manipuladores especificados dentro do arquivo de configuração.
import {
Minted as MintedEvent,
PriceUpdate as PriceUpdateEvent,
} from "../generated/NFT/NFT";
import { NFT, Activity } from "../generated/schema";
import { getOrCreateUser, getNFTByID } from "./util";
export function handleNFTCreation(event: MintedEvent): void {
let nft = new NFT(event.params.nftID.toString());
nft.owner = getOrCreateUser(event.params.minter).id;
nft.creator = getOrCreateUser(event.params.minter).id;
nft.price = event.params.price;
nft.tokenID = event.params.nftID;
nft.tokenUri = event.params.uri;
nft.txHash = event.transaction.hash;
nft.save();
let activity = new Activity(`${event.transaction.hash.toHex()}-${nft.id}`);
activity.nft = nft.id;
activity.type = "MINT";
activity.to = getOrCreateUser(event.params.minter).id;
activity.price = nft.price;
activity.timestamp = event.block.timestamp;
activity.txHash = event.transaction.hash;
activity.save();
}
export function handleNFTPriceUpdate(event: PriceUpdateEvent): void {
let nft = getNFTByID(event.params.nftID.toString());
if (!nft) return;
nft.price = event.params.newPrice;
nft.save();
let activity = new Activity(`${event.transaction.hash.toHex()}-${nft.id}`);
activity.nft = nft.id;
activity.type = "PRICE_UPDATE";
activity.to = getOrCreateUser(event.params.owner).id;
activity.price = nft.price;
activity.timestamp = event.block.timestamp;
activity.txHash = event.transaction.hash;
activity.save();
}
Esses mappings manipularão eventos para quando um novo NFT for cunhado e quando seu preço for atualizado. Os mappings garantirão que os dados sejam salvos no subgrafo quando esses eventos forem acionados.
Vamos criar um arquivo na pasta src
chamado util
que conterá a implementação das funções getOrCreateUser
e getNFTByID
.
import { Bytes } from "@graphprotocol/graph-ts";
import { User, NFT } from "../generated/schema";
export function getOrCreateUser(address: Bytes): User {
return getOrCreateUserFromString(address.toHex());
}
export function getOrCreateUserFromString(address: string): User {
let user = User.load(address);
if (!user) {
user = new User(address);
user.save();
}
return user as User;
}
export function getNFTByID(id: string): NFT | null {
return NFT.load(id);
}
Construção do Projeto
Em seguida, vamos executar uma compilação para garantir que tudo esteja configurado corretamente. Para fazer isso, execute o comando build
:
graph build
Se a compilação for bem-sucedida, você deverá ver uma nova pasta de compilação gerada em seu diretório raiz.
Implantação do Projeto
Para implantar, primeiro você precisará copiar o token de acesso para sua conta, disponível no Graph Explorer:
Em seguida, execute o seguinte comando:
$ graph auth
✔ Product for which to initialize · hosted-service
✔ Deploy key · ********************************
yarn deploy
Depois que o subgrafo for implantado, você deverá vê-lo em seu painel:
Seu endpoint do Graph deve ficar assim:
https://thegraph.com/explorer/subgraph/your-username/your-subgraph-name
https://api.thegraph.com/subgraphs/name/verdotte/ongama
Agora, devemos começar a consultar dados usando várias consultas que podemos projetar com base em nossa definição de esquema. Por exemplo:
{
nfts {
id
price
tokenID
tokenUri
owner {
id
}
creator {
id
}
activities {
price
type
txHash
timestamp
}
}
}
Também podemos adicionar parâmetros de filtragem extras como:
{
activities (
where: { type: "MINT" },
orderBy: price,
orderDirection: desc,
first: 10,
skip: 100
) {
price
type
txHash
timestamp
}
}
Conclusão
Aplicativos descentralizados começaram a ganhar popularidade entre os usuários. À medida que o espaço continua a crescer, espera-se que o desenvolvimento, a adoção e o uso de DApps também cresçam exponencialmente. É aqui que o Protocolo The Graph pode desempenhar um grande papel para os desenvolvedores. Ao tornar os dados blockchain e APIs facilmente acessíveis, o Protocolo The Graph está se tornando uma opção para gravar dados de blockchains de forma descentralizada.
Confira estes recursos para obter mais detalhes sobre o Protocolo The Graph:
https://github.com/dabit3/building-a-subgraph-workshop
https://portal.gitnation.org/contents/building-graphql-apis-on-top-of-ethereum-with-the-graph
Esse artigo é uma tradução feita por @bananlabs. Você pode encontrar o artigo original aqui
Latest comments (0)