/ Docs

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:

šŸ“ 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)

There are also preconfigured .dockerignore and .gitignore files; py.typed marker. 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.

Currently, we use Pydantic v1, but plan to migrate to v2 very soon.

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:

package: dipdup_indexer
    callback: backup.on_restore

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

ā”œā”€ā”€ 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