Skip to content

indexer-db reads are not network-isolated — every query omits the network predicate the Supabase path applies #2513

Description

@dcccrypto

Summary

Every read in app/lib/indexer-db.ts queries the shared indexer Postgres without a network predicate, while the Supabase paths in the same routes filter on network. The two backends therefore disagree about network isolation: whichever one a deployment happens to use decides whether a devnet trade can appear in mainnet figures.

Raised out of review on #2512 (CodeRabbit flagged the missing predicate on the new queryTraderStatsAggregate). It is not specific to that function — I checked the rest of the module and none of them filter either, so fixing one in isolation would make trader stats network-isolated while candles, funding and trade history on the same database stayed cross-network.

Affected

app/lib/indexer-db.ts — no occurrence of network in any WHERE clause. The column exists; the module's own schema comment documents it:

 *   trades            — id, slab_address, trader, tx_signature, side, size,
 *                       price, fee, created_at (timestamptz), network, ...
 *   funding_history   — ... timestamp (timestamptz), network

Contrast the Supabase fallback in app/app/api/trader/[wallet]/stats/route.ts, which does:

.eq("network", getServerNetwork())

Impact

Bounded by deployment: it only matters where one Postgres instance holds rows for more than one network. If INDEXER_DATABASE_URL always points at a single-network database, this is latent rather than live — which is worth establishing before changing anything, because it decides whether this is a bug or a hardening.

Where it does bite, the symptom is quiet: devnet activity inflating mainnet trade counts, volume and "unique markets", with no error and no visible marker.

Prerequisite before fixing — please check this first

The two sides derive the network from different environment variables:

side source values
indexer writes getNetwork() (@percolatorct/shared, dist/db/queries.js) → process.env.NETWORK "mainnet" | "devnet"
launch reads getServerNetwork() (app/lib/supabase.ts) → process.env.NEXT_PUBLIC_DEFAULT_NETWORK "mainnet" | "devnet"

The vocabularies match, so a filter would compare like with like. But both default to devnet when their variable is unset, so a deployment running NETWORK=mainnet on the indexer with NEXT_PUBLIC_DEFAULT_NETWORK unset on launch would go from cross-network reads to zero rows for every wallet the moment a predicate is added.

Silently zeroing an endpoint is a worse failure than the one being fixed, so confirming both variables are set consistently in each environment should come before the code change.

Suggested fix

Once the env question is settled: thread getServerNetwork() through indexer-db.ts and add AND network = ${network} to each query, so both backends agree. Worth doing in one pass rather than per-function, so the module cannot end up half-isolated.

Not doing this in #2512

That PR is scoped to the 10k truncation in /api/trader/:wallet/stats, and its aggregate faithfully preserves the pre-existing (unfiltered) behaviour of the query it replaces. Fixing network isolation there alone would leave the module inconsistent and would carry the deployment risk above without anyone having checked it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions