Skip to content

Commit e6687d5

Browse files
committed
monad-faucet-growth+-only
1 parent 959712d commit e6687d5

File tree

5 files changed

+98
-30
lines changed

5 files changed

+98
-30
lines changed

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/FaucetButton.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ export function FaucetButton({
237237

238238
{canClaimFaucetQuery.data.type === "unsupported-chain" &&
239239
"Faucet is empty right now"}
240+
241+
{canClaimFaucetQuery.data.type === "paid-plan-required" &&
242+
"This faucet is temporarily not available to customers on the free plan."}
240243
</Button>
241244
);
242245
}

apps/dashboard/src/app/api/testnet-faucet/can-claim/CanClaimResponseType.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ export type CanClaimResponseType =
77
| {
88
canClaim: false;
99
type: "unsupported-chain";
10+
}
11+
| {
12+
canClaim: false;
13+
type: "paid-plan-required";
1014
};

apps/dashboard/src/app/api/testnet-faucet/can-claim/route.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getTeams } from "@/api/team";
12
import {
23
DISABLE_FAUCET_CHAIN_IDS,
34
THIRDWEB_ACCESS_TOKEN,
@@ -8,6 +9,7 @@ import { ipAddress } from "@vercel/functions";
89
import { cacheTtl } from "lib/redis";
910
import { NextResponse } from "next/server";
1011
import type { NextRequest } from "next/server";
12+
import { FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID } from "../config";
1113
import type { CanClaimResponseType } from "./CanClaimResponseType";
1214

1315
// Note: This handler cannot use "edge" runtime because of Redis usage.
@@ -46,6 +48,30 @@ export const GET = async (req: NextRequest) => {
4648
} catch {}
4749
}
4850

51+
// IF the faucet requires a paid plan, check if the user has a paid plan
52+
if (FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID.has(chainId)) {
53+
// get the teams for the account
54+
const teams = await getTeams();
55+
if (!teams) {
56+
const res: CanClaimResponseType = {
57+
canClaim: false,
58+
type: "paid-plan-required",
59+
};
60+
return NextResponse.json(res);
61+
}
62+
// check if ANY of the customer's teams has "growth" or "pro" plan
63+
const hasPaidPlan = teams.some((team) =>
64+
["starter", "growth", "pro"].includes(team.billingPlan),
65+
);
66+
if (!hasPaidPlan) {
67+
const res: CanClaimResponseType = {
68+
canClaim: false,
69+
type: "paid-plan-required",
70+
};
71+
return NextResponse.json(res);
72+
}
73+
}
74+
4975
if (
5076
!THIRDWEB_ENGINE_URL ||
5177
!THIRDWEB_ENGINE_FAUCET_WALLET ||

apps/dashboard/src/app/api/testnet-faucet/claim/route.ts

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getTeams } from "@/api/team";
12
import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
23
import {
34
API_SERVER_URL,
@@ -11,6 +12,7 @@ import { startOfToday } from "date-fns";
1112
import { cacheGet, cacheSet } from "lib/redis";
1213
import { type NextRequest, NextResponse } from "next/server";
1314
import { ZERO_ADDRESS, getAddress } from "thirdweb";
15+
import { FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID } from "../config";
1416
import { getFaucetClaimAmount } from "./claim-amount";
1517

1618
interface RequestTestnetFundsPayload {
@@ -53,36 +55,6 @@ export const POST = async (req: NextRequest) => {
5355
);
5456
}
5557

56-
// Make sure the connected wallet has a thirdweb account
57-
const accountRes = await fetch(`${API_SERVER_URL}/v1/account/me`, {
58-
method: "GET",
59-
headers: {
60-
Authorization: `Bearer ${authCookie.value}`,
61-
},
62-
});
63-
64-
if (accountRes.status !== 200) {
65-
// Account not found on this connected address
66-
return NextResponse.json(
67-
{
68-
error: "thirdweb account not found",
69-
},
70-
{ status: 400 },
71-
);
72-
}
73-
74-
const account: { data: Account } = await accountRes.json();
75-
76-
// Make sure the logged-in account has verified its email
77-
if (!account.data.email) {
78-
return NextResponse.json(
79-
{
80-
error: "Account owner hasn't verified email",
81-
},
82-
{ status: 400 },
83-
);
84-
}
85-
8658
const requestBody = (await req.json()) as RequestTestnetFundsPayload;
8759
const { chainId, toAddress, turnstileToken } = requestBody;
8860
if (Number.isNaN(chainId)) {
@@ -150,6 +122,66 @@ export const POST = async (req: NextRequest) => {
150122
);
151123
}
152124

125+
// Make sure the connected wallet has a thirdweb account
126+
const accountRes = await fetch(`${API_SERVER_URL}/v1/account/me`, {
127+
method: "GET",
128+
headers: {
129+
Authorization: `Bearer ${authCookie.value}`,
130+
},
131+
});
132+
133+
if (accountRes.status !== 200) {
134+
// Account not found on this connected address
135+
return NextResponse.json(
136+
{
137+
error: "thirdweb account not found",
138+
},
139+
{ status: 400 },
140+
);
141+
}
142+
143+
const account: { data: Account } = await accountRes.json();
144+
145+
// Make sure the logged-in account has verified its email
146+
if (!account.data.email) {
147+
return NextResponse.json(
148+
{
149+
error: "Account owner hasn't verified email",
150+
},
151+
{ status: 400 },
152+
);
153+
}
154+
155+
// IF the faucet requires a paid plan, check if the user has a paid plan
156+
if (FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID.has(chainId)) {
157+
// get the teams for the account
158+
const teams = await getTeams();
159+
if (!teams) {
160+
return NextResponse.json(
161+
{
162+
error: "No teams found for this account.",
163+
},
164+
{
165+
status: 500,
166+
},
167+
);
168+
}
169+
// check if ANY of the customer's teams has "growth" or "pro" plan
170+
const hasPaidPlan = teams.some((team) =>
171+
["starter", "growth", "pro"].includes(team.billingPlan),
172+
);
173+
if (!hasPaidPlan) {
174+
return NextResponse.json(
175+
{
176+
error: "Free plan cannot claim on this chain.",
177+
},
178+
{
179+
status: 402,
180+
},
181+
);
182+
}
183+
}
184+
153185
const ipCacheKey = `testnet-faucet:${chainId}:${ip}`;
154186
const addressCacheKey = `testnet-faucet:${chainId}:${toAddress}`;
155187
const accountCacheKey = `testnet-faucet:${chainId}:${account.data.id}`;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID = new Set([
2+
10143, // monad testnet
3+
]);

0 commit comments

Comments
 (0)