diff --git a/database/README.md b/database/README.md index 1e2e005818..df3c1a6db6 100644 --- a/database/README.md +++ b/database/README.md @@ -518,7 +518,7 @@ Indexes: - jit\_user\_order\_creation\_timestamp: btree(`owner`, `creation_timestamp` DESC) - jit\_event\_id: btree(`block_number`, `log_index`) -The `pool-indexer` service uses its own per-network database, not these shared DBs. Its tables (`pool_indexer_checkpoints`, `uniswap_v3_pools`, `uniswap_v3_pool_states`, `uniswap_v3_ticks`) and migrations live in [`sql-pool-indexer/`](sql-pool-indexer/). +The `pool-indexer` service uses its own per-network database, not these shared DBs. Its tables (`pool_indexer_checkpoints`, `uniswap_v3_pools`, `uniswap_v3_pool_states`, `uniswap_v3_ticks`, `balancer_v2_pools`, `balancer_v2_pool_tokens`) and migrations live in [`sql-pool-indexer/`](sql-pool-indexer/). ### Enums diff --git a/database/sql-pool-indexer/README.md b/database/sql-pool-indexer/README.md index fec9aa2f60..1af88317f2 100644 --- a/database/sql-pool-indexer/README.md +++ b/database/sql-pool-indexer/README.md @@ -18,11 +18,13 @@ applied migrations) so it's cancelled there by `../sql/V111`. ## Schema The tables below live in the indexer's own per-network database (e.g. -`ink_pool_indexer`), created by the migrations in this directory. +`ink_pool_indexer`), created by the migrations in this directory. `V110` defines +the Uniswap V3 discovery schema and `V111` the Balancer V2 one; a pool-indexer +process indexes whichever protocol(s) its network config enables. ### pool\_indexer\_checkpoints -Highest finalized block processed per `contract_address` by `pool-indexer`. `contract_address` is the factory address. The indexer runs one process per network against its own DB, so there's no `chain_id` column. +Highest finalized block processed per `contract_address` (the factory address) by `pool-indexer`. Shared by the Uniswap V3 and Balancer V2 indexers: their factory addresses are distinct contracts so rows never collide, and each protocol's queries filter to its own configured factories. One process per network against its own DB, so there's no `chain_id` column. Column | Type | Nullable | Details --------------------|--------|----------|-------- @@ -97,3 +99,34 @@ Quoters consult these to predict liquidity changes at tick crossings during swap Indexes: - PRIMARY KEY: btree (`pool_address`, `tick_idx`) + +### balancer\_v2\_pools + +One row per pool, discovered from each factory's `PoolCreated` event. `pool_type` is derived from the creating factory (weighted V0 and V3-plus both map to `Weighted`) and stored as the string the API serves. Referenced by `balancer_v2_pool_tokens`. Discovery metadata only — dynamic state (balances, amplification, LBP weights, scaling factors, swap fee) stays on-chain and is fetched by the driver at query time. + + Column | Type | Nullable | Details +----------------|--------|----------|-------- + pool\_id | bytea | not null | 32-byte Balancer poolId + address | bytea | not null | Pool address (poolId's first 20 bytes) + factory | bytea | not null | Factory that emitted `PoolCreated` + pool\_type | text | not null | `Weighted`, `Stable`, `ComposableStable`, or `LiquidityBootstrapping` (`CHECK`) + created\_block | bigint | not null | Block the pool was created on-chain + +Indexes: +- PRIMARY KEY: btree (`pool_id`) + +### balancer\_v2\_pool\_tokens + +Tokens per pool in `Vault.getPoolTokens` order. `decimals` is backfilled; `weight` is set only for weighted pools. FK → `balancer_v2_pools`. + + Column | Type | Nullable | Details +-----------|----------|----------|-------- + pool\_id | bytea | not null | FK → `balancer_v2_pools(pool_id)` + position | int | not null | Index in `getPoolTokens` order + token | bytea | not null | Token address + decimals | smallint | nullable | `NULL` = not yet fetched. `-1` = sentinel for "fetched but call failed" + weight | numeric | nullable | Bfp (1e18) normalized weight; weighted pools only, else `NULL` + +Indexes: +- PRIMARY KEY: btree (`pool_id`, `position`) +- Partial index on `(token)` with predicate `decimals IS NULL` to power the backfill scan. diff --git a/database/sql-pool-indexer/V111__balancer_v2.sql b/database/sql-pool-indexer/V111__balancer_v2.sql new file mode 100644 index 0000000000..98ce9a09c1 --- /dev/null +++ b/database/sql-pool-indexer/V111__balancer_v2.sql @@ -0,0 +1,36 @@ +-- Balancer V2 discovery tables, applied on top of V110's uniswap_v3_* schema in +-- the pool-indexer's per-network DB. Checkpoints reuse `pool_indexer_checkpoints` +-- (keyed by factory address): Balancer and Uniswap V3 factory addresses are +-- distinct contracts, so both protocols share that table without collision. + +-- One row per registered pool, discovered from each factory's `PoolCreated` +-- event. `pool_type` is derived from which factory created the pool (no on-chain +-- classification); weighted V0 and V3-plus both map to `Weighted` (the variant +-- is recoverable from `factory`). Stored as the string the API serves, so +-- there's no int<->enum mapping at the boundary. +CREATE TABLE balancer_v2_pools ( + pool_id BYTEA NOT NULL, -- 32-byte Balancer poolId + address BYTEA NOT NULL, -- pool address (poolId's first 20 bytes) + factory BYTEA NOT NULL, + pool_type TEXT NOT NULL CHECK (pool_type IN ('Weighted', 'Stable', 'ComposableStable', 'LiquidityBootstrapping')), + created_block BIGINT NOT NULL, + PRIMARY KEY (pool_id) +); + +-- Tokens per pool, in `Vault.getPoolTokens` order (`position`). `decimals` is +-- nullable and filled in by the backfill task. `weight` is the Balancer Bfp +-- (1e18 fixed-point) normalized weight, set only for weighted pools; NULL for +-- stable/composable-stable/LBP (their weights are absent or fetched on-chain). +CREATE TABLE balancer_v2_pool_tokens ( + pool_id BYTEA NOT NULL, + position INT NOT NULL, + token BYTEA NOT NULL, + decimals SMALLINT, -- NULL = not yet fetched; -1 = fetched but call failed + weight NUMERIC, -- Bfp (1e18); weighted pools only, else NULL + PRIMARY KEY (pool_id, position), + FOREIGN KEY (pool_id) REFERENCES balancer_v2_pools(pool_id) +); + +-- Decimals backfill hot path. Partial on `IS NULL` so the index shrinks to +-- near-empty once most rows are populated (real value or the `-1` sentinel). +CREATE INDEX ON balancer_v2_pool_tokens (token) WHERE decimals IS NULL;