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)

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.

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