Graphgen aims to facilitate subgraph development by abstracting away simple but common subgraph writing patterns
and automating the set up of peripherals.
Designed by Protean Labs
Contributing Guidelines
Β·
Submit an Issue
Β·
Blog
Supported by The Graph Foundation through a wave two ecosystem grant
Graphgen is released on the npm.js registry and Github package registry.
You can install Graphgen globally with:
npm i -g @protean-labs/graphgen
Basic usage is to call on an already annotated .sol contract file. If installed globally, use npx to call the executable if your $PATH is not already set. This will generate a subgraph/
folder, containing the output files, where you called the command.
npx graphgen [CONTRACT_FILE].sol
Graphgen can also be installed locally, along with your solidity contract files. You can then use npm's npx
within you contract's folder the same way it's used just above.
NAME
graphgen - Generate a subgraph from annotated solidity interfaces
SYNOPSIS
graphgen [OPTION]... SOURCE
ARGUMENTS
SOURCE (required)
Solidity interface file or directory containing multiple interface
files annotated with graphgen tags
OPTIONS
-d VAL, --description=VAL (absent=PLACEHOLDER)
Subgraph description
--help[=FMT] (default=auto)
Show this help in format FMT. The value FMT must be one of `auto',
`pager', `groff' or `plain'. With `auto', the format is `pager` or
`plain' whenever the TERM env var is `dumb' or undefined.
-n VAL, --name=VAL (absent=PLACEHOLDER)
The name of the subgraph
-o VAL, --output-dir=VAL (absent=subgraph)
The name of the output directory to which the subgraph will be
generated
-u VAL, --user=VAL (absent=PLACEHOLDER)
The Graph Github user
-v, --verbose
Verbose output
GraphGen takes as inputs solidity files containing annotated interfaces and outputs a working subgraph. The annotations indicate to GraphGen which contracts should be indexed (as dataSources
or templates
), which events and calls to listen to and what to do when one happens, etc.
Given a solidity file containing annotated interfaces, or a directory containing multiple such files, the following command is used to generate the subgraph:
npx graphgen -o OUTPUT_DIR FILE_OR_DIR
. Important: In its current state, GraphGen only works with solidity interface definition and not contract definitions. Support for annotations in contract definitions is in the works.
Provided the annotations and interfaces are valid, GraphGen will generate a subgraph (located in in OUTPUT_DIR/
) with the following files:
subgraph.yaml
: Subgraph manifestpackage.json
: Package.jsonschema.graphql
: Graphql schemasrc/mappings/X.ts
: Typescript mappings for each indexed contractsX
src/utils.ts
: Utility functions used in generated mappingsabis/X.json
: Solidity ABIs for each indexed subgraphX
IMPORTANT: GraphGen does not include any functionality from the graph-cli
. One must therefore run npm run codegen
and npm run build
after generating the source files with GraphGen.
CAVEAT: GraphGen is still in active development and should only be used in production with caution. Moreover, the generated subgraphs might not always be optimal from an indexing point of view.
GraphGen supports three kinds of annotations, each with their specific parameters:
@gg:source
: Defines adataSource
ortemplate
(depending on parameters). Must precede an interface definition.@gg:field
: Defines an entity field with an optional default value. Must precede aview
orpure
function definition.@gg:handler
: Defines an event (or call) handler, as well as the logic to be executed when the handler is triggered. Must precede an event (or call) definition.
IMPORTANT: All GraphGen annotations must directly precede their associated code block and be written inside a comment block delimited by /*
and */
.
name
:STRING
- (optional) Name used for the entity type representing this interface and all other references to it. Defaults to interface name.instances
:[INSTANCE]
- (optional) A list of instances. Defaults to empty list, indicating that this interface maps to a subgraph template.
Where INSTANCE
has two parameters:
address
:STRING
- The address of the contract implementing the interface.startBlock
:INTEGER
- The block at which to start the indexing of this contract.
Template:
/* @gg:source
name: MySuperContract
*/
interface MyContract {
...
}
DataSource:
/* @gg:source
instances:
- address: '0xaa7fb1c8ce6f18d4fd4aabb61a2193d4d441c54f'
startBlock: 8335916
*/
interface MyContract {
...
}
name
:STRING
- (optional) Name used as the name of the entity field. Defaults to the name of the function.default
:STRING
- (optional) Default value for the field, used in case of errors. Defaults to predefined values for each type (e.g.: 0 for BigInt, "" for String).
/* @gg:source
name: MySuperContract
*/
interface MyContract {
/* @gg:field */
function totalSupply() external view returns (uint);
/* @gg:field
name: speedOfLight
*/
function c() external pure returns (uint);
}
name
:STRING
- (optional) Name used for the entity type representing this event (or call) and all other references to it. Defaults to event (or call) name.actions
:[STRING]
- List of handler actions, see below for more information.
Actions are commands (encoded as simple strings) that tell GraphGen what kind of logic should be executed when a certain event (or call) handler is triggered. GraphGen currently supports four distinct actions:
StoreEvent
: When the handler is associated with an event, this action command tells GraphGen to: 1) Create a new entity type for the event; 2) Store each of those events; and 3) Add edges between the emitter contract entity and the event entities.StoreCall
: Same asStoreEvent
, but for storing function calls. (Note:StoreEvent
andStoreCall
might get merged into a single action command in the future).UpdateField X
: This action command tells GraphGen that whenever the handler is triggered, the fieldX
(of the emitter contract entity) should be updated. The fieldX
must be defined using a@gg:field
annotation on the same interface.NewEntity X of Y
: This action command tells GraphGen that whenever the handler is triggered, a new template contract entity of typeX
should be created, using the fieldY
of the event (or call) as the address and id of this new entity.X
must be defined using a@gg:source
annotation.
/* @gg:source
name: MySuperContract
*/
interface MyContract {
/* @gg:field */
function totalSupply() external view returns (uint);
/* @gg:handler
actions:
- StoreEvent
- UpdateField totalSupply
*/
event Mint(uint amount);
/* @gg:handler
name: AdminChange
actions:
- StoreCall
*/
function changeAdmin(address newAdmin) external returns (bool);
/* @gg:handler
actions:
- NewEntity ERC20 from token
*/
event NewToken(address indexed token);
}
You can find multiple examples & use cases under the example/
folder. See example/README.md
for more details.
Graphgen uses parser generator technologies in order to leverage the information that resides in solidity interface files. It is written with the OCaml/ReasonML toolchain and compiled to native OCaml code.
We at Protean Labs focus on building various pieces of infrastructure and developer tooling around the Web3 ecosystem. You can reach out to us through our multiple social accounts.