-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathroute.ts
More file actions
74 lines (64 loc) 路 2.25 KB
/
Copy pathroute.ts
File metadata and controls
74 lines (64 loc) 路 2.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { createHmac } from "node:crypto"
import { processContractEvent } from "@packages/cqrs"
import { env } from "@packages/env"
import { NetworkSchema, type NetworkT } from "@packages/schema"
import { bioVerifyAbi, NetworkToChainId } from "@packages/utils"
import { waitUntil } from "@vercel/functions"
import { NextResponse } from "next/server"
import { decodeEventLog } from "viem"
import { inngest } from "@/inngest/client"
const SECRETS: Record<NetworkT, string | undefined> = {
[NetworkSchema.enum.base_sepolia]: env.ALCHEMY_BASE_SEPOLIA_WH_SK,
[NetworkSchema.enum.eth_sepolia]: env.ALCHEMY_ETH_SEPOLIA_WH_SK,
}
export async function POST(req: Request) {
const signature = req.headers.get("x-alchemy-signature")
const rawBody = await req.text()
if (!signature) return new Response("Missing signature", { status: 401 })
const isValid = (secret: string) =>
createHmac("sha256", secret).update(rawBody).digest("hex") === signature
let activeChainId: number | null = null
if (SECRETS.base_sepolia && isValid(SECRETS.base_sepolia)) {
activeChainId = NetworkToChainId[NetworkSchema.enum.base_sepolia]
} else if (SECRETS.eth_sepolia && isValid(SECRETS.eth_sepolia)) {
activeChainId = NetworkToChainId[NetworkSchema.enum.eth_sepolia]
}
if (!activeChainId)
return NextResponse.json({ error: "Invalid signature" }, { status: 401 })
const json = JSON.parse(rawBody)
const logs = json.event?.data?.block?.logs || []
const blockNumber = BigInt(json.event?.data?.block?.number || 0)
waitUntil(
(async () => {
for (const log of logs) {
try {
const decoded = decodeEventLog({
abi: bioVerifyAbi,
data: log.data,
topics: log.topics,
})
if (!decoded.eventName) {
console.warn(
`[Webhook] Skipping anonymous/undecoded event at block ${blockNumber}`,
)
continue
}
// Call the CQRS handler
await processContractEvent({
chainId: activeChainId as number,
decoded: decoded as unknown as { eventName: string; args: any },
blockNumber,
logIndex: Number(log.index),
inngest: inngest,
})
} catch (e) {
console.error(
`[Webhook] Failed to process log at block ${blockNumber}:`,
e,
)
}
}
})(),
)
return NextResponse.json({ received: true })
}