Web3 React App Template utilizing TheGraph
Set ETHEREUM_REORG_THRESHOLD=1
and ETHEREUM_ANCESTOR_COUNT=1
in the thegraph service, it will only query for the latest block and its transaction receipts on startup
npx create-react-app <your_application_name> --template cra-subgraph
npm install create-subgraph-appp
-- đź”— npm/create-subgraph-app
Import the store API and other features from this library in your mappings. A few examples:
import { store, crypto } from '@graphprotocol/graph-ts'
// This is just an example event type generated by `graph-cli`
// from an Ethereum smart contract ABI
import { NameRegistered } from './types/abis/SomeContract'
// This is an example of an entity type generated from a
// subgraph's GraphQL schema
import { Domain } from './types/schema'
function handleNameRegistered(event: NameRegistered) {
// Example use of a crypto function
let id = crypto.keccak256(name).toHexString()
// Example use of the generated `Entry` class
let domain = new Domain()
domain.name = name
domain.owner = event.params.owner
domain.timeRegistered = event.block.timestamp
// Example use of the store API
store.set('Name', id, entity)
}
For each Entity
type that you define in your schema, an entity
and entities
field will be generated on the top-level Query
type. Note that query
does not need to be included at the top of the graphql
query when using The Graph.
Query for a single Token
entity defined in your schema:
{
token(id: "1") {
id
owner
}
}
When querying for a single entity, the id
field is required.
Collection query for Token
entities:
{
tokens(first: 100) {
id
owner
}
}
When querying a collection, the orderBy
parameter may be used to sort by a specific attribute. Additionally, the orderDirection
can be used to specify the sort direction, asc
for ascending or desc
for descending.
{
tokens(first: 100, orderBy: price, orderDirection: asc) {
id
owner
}
}
When querying a collection, the first
parameter must be used to paginate from the beginning of the collection.
To query for groups of entities in the middle of a collection, the skip
parameter may be used to skip a specified number of entities starting at the beginning of the collection.
Query 10 Token
entities, offset by 10:
{
tokens(first: 10, skip: 10) {
id
owner
}
}
You can use the where
parameter in your queries to filter for different properties.
Query challenges with failed
outcome:
{
challenges(first: 100, where: {outcome: "failed"}) {
challenger
outcome
application(first: 100) {
id
}
}
}
You can use suffixes like _gt
, _lte
for value comparison:
{
applications(first: 100, where: {deposit_gt:"10000000000"}) {
id
whitelisted
deposit
}
}
Full list of parameter suffixes:
_not
_gt
_lt
_gte
_lte
_in
_not_in
_contains
_not_contains
_starts_with
_ends_with
_not_starts_with
_not_ends_with
Please note that some suffixes are only supported for specific types. For example, Boolean
only supports _not
, _in
, and _not_in
.
Graph Protocol subscriptions are GraphQL spec-compliant subscriptions. Unlike query operations, GraphQL subscriptions may only have a single top-level field at the root level for each subscription operation.
The root Subscription type for subscription operations mimics the root Query type used for query operations to minimize the cognitive overhead for writing subscriptions.
Query the first 100 Token
entities along with their id
and owner
attributes:
query {
tokens(first: 100) {
id
owner
}
}
Subscribe to all Token
entity changes and fetch the values of the id
and owner
attributes on the updated entity:
subscription {
tokens(first: 100) {
id
owner
}
}
The schema of your data source--that is, the entity types, values, and relationships that are available to query--are defined through the GraphQL Interface Definition Langauge (IDL).
GraphQL requests consist of three basic operations: query
, subscription
, and mutation
. Each of these has a corresponding root level Query
, Subscription
, and Mutation
type in the schema of a GraphQL endpoint.
Note: Our API does not expose mutations because developers are expected to issue transactions directly against the underlying blockchain from their applications.
It is typical for developers to define their own root Query
and Subscription
types when building a GraphQL API server, but with The Graph, we generate these top-level types based on the entities that you define in your schema as well as several other types for exploring blockchain data, which we describe in depth in the Query API.
All GraphQL types with @entity
directives in your schema will be treated as entities and must have an ID
field.
Note: Currently, all types in your schema must have an
@entity
directive. In the future, we will treat types without an@entity
directive as value objects, but this is not yet supported.
Define a Token
entity:
type Token @entity {
# The unique ID of this entity
id: ID!
name: String!
symbol: String!
decimals: Int!
}
All the scalars defined in the GraphQL spec are supported: Int
, Float
, String
, Boolean
, and ID
.
There is a Bytes
scalar for variable-length byte arrays.
The GraphQL spec defines Int
and Float
to have sizes of 32 bytes.
This API additionally includes a BigInt
number type to represent arbitrarily large integer numbers.
You can also create enums
within a schema. Enums have the following syntax:
enum TokenStatus {
OriginalOwner,
SecondOwner,
ThirdOwner,
}
To set a store value with an enum, use the name of the enum value as a string. In the example above, you can set the TokenStatus
to the second owner with SecondOwner
.
More detail on writing enums can be found in the GraphQL documentation.
An entity may have a relationship to one or more other entities in your schema. These relationships may be traversed in your queries and subscriptions.
Relationships in The Graph are unidirectional. Despite this, relationships may be traversed in either direction by defining reverse lookups on an entity.
Relationships are defined on entities just like any other scalar type except that the type specified is that of another entity.
Define a Transaction
entity type with an optional one-to-one relationship with a TransactionReceipt
entity type:
type Transaction @entity {
id: ID!
transactionReceipt: TransactionReceipt
}
type TransactionReceipt @entity {
id: ID!
transaction: Transaction
}
Define a Token
entity type with a required one-to-many relationship with a TokenBalance
entity type:
type Token @entity {
id: ID!
tokenBalances: [TokenBalance!]!
}
type TokenBalance @entity {
id: ID!
amount: Int!
}
Defining reverse lookups can be defined on an entity through the @derivedFrom
field. This creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API. Rather, it is derived from the relationship defined on the other entity.
The type of an @derivedFrom
field must be a collection since multiple entities may specify relationships to a single entity.
Define a reverse lookup from a User
entity type to an Organization
entity type:
type Organization @entity {
id: ID!
name: String!
members: [User]!
}
type User @entity {
id: ID!
name: String!
organizations: [Organization!] @derivedFrom(field: "members")
}
Apache-2.0 or MIT