Project package

Each DipDup project consists of a YAML config and a Python package of a specific structure. It could be placed anywhere, but needs to be importable. The package name is defined in the config file.

To generate all necessary directories and files according to config run the init command. You should run it every time you significantly change the config file.

The structure of the resulting package is the following:

PathDescription
📁 abiContract ABIs used to generate typeclasses
📁 configsEnvironment-specific configs to merge with the root one
📁 deployDockerfiles, compose files, and default env variables for each environment
📁 graphqlCustom GraphQL queries to expose with Hasura engine
📁 handlersUser-defined callbacks to process contract data
📁 hasuraArbitrary Hasura metadata to apply during configuration
📁 hooksUser-defined callbacks to run manually or by schedule
📁 modelsDipDup ORM models to store data in the database
📁 sqlSQL scripts and queries to run manually or on specific events
📁 typesAutomatically generated Pydantic dataclasses for contract types
dipdup.yamlRoot DipDup config; can be expanded with env-specific files
dipdup_indexer -> .A little helper, symlink to let you import the package from the root directory.
pyproject.tomlPython package metadata (introduced in PEP 518; see details)
MakefileMakefile with shortcuts for common commands (run make for help)
README.mdProject README with a brief description and usage instructions

Also, there are .dockerignore, .gitignore files and py.typed marker (PEP 561). Usually, you won't need to modify them.

ABIs and typeclasses

DipDup uses contract type information to generate Pydantic models to work with strictly typed data. We call these models typeclasses. Modules in the types directory are generated automatically from contract ABIs and JSONSchemas during init. You can modify them manually, but usually won't need to. Under the hood, the process is roughly the following:

  • Contract ABIs are fetched from public sources or provided by the user.
  • DipDup converts these ABIs to intermediate JSONSchemas.
  • JSONSchemas converted to Pydantic models with datamodel-code-generator.

This approach allows working with complex contract types with nested structures and polymorphic variants.

Config snippets

config/ directory contains environment-specific config snippets. They don't contain package/spec_version fields and can be used to extend/override the root config. See Merging config files for details.

Replay file

config/replay.yaml is a special file that contains options used during generation a new project. You can use it to create a new project with the same settings, or modify it to change chosen options.

Dev tools

The Makefile contains shortcuts for all commands you might need during development! Run make without arguments to see the list of available commands:


  🚧 DipDup developer tools

help:            Show this help (default)
all:             Run an entire CI pipeline

install:         Install dependencies
update:          Update dependencies
format:          Format with all tools
lint:            Lint with all tools

black:           Format with black
ruff:            Lint with ruff
mypy:            Lint with mypy

image:           Build Docker image
up:              Start Compose stack
down:            Stop Compose stack

See the file contents for details. Feel free to modify it to fit your workflow!

Deploy recipes

The deploy directory contains:

  • Dockerfile, a recipe to build a Docker image with your project. Usually, you won't need to modify it. See comments inside for details.
  • Compose files to run your project locally or in the cloud.
  • Default env variables for each environment. See Environment variables for details.

Nested packages

Callbacks can be grouped into packages to organize the project structure. Add one or multiple dots to the callback name to define nested packages:

dipdup.yaml
package: dipdup_indexer
hooks:
  backup.restore:
    callback: backup.on_restore

After running the init command, you'll get the following directory tree (shortened for brevity)

dipdup_indexer
├── hooks
│   ├── backup
│   │   └── on_restore.py
└── sql
    └── backup
        └── on_restore

Handler callbacks can be grouped the same way. Note, that the callback name still needs to be a valid Python module path: only lowercase letters, underscores, and dots.

Help and tips -> Join our Discord
Ideas or suggestions -> Issue Tracker
GraphQL IDE -> Open Playground