From 28b3593d767bcdc5f1d2709fb4bc247b96bd4683 Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Fri, 24 Apr 2026 08:27:55 +0900 Subject: [PATCH 1/2] [#961] Validate log.address against StoryFactory in indexer endpoints Co-Authored-By: Claude Opus 4.6 (1M context) --- package-lock.json | 4 ++-- package.json | 2 +- src/app/api/index/donation/route.ts | 4 ++++ src/app/api/index/plot/route.ts | 4 ++++ src/app/api/index/storyline/route.ts | 4 ++++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1c62f448..62e3e3db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "plotlink", - "version": "0.1.49", + "version": "0.1.50", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "plotlink", - "version": "0.1.49", + "version": "0.1.50", "workspaces": [ "packages/*" ], diff --git a/package.json b/package.json index f5e679d1..4651e330 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plotlink", - "version": "0.1.49", + "version": "0.1.50", "private": true, "workspaces": [ "packages/*" diff --git a/src/app/api/index/donation/route.ts b/src/app/api/index/donation/route.ts index 727c769c..493aa69c 100644 --- a/src/app/api/index/donation/route.ts +++ b/src/app/api/index/donation/route.ts @@ -43,6 +43,10 @@ export async function POST(req: Request) { return error("Donation event not found in receipt"); } + if (donationLog.address.toLowerCase() !== STORY_FACTORY.toLowerCase()) { + return error("Event not from StoryFactory", 400); + } + // 3. Decode event let decoded; try { diff --git a/src/app/api/index/plot/route.ts b/src/app/api/index/plot/route.ts index b782a684..83aadc72 100644 --- a/src/app/api/index/plot/route.ts +++ b/src/app/api/index/plot/route.ts @@ -49,6 +49,10 @@ export async function POST(req: Request) { return error("PlotChained event not found in receipt"); } + if (plotChainedLog.address.toLowerCase() !== STORY_FACTORY.toLowerCase()) { + return error("Event not from StoryFactory", 400); + } + // 3. Decode event let decoded; try { diff --git a/src/app/api/index/storyline/route.ts b/src/app/api/index/storyline/route.ts index c05421ad..eafb6822 100644 --- a/src/app/api/index/storyline/route.ts +++ b/src/app/api/index/storyline/route.ts @@ -56,6 +56,10 @@ export async function POST(req: Request) { return error("StorylineCreated event not found in receipt"); } + if (storylineLog.address.toLowerCase() !== STORY_FACTORY.toLowerCase()) { + return error("Event not from StoryFactory", 400); + } + // 3. Decode event let decoded; try { From 2c158527895186d6e6ee5b0e4ea2141df1e2f04d Mon Sep 17 00:00:00 2001 From: Cho Young-Hwi Date: Fri, 24 Apr 2026 08:29:24 +0900 Subject: [PATCH 2/2] [#961] Add fail-fast contract validation to trade indexer endpoint Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/api/index/trade/route.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/app/api/index/trade/route.ts b/src/app/api/index/trade/route.ts index f1c67261..f53cafad 100644 --- a/src/app/api/index/trade/route.ts +++ b/src/app/api/index/trade/route.ts @@ -55,6 +55,14 @@ export async function POST(req: Request) { } } + // Fail fast if no logs from MCV2_BOND in this receipt + const hasBondLog = receipt.logs.some( + (log) => log.address.toLowerCase() === MCV2_BOND.toLowerCase() + ); + if (!hasBondLog) { + return error("Event not from MCV2_Bond", 400); + } + // Fetch current PLOT/USD rate for this trade batch const reserveUsdRate = await getReserveUsdRate();