1+ import { COOKIE_ACTIVE_ACCOUNT , COOKIE_PREFIX_TOKEN } from "@/constants/cookie" ;
2+ import { API_SERVER_URL } from "@/constants/env" ;
3+ import type { Account } from "@3rdweb-sdk/react/hooks/useApi" ;
14import { startOfToday } from "date-fns" ;
25import { cacheGet , cacheSet } from "lib/redis" ;
36import { type NextRequest , NextResponse } from "next/server" ;
4- import { ZERO_ADDRESS } from "thirdweb" ;
7+ import { ZERO_ADDRESS , getAddress } from "thirdweb" ;
58import { getFaucetClaimAmount } from "./claim-amount" ;
69
710const THIRDWEB_ENGINE_URL = process . env . THIRDWEB_ENGINE_URL ;
@@ -19,6 +22,60 @@ interface RequestTestnetFundsPayload {
1922
2023// Note: This handler cannot use "edge" runtime because of Redis usage.
2124export const POST = async ( req : NextRequest ) => {
25+ // Make sure user's connected to the site
26+ const activeAccount = req . cookies . get ( COOKIE_ACTIVE_ACCOUNT ) ?. value ;
27+
28+ if ( ! activeAccount ) {
29+ return NextResponse . json (
30+ {
31+ error : "No wallet detected" ,
32+ } ,
33+ { status : 400 } ,
34+ ) ;
35+ }
36+ const authCookieName = COOKIE_PREFIX_TOKEN + getAddress ( activeAccount ) ;
37+
38+ const authCookie = req . cookies . get ( authCookieName ) ;
39+
40+ if ( ! authCookie ) {
41+ return NextResponse . json (
42+ {
43+ error : "No wallet connected" ,
44+ } ,
45+ { status : 400 } ,
46+ ) ;
47+ }
48+
49+ // Make sure the connected wallet has a thirdweb account
50+ const accountRes = await fetch ( `${ API_SERVER_URL } /v1/account/me` , {
51+ method : "GET" ,
52+ headers : {
53+ Authorization : `Bearer ${ authCookie . value } ` ,
54+ } ,
55+ } ) ;
56+
57+ if ( accountRes . status !== 200 ) {
58+ // Account not found on this connected address
59+ return NextResponse . json (
60+ {
61+ error : "thirdweb account not found" ,
62+ } ,
63+ { status : 400 } ,
64+ ) ;
65+ }
66+
67+ const account : Account = await accountRes . json ( ) ;
68+
69+ // Make sure the logged-in account has verified its email
70+ if ( ! account . emailConfirmedAt && ! account . unconfirmedEmail ) {
71+ return NextResponse . json (
72+ {
73+ error : "Account owner hasn't verified email" ,
74+ } ,
75+ { status : 400 } ,
76+ ) ;
77+ }
78+
2279 const requestBody = ( await req . json ( ) ) as RequestTestnetFundsPayload ;
2380 const { chainId, toAddress, turnstileToken } = requestBody ;
2481 if ( Number . isNaN ( chainId ) ) {
@@ -86,17 +143,17 @@ export const POST = async (req: NextRequest) => {
86143 ) ;
87144 }
88145
89- const ipCacheKey = `testnet-faucet:${ chainId } :${ ipAddress } ` ;
90146 const addressCacheKey = `testnet-faucet:${ chainId } :${ toAddress } ` ;
147+ const accountCacheKey = `testnet-faucet:${ chainId } :${ account . id } ` ;
91148
92- // Assert 1 request per IP/chain every 24 hours.
149+ // Assert 1 request per userId every 24 hours.
93150 // get the cached value
94- const [ ipCacheValue , addressCache ] = await Promise . all ( [
95- cacheGet ( ipCacheKey ) ,
151+ const [ accountCacheValue , addressCache ] = await Promise . all ( [
152+ cacheGet ( accountCacheKey ) ,
96153 cacheGet ( addressCacheKey ) ,
97154 ] ) ;
98155 // if we have a cached value, return an error
99- if ( ipCacheValue !== null || addressCache !== null ) {
156+ if ( accountCacheValue !== null || addressCache !== null ) {
100157 return NextResponse . json (
101158 { error : "Already requested funds on this chain in the past 24 hours." } ,
102159 { status : 429 } ,
@@ -109,13 +166,13 @@ export const POST = async (req: NextRequest) => {
109166 todayLocal . getTime ( ) - todayLocal . getTimezoneOffset ( ) * 60000 ,
110167 ) ;
111168 const todayUTCSeconds = Math . floor ( todayUTC . getTime ( ) / 1000 ) ;
112- const idempotencyKey = `${ ipCacheKey } :${ todayUTCSeconds } ` ;
169+ const idempotencyKey = `${ accountCacheValue } :${ todayUTCSeconds } ` ;
113170 const amountToClaim = getFaucetClaimAmount ( chainId ) . toString ( ) ;
114171
115172 try {
116173 // Store the claim request for 24 hours.
117174 await Promise . all ( [
118- cacheSet ( ipCacheKey , "claimed" , 24 * 60 * 60 ) ,
175+ cacheSet ( accountCacheKey , "claimed" , 24 * 60 * 60 ) ,
119176 cacheSet ( addressCacheKey , "claimed" , 24 * 60 * 60 ) ,
120177 ] ) ;
121178 // then actually transfer the funds
0 commit comments