Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions indexer/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
DATABASE_URL=postgresql://trustlink:trustlink@localhost:5432/trustlink
CONTRACT_ID=YOUR_CONTRACT_ID_HERE
# Soroban RPC endpoint
RPC_URL=https://soroban-testnet.stellar.org
GENESIS_LEDGER=0
PORT=3000

# ── Single contract (original behaviour) ──────────────────────────────────────
# CONTRACT_ID=CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCN8

# ── Multiple contracts (new) — comma-separated, takes precedence over CONTRACT_ID
CONTRACT_IDS=CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCN8,CYYY...

# PostgreSQL connection
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/trustlink

# Redis — used for PubSub (horizontal scaling) and optional query caching
REDIS_URL=redis://localhost:6379

# Port for the GraphQL / metrics HTTP server
PORT=4000

# Ledger to start from when no checkpoint exists (0 = chain genesis)
# GENESIS_LEDGER=0
50 changes: 50 additions & 0 deletions indexer/prisma/migrations/0003_multi_contract/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
-- Migration: 0003_multi_contract
-- Extend schema to support multiple contract IDs.
--
-- All attestation and proposal records are now keyed by contractId so a single
-- indexer deployment can track several TrustLink instances simultaneously.

-- 1. Add contractId column with a temporary default so existing rows get a
-- value. The default is cleared after backfill to enforce NOT NULL.
ALTER TABLE "Attestation" ADD COLUMN "contractId" TEXT;

-- Backfill existing rows using the CONTRACT_ID env var that was hard-coded
-- before this migration. Operators must set LEGACY_CONTRACT_ID to the value
-- that was in use before upgrading. If unset we fall back to an empty string
-- so the migration succeeds and operators can UPDATE manually.
UPDATE "Attestation"
SET "contractId" = COALESCE(current_setting('app.legacy_contract_id', true), '');

-- Make the column required once backfilled.
ALTER TABLE "Attestation" ALTER COLUMN "contractId" SET NOT NULL;

ALTER TABLE "MultisigProposal" ADD COLUMN "contractId" TEXT;

UPDATE "MultisigProposal"
SET "contractId" = COALESCE(current_setting('app.legacy_contract_id', true), '');

ALTER TABLE "MultisigProposal" ALTER COLUMN "contractId" SET NOT NULL;

-- 2. Drop the old singleton Checkpoint row (id=1) and replace with a per-
-- contract table keyed by contractId.
DROP TABLE IF EXISTS "Checkpoint";

CREATE TABLE "Checkpoint" (
"contractId" TEXT NOT NULL,
"ledger" INTEGER NOT NULL,
CONSTRAINT "Checkpoint_pkey" PRIMARY KEY ("contractId")
);

-- Seed a checkpoint for the legacy contract if one was in use.
INSERT INTO "Checkpoint" ("contractId", "ledger")
SELECT COALESCE(current_setting('app.legacy_contract_id', true), ''), 0
WHERE COALESCE(current_setting('app.legacy_contract_id', true), '') <> ''
ON CONFLICT DO NOTHING;

-- 3. Add indexes for the new contractId columns.
CREATE INDEX "Attestation_contractId_idx" ON "Attestation"("contractId");
CREATE INDEX "Attestation_contractId_subject_idx" ON "Attestation"("contractId", "subject");
CREATE INDEX "Attestation_contractId_issuer_idx" ON "Attestation"("contractId", "issuer");
CREATE INDEX "Attestation_contractId_claimType_idx" ON "Attestation"("contractId", "claimType");

CREATE INDEX "MultisigProposal_contractId_idx" ON "MultisigProposal"("contractId");
13 changes: 10 additions & 3 deletions indexer/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ datasource db {

model Attestation {
id String @id // deterministic hash ID from the contract
contractId String // the contract that emitted this attestation
issuer String
subject String
claimType String
Expand All @@ -28,10 +29,15 @@ model Attestation {
@@index([claimType])
@@index([subject, claimType])
@@index([timestamp])
@@index([contractId])
@@index([contractId, subject])
@@index([contractId, issuer])
@@index([contractId, claimType])
}

model MultisigProposal {
id String @id // proposal ID from the contract
contractId String // the contract that emitted this proposal
subject String
proposer String
claimType String
Expand All @@ -45,12 +51,13 @@ model MultisigProposal {

@@index([subject])
@@index([proposer])
@@index([contractId])
}

// Singleton row (id=1) tracking the last fully-processed ledger sequence.
// One row per watched contract, tracking the last fully-processed ledger.
model Checkpoint {
id Int @id @default(1)
ledger Int
contractId String @id
ledger Int
}

model Webhook {
Expand Down
Loading
Loading