Skip to content

Commit

Permalink
monad-faucet-growth+-only
Browse files Browse the repository at this point in the history
  • Loading branch information
jnsdls committed Feb 26, 2025
1 parent 959712d commit 1325058
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ export function FaucetButton({

{canClaimFaucetQuery.data.type === "unsupported-chain" &&
"Faucet is empty right now"}

{canClaimFaucetQuery.data.type === "paid-plan-required" && (
<>
This faucet is temporarily only available to <b>Growth</b> and{" "}
<b>Pro</b> customers.
</>
)}
</Button>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ export type CanClaimResponseType =
| {
canClaim: false;
type: "unsupported-chain";
}
| {
canClaim: false;
type: "paid-plan-required";
};
26 changes: 26 additions & 0 deletions apps/dashboard/src/app/api/testnet-faucet/can-claim/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getTeams } from "@/api/team";
import {
DISABLE_FAUCET_CHAIN_IDS,
THIRDWEB_ACCESS_TOKEN,
Expand All @@ -8,6 +9,7 @@ import { ipAddress } from "@vercel/functions";
import { cacheTtl } from "lib/redis";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID } from "../config";
import type { CanClaimResponseType } from "./CanClaimResponseType";

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

// IF the faucet requires a paid plan, check if the user has a paid plan
if (FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID.has(chainId)) {
// get the teams for the account
const teams = await getTeams();
if (!teams) {
const res: CanClaimResponseType = {
canClaim: false,
type: "paid-plan-required",
};
return NextResponse.json(res);
}
// check if ANY of the customer's teams has "growth" or "pro" plan
const hasPaidPlan = teams.some((team) =>
["growth", "pro"].includes(team.billingPlan),
);
if (!hasPaidPlan) {
const res: CanClaimResponseType = {
canClaim: false,
type: "paid-plan-required",
};
return NextResponse.json(res);
}
}

if (
!THIRDWEB_ENGINE_URL ||
!THIRDWEB_ENGINE_FAUCET_WALLET ||
Expand Down
92 changes: 62 additions & 30 deletions apps/dashboard/src/app/api/testnet-faucet/claim/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getTeams } from "@/api/team";
import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
import {
API_SERVER_URL,
Expand All @@ -11,6 +12,7 @@ import { startOfToday } from "date-fns";
import { cacheGet, cacheSet } from "lib/redis";
import { type NextRequest, NextResponse } from "next/server";
import { ZERO_ADDRESS, getAddress } from "thirdweb";
import { FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID } from "../config";
import { getFaucetClaimAmount } from "./claim-amount";

interface RequestTestnetFundsPayload {
Expand Down Expand Up @@ -53,36 +55,6 @@ export const POST = async (req: NextRequest) => {
);
}

// Make sure the connected wallet has a thirdweb account
const accountRes = await fetch(`${API_SERVER_URL}/v1/account/me`, {
method: "GET",
headers: {
Authorization: `Bearer ${authCookie.value}`,
},
});

if (accountRes.status !== 200) {
// Account not found on this connected address
return NextResponse.json(
{
error: "thirdweb account not found",
},
{ status: 400 },
);
}

const account: { data: Account } = await accountRes.json();

// Make sure the logged-in account has verified its email
if (!account.data.email) {
return NextResponse.json(
{
error: "Account owner hasn't verified email",
},
{ status: 400 },
);
}

const requestBody = (await req.json()) as RequestTestnetFundsPayload;
const { chainId, toAddress, turnstileToken } = requestBody;
if (Number.isNaN(chainId)) {
Expand Down Expand Up @@ -150,6 +122,66 @@ export const POST = async (req: NextRequest) => {
);
}

// Make sure the connected wallet has a thirdweb account
const accountRes = await fetch(`${API_SERVER_URL}/v1/account/me`, {
method: "GET",
headers: {
Authorization: `Bearer ${authCookie.value}`,
},
});

if (accountRes.status !== 200) {
// Account not found on this connected address
return NextResponse.json(
{
error: "thirdweb account not found",
},
{ status: 400 },
);
}

const account: { data: Account } = await accountRes.json();

// Make sure the logged-in account has verified its email
if (!account.data.email) {
return NextResponse.json(
{
error: "Account owner hasn't verified email",
},
{ status: 400 },
);
}

// IF the faucet requires a paid plan, check if the user has a paid plan
if (FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID.has(chainId)) {
// get the teams for the account
const teams = await getTeams();
if (!teams) {
return NextResponse.json(
{
error: "No teams found for this account.",
},
{
status: 500,
},
);
}
// check if ANY of the customer's teams has "growth" or "pro" plan
const hasPaidPlan = teams.some((team) =>
["growth", "pro"].includes(team.billingPlan),
);
if (!hasPaidPlan) {
return NextResponse.json(
{
error: "Paid plan required to claim on this chain.",
},
{
status: 402,
},
);
}
}

const ipCacheKey = `testnet-faucet:${chainId}:${ip}`;
const addressCacheKey = `testnet-faucet:${chainId}:${toAddress}`;
const accountCacheKey = `testnet-faucet:${chainId}:${account.data.id}`;
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/src/app/api/testnet-faucet/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const FAUCET_REQUIRES_PAID_PLAN_CHAIN_ID = new Set([
10143, // monad testnet
]);

0 comments on commit 1325058

Please sign in to comment.