diff --git a/src/app/api/backfill-user-address/route.ts b/src/app/api/backfill-user-address/route.ts index 778c7dd6..48c6425c 100644 --- a/src/app/api/backfill-user-address/route.ts +++ b/src/app/api/backfill-user-address/route.ts @@ -3,7 +3,7 @@ import { decodeEventLog } from "viem"; import { publicClient } from "../../../../lib/rpc"; import { createServerClient } from "../../../../lib/supabase"; import { mcv2BondEventAbi } from "../../../../lib/contracts/abi"; -import { MCV2_BOND } from "../../../../lib/contracts/constants"; +import { MCV2_BOND, ZAP_PLOTLINK } from "../../../../lib/contracts/constants"; /** Fail closed in production when CRON_SECRET is unset */ function verifyCron(req: Request): boolean { @@ -25,11 +25,11 @@ export async function POST(req: Request) { return NextResponse.json({ error: "Supabase not configured" }, { status: 500 }); } - // Fetch all trade_history rows missing user_address + // Fetch trade_history rows missing user_address OR attributed to the Zap contract const { data: rows, error: fetchError } = await supabase .from("trade_history") .select("id, tx_hash, log_index") - .is("user_address", null) + .or(`user_address.is.null,user_address.eq.${ZAP_PLOTLINK.toLowerCase()}`) .order("id", { ascending: true }) .limit(500); @@ -79,8 +79,23 @@ export async function POST(req: Request) { topics: log.topics, }); - const args = decoded.args as { user: `0x${string}` }; - const userAddress = args.user.toLowerCase(); + const args = decoded.args as { user: `0x${string}`; receiver: `0x${string}` }; + const userAddress = args.receiver.toLowerCase(); + + // Delete intermediate Zap self-mints (receiver is the Zap contract) + if (userAddress === ZAP_PLOTLINK.toLowerCase()) { + const { error: deleteError } = await supabase + .from("trade_history") + .delete() + .eq("id", row.id); + if (deleteError) { + errorDetails.push({ id: row.id, tx_hash: txHash, reason: deleteError.message }); + errors++; + } else { + updated++; + } + continue; + } const { error: updateError } = await supabase .from("trade_history") diff --git a/src/app/api/cron/trade-history/route.ts b/src/app/api/cron/trade-history/route.ts index 7516bc44..99099430 100644 --- a/src/app/api/cron/trade-history/route.ts +++ b/src/app/api/cron/trade-history/route.ts @@ -3,7 +3,7 @@ import { decodeEventLog, formatUnits, type Log } from "viem"; import { publicClient } from "../../../../../lib/rpc"; import { createServerClient } from "../../../../../lib/supabase"; import { mcv2BondEventAbi } from "../../../../../lib/contracts/abi"; -import { MCV2_BOND } from "../../../../../lib/contracts/constants"; +import { MCV2_BOND, ZAP_PLOTLINK } from "../../../../../lib/contracts/constants"; import { erc20Abi } from "../../../../../lib/price"; import type { Database } from "../../../../../lib/supabase"; @@ -172,12 +172,16 @@ async function processTradeEvent( const args = decoded.args as { token: `0x${string}`; user: `0x${string}`; + receiver: `0x${string}`; amountMinted?: bigint; amountBurned?: bigint; reserveAmount?: bigint; refundAmount?: bigint; }; + // Skip intermediate Zap self-mints (HUNT→PLOT conversion where receiver is the Zap contract) + if (args.receiver.toLowerCase() === ZAP_PLOTLINK.toLowerCase()) return; + const isMint = decoded.eventName === "Mint"; const reserveAmount = isMint ? args.reserveAmount! : args.refundAmount!; const tokenAmount = isMint ? args.amountMinted! : args.amountBurned!; @@ -215,7 +219,7 @@ async function processTradeEvent( tx_hash: log.transactionHash!.toLowerCase(), log_index: log.logIndex!, contract_address: MCV2_BOND.toLowerCase(), - user_address: args.user.toLowerCase(), + user_address: args.receiver.toLowerCase(), }; const { error } = await supabase diff --git a/src/app/api/index/trade/route.ts b/src/app/api/index/trade/route.ts index 38f960a6..91a8613f 100644 --- a/src/app/api/index/trade/route.ts +++ b/src/app/api/index/trade/route.ts @@ -3,7 +3,7 @@ import { type Hex, decodeEventLog, formatUnits } from "viem"; import { publicClient, getReceiptWithRetry } from "../../../../../lib/rpc"; import { createServerClient } from "../../../../../lib/supabase"; import { mcv2BondEventAbi, priceForNextMintFunction } from "../../../../../lib/contracts/abi"; -import { MCV2_BOND } from "../../../../../lib/contracts/constants"; +import { MCV2_BOND, ZAP_PLOTLINK } from "../../../../../lib/contracts/constants"; import { erc20Abi } from "../../../../../lib/price"; import type { Database } from "../../../../../lib/supabase"; @@ -66,6 +66,7 @@ export async function POST(req: Request) { const args = decoded.args as { token: `0x${string}`; user: `0x${string}`; + receiver: `0x${string}`; amountMinted?: bigint; amountBurned?: bigint; reserveAmount?: bigint; @@ -74,6 +75,9 @@ export async function POST(req: Request) { if (args.token.toLowerCase() !== tokenAddress) continue; + // Skip intermediate Zap self-mints (HUNT→PLOT conversion where receiver is the Zap contract) + if (args.receiver.toLowerCase() === ZAP_PLOTLINK.toLowerCase()) continue; + const isMint = decoded.eventName === "Mint"; const reserveAmount = isMint ? args.reserveAmount! : args.refundAmount!; const tokenAmount = isMint ? args.amountMinted! : args.amountBurned!; @@ -121,7 +125,7 @@ export async function POST(req: Request) { tx_hash: txHash.toLowerCase(), log_index: log.logIndex!, contract_address: MCV2_BOND.toLowerCase(), - user_address: args.user.toLowerCase(), + user_address: args.receiver.toLowerCase(), }; const { error: dbError } = await supabase