subgraphs > Developing > Creating > Subgraph Manifest

Subgraph Manifest

Reading time: 14 min

Genel Bakış

Bu bölüme bağlantı

The subgraph manifest, subgraph.yaml, defines the smart contracts & network your subgraph will index, the events from these contracts to pay attention to, and how to map event data to entities that Graph Node stores and allows to query.

The subgraph definition consists of the following files:

  • subgraph.yaml: Contains the subgraph manifest

  • schema.graphql: A GraphQL schema defining the data stored for your subgraph and how to query it via GraphQL

  • mapping.ts: AssemblyScript Mappings code that translates event data into entities defined in your schema (e.g. mapping.ts in this guide)

Subgraph Capabilities

Bu bölüme bağlantı

Tek bir subgraph:

  • Birden fazla akıllı sözleşmeden veri endeksleyebilir (fakat birden fazla ağdan endeksleyemez).

  • IPFS dosyalarından Dosya Veri Kaynakları kullanarak veri endeksleyebilir.

  • Add an entry for each contract that requires indexing to the dataSources array.

The full specification for subgraph manifests can be found here.

For the example subgraph listed above, subgraph.yaml is:

specVersion: 0.0.4
description: Gravatar for Ethereum
repository: https://github.com/graphprotocol/graph-tooling
schema:
file: ./schema.graphql
indexerHints:
prune: auto
dataSources:
- kind: ethereum/contract
name: Gravity
network: mainnet
source:
address: '0x2E645469f354BB4F5c8a05B3b30A929361cf77eC'
abi: Gravity
startBlock: 6175244
endBlock: 7175245
context:
foo:
type: Bool
data: true
bar:
type: String
data: 'bar'
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
entities:
- Gravatar
abis:
- name: Gravity
file: ./abis/Gravity.json
eventHandlers:
- event: NewGravatar(uint256,address,string,string)
handler: handleNewGravatar
- event: UpdatedGravatar(uint256,address,string,string)
handler: handleUpdatedGravatar
callHandlers:
- function: createGravatar(string,string)
handler: handleCreateGravatar
blockHandlers:
- handler: handleBlock
- handler: handleBlockWithCall
filter:
kind: call
file: ./src/mapping.ts

Subgraph Entries

Bu bölüme bağlantı

Important Note: Be sure you populate your subgraph manifest with all handlers and entities.

Manifest için güncellenmesi gereken önemli girdiler şunlardır:

  • specVersion: a semver version that identifies the supported manifest structure and functionality for the subgraph. The latest version is 1.2.0. See specVersion releases section to see more details on features & releases.

  • description: a human-readable description of what the subgraph is. This description is displayed in Graph Explorer when the subgraph is deployed to Subgraph Studio.

  • repository: the URL of the repository where the subgraph manifest can be found. This is also displayed in Graph Explorer.

  • features: a list of all used feature names.

  • indexerHints.prune: Defines the retention of historical block data for a subgraph. See prune in indexerHints section.

  • dataSources.source: the address of the smart contract the subgraph sources, and the ABI of the smart contract to use. The address is optional; omitting it allows to index matching events from all contracts.

  • dataSources.source.startBlock: the optional number of the block that the data source starts indexing from. In most cases, we suggest using the block in which the contract was created.

  • dataSources.source.endBlock: The optional number of the block that the data source stops indexing at, including that block. Minimum spec version required: 0.0.9.

  • dataSources.context: key-value pairs that can be used within subgraph mappings. Supports various data types like Bool, String, Int, Int8, BigDecimal, Bytes, List, and BigInt. Each variable needs to specify its type and data. These context variables are then accessible in the mapping files, offering more configurable options for subgraph development.

  • dataSources.mapping.entities: the entities that the data source writes to the store. The schema for each entity is defined in the schema.graphql file.

  • dataSources.mapping.abis: one or more named ABI files for the source contract as well as any other smart contracts that you interact with from within the mappings.

  • dataSources.mapping.eventHandlers: lists the smart contract events this subgraph reacts to and the handlers in the mapping—./src/mapping.ts in the example—that transform these events into entities in the store.

  • dataSources.mapping.callHandlers: lists the smart contract functions this subgraph reacts to and handlers in the mapping that transform the inputs and outputs to function calls into entities in the store.

  • dataSources.mapping.blockHandlers: lists the blocks this subgraph reacts to and handlers in the mapping to run when a block is appended to the chain. Without a filter, the block handler will be run every block. An optional call-filter can be provided by adding a filter field with kind: call to the handler. This will only run the handler if the block contains at least one call to the data source contract.

A single subgraph can index data from multiple smart contracts. Add an entry for each contract from which data needs to be indexed to the dataSources array.

Olay İşleyicileri

Bu bölüme bağlantı

Bir subgraph'in olay işleyicileri, blokzincir üzerindeki akıllı sözleşmeler tarafından yayılan belirli olaylara tepki verir, ve subgraph'in manifesto dosyasında tanımlanan işleyicileri tetikler. Bu, subgraph'lerin tanımlanmış mantığa göre olay verilerini işlemesini ve depolamasını sağlar.

Olay İşleyici Tanımlama

Bu bölüme bağlantı

Bir olay işleyici, subgraph'in YAML yapılandırmasında bir veri kaynağı içinde tanımlanır. Hangi olayların dinleneceğini ve bu olaylar algılandığında hangi fonksiyonun çalıştırılacağını belirtir.

dataSources:
- kind: ethereum/contract
name: Gravity
network: dev
source:
address: '0x731a10897d267e19b34503ad902d0a29173ba4b1'
abi: Gravity
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
entities:
- Gravatar
- Transaction
abis:
- name: Gravity
file: ./abis/Gravity.json
eventHandlers:
- event: Approval(address,address,uint256)
handler: handleApproval
- event: Transfer(address,address,uint256)
handler: handleTransfer
topic1: ['0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', '0xc8dA6BF26964aF9D7eEd9e03E53415D37aA96325'] # Opsiyonel konu filtresi, sadece verilen konuyu içeren olayları filtreler.

Çağrı İşleyicileri

Bu bölüme bağlantı

While events provide an effective way to collect relevant changes to the state of a contract, many contracts avoid generating logs to optimize gas costs. In these cases, a subgraph can subscribe to calls made to the data source contract. This is achieved by defining call handlers referencing the function signature and the mapping handler that will process calls to this function. To process these calls, the mapping handler will receive an ethereum.Call as an argument with the typed inputs to and outputs from the call. Calls made at any depth in a transaction's call chain will trigger the mapping, allowing activity with the data source contract through proxy contracts to be captured.

Çağrı işleyicileri yalnızca iki durumdan birinde tetiklenir: belirtilen işlevin sözleşme tarafından değil, başka bir hesap tarafından çağrılması durumunda veya Solidity'de harici olarak işaretlenip aynı sözleşmenin başka bir işlevinin bir parçası olarak çağrılması durumunda yalnızca tetiklenir.

Note: Call handlers currently depend on the Parity tracing API. Certain networks, such as BNB chain and Arbitrum, does not support this API. If a subgraph indexing one of these networks contain one or more call handlers, it will not start syncing. Subgraph developers should instead use event handlers. These are far more performant than call handlers, and are supported on every evm network.

Bir Çağrı İşleyici Tanımlama

Bu bölüme bağlantı

To define a call handler in your manifest, simply add a callHandlers array under the data source you would like to subscribe to.

dataSources:
- kind: ethereum/contract
name: Gravity
network: mainnet
source:
address: '0x731a10897d267e19b34503ad902d0a29173ba4b1'
abi: Gravity
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
entities:
- Gravatar
- Transaction
abis:
- name: Gravity
file: ./abis/Gravity.json
callHandlers:
- function: createGravatar(string,string)
handler: handleCreateGravatar

The function is the normalized function signature to filter calls by. The handler property is the name of the function in your mapping you would like to execute when the target function is called in the data source contract.

Eşleştirme fonksiyonu

Bu bölüme bağlantı

Each call handler takes a single parameter that has a type corresponding to the name of the called function. In the example subgraph above, the mapping contains a handler for when the createGravatar function is called and receives a CreateGravatarCall parameter as an argument:

import { CreateGravatarCall } from '../generated/Gravity/Gravity'
import { Transaction } from '../generated/schema'
export function handleCreateGravatar(call: CreateGravatarCall): void {
let id = call.transaction.hash
let transaction = new Transaction(id)
transaction.displayName = call.inputs._displayName
transaction.imageUrl = call.inputs._imageUrl
transaction.save()
}

The handleCreateGravatar function takes a new CreateGravatarCall which is a subclass of ethereum.Call, provided by @graphprotocol/graph-ts, that includes the typed inputs and outputs of the call. The CreateGravatarCall type is generated for you when you run graph codegen.

Blok İşleyicileri

Bu bölüme bağlantı

Bir subgraph, sözleşme olaylarına veya işlev çağrılarına abone olmanın yanı sıra, zincire yeni bloklar eklendikçe verilerini güncellemek isteyebilir. Bu işlemi gerçekleştirmek için a subgraph, her blok sonrasında veya önceden tanımlanmış bir filtreye uygun bloklardan sonra bir işlev çalıştırabilir.

Desteklenen Filtreler

Bu bölüme bağlantı

Çağrı Filtresi

Bu bölüme bağlantı
filter:
kind: call

The defined handler will be called once for every block which contains a call to the contract (data source) the handler is defined under.

Note: The call filter currently depend on the Parity tracing API. Certain networks, such as BNB chain and Arbitrum, does not support this API. If a subgraph indexing one of these networks contain one or more block handlers with a call filter, it will not start syncing.

Bir blok işleyicisi için filtre olmaması, işleyicinin her blok için çağrılacağı anlamına gelir. Bir veri kaynağı, her filtre türü için yalnızca bir blok işleyicisi içerebilir.

dataSources:
- kind: ethereum/contract
name: Gravity
network: dev
source:
address: '0x731a10897d267e19b34503ad902d0a29173ba4b1'
abi: Gravity
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
entities:
- Gravatar
- Transaction
abis:
- name: Gravity
file: ./abis/Gravity.json
blockHandlers:
- handler: handleBlock
- handler: handleBlockWithCallToContract
filter:
kind: call

Polling Filtresi

Bu bölüme bağlantı

Requires specVersion >= 0.0.8

Note: Polling filters are only available on dataSources of kind: ethereum.

blockHandlers:
- handler: handleBlock
filter:
kind: polling
every: 10

The defined handler will be called once for every n blocks, where n is the value provided in the every field. This configuration allows the subgraph to perform specific operations at regular block intervals.

Once Filtresi

Bu bölüme bağlantı

Requires specVersion >= 0.0.8

Note: Once filters are only available on dataSources of kind: ethereum.

blockHandlers:
- handler: handleOnce
filter:
kind: once

Once filtresi ile tanımlanan işleyici, diğer tüm işleyiciler çalışmadan önce yalnızca bir kez çağrılacaktır. Bu yapılandırma, subgraph'ın işleyiciyi indekslemenin başlangıcında belirli görevleri yerine getirmesine olanak sağlayan bir başlatma işleyicisi olarak kullanmasına yarar.

export function handleOnce(block: ethereum.Block): void {
let data = new InitialData(Bytes.fromUTF8('initial'))
data.data = 'Setup data here'
data.save()
}

Eşleştirme fonksiyonu

Bu bölüme bağlantı

The mapping function will receive an ethereum.Block as its only argument. Like mapping functions for events, this function can access existing subgraph entities in the store, call smart contracts and create or update entities.

import { ethereum } from '@graphprotocol/graph-ts'
export function handleBlock(block: ethereum.Block): void {
let id = block.hash
let entity = new Block(id)
entity.save()
}

Anonim Olaylar

Bu bölüme bağlantı

Solidity'de anonim olayları işlemek gerekiyorsa, örnekte olduğu gibi, olayın topic 0'ını sağlayarak bunu başarabilirsiniz:

eventHandlers:
- event: LogNote(bytes4,address,bytes32,bytes32,uint256,bytes)
topic0: '0x644843f351d3fba4abcd60109eaff9f54bac8fb8ccf0bab941009c21df21cf31'
handler: handleGive

An event will only be triggered when both the signature and topic 0 match. By default, topic0 is equal to the hash of the event signature.

Olay İşleyicilerinde İşlem Makbuzları

Bu bölüme bağlantı

Starting from specVersion 0.0.5 and apiVersion 0.0.7, event handlers can have access to the receipt for the transaction which emitted them.

To do so, event handlers must be declared in the subgraph manifest with the new receipt: true key, which is optional and defaults to false.

eventHandlers:
- event: NewGravatar(uint256,address,string,string)
handler: handleNewGravatar
receipt: true

Inside the handler function, the receipt can be accessed in the Event.receipt field. When the receipt key is set to false or omitted in the manifest, a null value will be returned instead.

İşleyicilerin Tetiklenme Sırası

Bu bölüme bağlantı

Bir bloktaki veri kaynağı için tetikleyiciler şu işlemlerle sıralanır:

  1. Olay ve çağrı tetikleyicileri, öncelikle bloktaki işlem indeksine göre sıralanır.
  2. Aynı işlemdeki olay ve çağrı tetikleyicileri, bir kurala göre sıralanır: önce olay tetikleyicileri, ardından çağrı tetikleyicileri olmak üzere her tür manifest'te tanımlandıkları sıraya göre sıralanır.
  3. Blok tetikleyicileri, olay ve çağrı tetikleyicilerinden sonra manifest'te tanımlandıkları sırada göre çalıştırılır.

Bu sıralama kuralları değişebilir.

Note: When new dynamic data source are created, the handlers defined for dynamic data sources will only start processing after all existing data source handlers are processed, and will repeat in the same sequence whenever triggered.

Veri Kaynağı Şablonları

Bu bölüme bağlantı

EVM uyumlu akıllı sözleşmelerde yaygın bir model, kayıt (registry) veya fabrika (factory) sözleşmelerinin kullanılmasıdır. Böylece ana sözleşme, kendi durumuna ve olaylarına sahip istenilen sayıda diğer sözleşmeyi oluşturur, yönetir veya bunlara referans verir.

The addresses of these sub-contracts may or may not be known upfront and many of these contracts may be created and/or added over time. This is why, in such cases, defining a single data source or a fixed number of data sources is impossible and a more dynamic approach is needed: data source templates.

Ana Sözleşme için Veri Kaynağı

Bu bölüme bağlantı

First, you define a regular data source for the main contract. The snippet below shows a simplified example data source for the Uniswap exchange factory contract. Note the NewExchange(address,address) event handler. This is emitted when a new exchange contract is created on-chain by the factory contract.

dataSources:
- kind: ethereum/contract
name: Factory
network: mainnet
source:
address: '0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95'
abi: Factory
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
file: ./src/mappings/factory.ts
entities:
- Directory
abis:
- name: Factory
file: ./abis/factory.json
eventHandlers:
- event: NewExchange(address,address)
handler: handleNewExchange

Dinamik Olarak Oluşturulan Sözleşmeler için Veri Kaynağı Şablonları

Bu bölüme bağlantı

Then, you add data source templates to the manifest. These are identical to regular data sources, except that they lack a pre-defined contract address under source. Typically, you would define one template for each type of sub-contract managed or referenced by the parent contract.

dataSources:
- kind: ethereum/contract
name: Factory
# ... other source fields for the main contract ...
templates:
- name: Exchange
kind: ethereum/contract
network: mainnet
source:
abi: Exchange
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
file: ./src/mappings/exchange.ts
entities:
- Exchange
abis:
- name: Exchange
file: ./abis/exchange.json
eventHandlers:
- event: TokenPurchase(address,uint256,uint256)
handler: handleTokenPurchase
- event: EthPurchase(address,uint256,uint256)
handler: handleEthPurchase
- event: AddLiquidity(address,uint256,uint256)
handler: handleAddLiquidity
- event: RemoveLiquidity(address,uint256,uint256)
handler: handleRemoveLiquidity

Bir Veri Kaynağı Şablonunun Örneklenmesi

Bu bölüme bağlantı

In the final step, you update your main contract mapping to create a dynamic data source instance from one of the templates. In this example, you would change the main contract mapping to import the Exchange template and call the Exchange.create(address) method on it to start indexing the new exchange contract.

import { Exchange } from '../generated/templates'
export function handleNewExchange(event: NewExchange): void {
// Borsayı indekslemeye başlayın; "event.params.exchange"
// yeni borsa sözleşmesinin adresi
Exchange.create(event.params.exchange)
}

Note: A new data source will only process the calls and events for the block in which it was created and all following blocks, but will not process historical data, i.e., data that is contained in prior blocks.

Eğer önceki bloklar, yeni veri kaynağı için ilgili veri içeriyorsa, o veriyi indekslemek için sözleşmenin mevcut durumunu okuyarak ve yeni veri kaynağı oluşturulurken o zaman dilimindeki durumu temsil eden varlıklar oluşturarak yapmak en iyisidir.

Veri Kaynağı Bağlamı

Bu bölüme bağlantı

Data source contexts allow passing extra configuration when instantiating a template. In our example, let's say exchanges are associated with a particular trading pair, which is included in the NewExchange event. That information can be passed into the instantiated data source, like so:

import { Exchange } from '../generated/templates'
export function handleNewExchange(event: NewExchange): void {
let context = new DataSourceContext()
context.setString('tradingPair', event.params.tradingPair)
Exchange.createWithContext(event.params.exchange, context)
}

Inside a mapping of the Exchange template, the context can then be accessed:

import { dataSource } from '@graphprotocol/graph-ts'
let context = dataSource.context()
let tradingPair = context.getString('tradingPair')

There are setters and getters like setString and getString for all value types.

Başlangıç Blokları

Bu bölüme bağlantı

The startBlock is an optional setting that allows you to define from which block in the chain the data source will start indexing. Setting the start block allows the data source to skip potentially millions of blocks that are irrelevant. Typically, a subgraph developer will set startBlock to the block in which the smart contract of the data source was created.

dataSources:
- kind: ethereum/contract
name: ExampleSource
network: mainnet
source:
address: '0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95'
abi: ExampleContract
startBlock: 6627917
mapping:
kind: ethereum/events
apiVersion: 0.0.6
language: wasm/assemblyscript
file: ./src/mappings/factory.ts
entities:
- User
abis:
- name: ExampleContract
file: ./abis/ExampleContract.json
eventHandlers:
- event: NewEvent(address,address)
handler: handleNewEvent

Note: The contract creation block can be quickly looked up on Etherscan:

  1. Arama çubuğuna adresini girerek sözleşmeyi arayın.
  2. Click on the creation transaction hash in the Contract Creator section.
  3. İşlem detayları sayfasını yükleyin ve bu sözleşme için başlangıç bloğunu bulacaksınız.

Endeksleyici İpuçları

Bu bölüme bağlantı

The indexerHints setting in a subgraph's manifest provides directives for indexers on processing and managing a subgraph. It influences operational decisions across data handling, indexing strategies, and optimizations. Presently, it features the prune option for managing historical data retention or pruning.

This feature is available from specVersion: 1.0.0

indexerHints.prune: Defines the retention of historical block data for a subgraph. Options include:

  1. "never": No pruning of historical data; retains the entire history.
  2. "auto": Retains the minimum necessary history as set by the indexer, optimizing query performance.
  3. Belirli bir sayı: Verilen sayıyı saklanacak tarihsel blok sayısı olarak ayarlar.
indexerHints:
prune: auto

Subgraph'lerde "geçmiş" terimi, bu bağlamda, değiştirilebilir varlıkların eski durumlarına dair verilerin saklanmasıyla ilgilidir.

Verilen bir bloktaki geçmiş, şu durumlar için gereklidir:

  • Time travel queries, which enable querying the past states of these entities at specific blocks throughout the subgraph's history
  • Using the subgraph as a graft base in another subgraph, at that block
  • Subgraph'i verilen bloka geri sarmak

Eğer verilen bloktaki tarihsel veri budanmışsa yukarıdaki özellikler kullanılamayacaktır.

Using "auto" is generally recommended as it maximizes query performance and is sufficient for most users who do not require access to extensive historical data.

For subgraphs leveraging time travel queries, it's advisable to either set a specific number of blocks for historical data retention or use prune: never to keep all historical entity states. Below are examples of how to configure both options in your subgraph's settings:

Belirli bir miktarda tarihsel veri saklamak için:

indexerHints:
prune: 1000 # Replace 1000 with the desired number of blocks to retain

Varlık durumlarının tam geçmişini korumak için:

indexerHints:
prune: never
Sayfayı Düzenle

Önceki
Graph CLI'ı Yükleyin
Sonraki
The Graph QL Schema
Sayfayı Düzenle