Quick start
Get your selective indexer up & running in a few steps

Install Python SDK

1
pip install dipdup
Copied!

Write config file

Make a new folder and create a configuration file dipdup.yml inside with the following content:
1
spec_version: 1.1
2
package: demo_tzbtc
3
4
database:
5
kind: sqlite
6
path: demo_tzbtc.sqlite3
7
8
contracts:
9
tzbtc_mainnet:
10
address: KT1PWx2mnDueood7fEmfbBDKx1D9BAnnXitn
11
typename: tzbtc
12
13
datasources:
14
tzkt_mainnet:
15
kind: tzkt
16
url: https://api.tzkt.io
17
18
indexes:
19
tzbtc_holders_mainnet:
20
kind: operation
21
datasource: tzkt_mainnet
22
contracts:
23
- tzbtc_mainnet
24
handlers:
25
- callback: on_transfer
26
pattern:
27
- destination: tzbtc_mainnet
28
entrypoint: transfer
29
- callback: on_mint
30
pattern:
31
- destination: tzbtc_mainnet
32
entrypoint: mint
Copied!
We will index all the tzBTC transfers and mints and store indexed data in the models representing token holders.

Generate types

1
dipdup init
Copied!
This command will generate the following files:
1
demo_tzbtc/
2
├── models.py
3
├── handlers
4
│ ├── on_transfer.py
5
│ ├── on_mint.py
6
│ ├── on_configure.py
7
│ └── on_rollback.py
8
└── types
9
└── tzbtc
10
├── storage.py
11
└── parameter
12
└── transfer.py
13
└── mint.py
Copied!
Let's fill them one by one.

Define data models

Our schema will consist of a single model Holder having several fields:
    address — account address
    balance — in tzBTC
    volume — total transfer/mint amount bypassed
    tx_count — number of transfers/mints
    last_seen — time of the last transfer/mint
1
from tortoise import Model, fields
2
3
4
class Holder(Model):
5
address = fields.CharField(max_length=36, pk=True)
6
balance = fields.DecimalField(decimal_places=8, max_digits=20, default=0)
7
volume = fields.DecimalField(decimal_places=8, max_digits=20, default=0)
8
tx_count = fields.BigIntField(default=0)
9
last_seen = fields.DateTimeField(null=True)
Copied!

Implement handlers

Our task is to properly index all the balance updates, so we'll start with a helper method handling them.
on_balance_update.py
1
from decimal import Decimal
2
import demo_tzbtc.models as models
3
4
5
async def on_balance_update(
6
address: str,
7
balance_update: Decimal,
8
timestamp: str
9
) -> None:
10
holder, _ = await models.Holder.get_or_create(address=address)
11
holder.balance += balance_update
12
holder.turnover += abs(balance_update)
13
holder.tx_count += 1
14
holder.last_seen = timestamp
15
assert holder.balance >= 0, address
16
await holder.save()
Copied!
That was pretty straightforward👍🏻
Now we need to handle two contract methods that can alter token balances — transfer and mint (there's also burn, but for simplicity we'll omit that in this tutorial).
on_transfer.py
1
from typing import Optional
2
from decimal import Decimal
3
4
from dipdup.models import Transaction
5
from dipdup.context import HandlerContext
6
7
import demo_tzbtc.models as models
8
9
from demo_tzbtc.types.tzbtc.parameter.transfer import TransferParameter
10
from demo_tzbtc.types.tzbtc.storage import TzbtcStorage
11
from demo_tzbtc.handlers.on_balance_update import on_balance_update
12
13
14
async def on_transfer(
15
ctx: HandlerContext,
16
transfer: Transaction[TransferParameter, TzbtcStorage],
17
) -> None:
18
if transfer.parameter.from_ == transfer.parameter.to:
19
return # tzBTC specific
20
amount = Decimal(transfer.parameter.value) / (10 ** 8)
21
await on_balance_update(address=transfer.parameter.from_,
22
balance_update=-amount,
23
timestamp=transfer.data.timestamp)
24
await on_balance_update(address=transfer.parameter.to,
25
balance_update=amount,
26
timestamp=transfer.data.timestamp)
Copied!
on_mint.py
1
from typing import Optional
2
from decimal import Decimal
3
4
from dipdup.models import Transaction
5
from dipdup.context import HandlerContext
6
7
import demo_tzbtc.models as models
8
9
from demo_tzbtc.types.tzbtc.parameter.mint import MintParameter
10
from demo_tzbtc.types.tzbtc.storage import TzbtcStorage
11
from demo_tzbtc.handlers.on_balance_update import on_balance_update
12
13
14
async def on_mint(
15
ctx: HandlerContext,
16
mint: Transaction[MintParameter, TzbtcStorage],
17
) -> None:
18
amount = Decimal(mint.parameter.value) / (10 ** 8)
19
await on_balance_update(address=mint.parameter.to,
20
balance_update=amount,
21
timestamp=mint.data.timestamp)
22
Copied!
And that's all! We can run the indexer now.

Run your indexer

1
dipdup run
Copied!
DipDup will fetch all the historical data first, and then switch to real-time updates. You application data has been successfully indexed!
Last modified 2mo ago