Skip to content

Commit

Permalink
Merge pull request #5 from kaiachain/dev
Browse files Browse the repository at this point in the history
Sender whitelist feature
  • Loading branch information
kjeom authored Jan 15, 2025
2 parents deb697b + 8b5a783 commit b41b281
Show file tree
Hide file tree
Showing 20 changed files with 512 additions and 6,556 deletions.
7 changes: 7 additions & 0 deletions app/api/auth/[...nextauth]/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { verify } from "@/lib/verifyToken";
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

Expand Down Expand Up @@ -28,6 +29,12 @@ const handler = NextAuth({
session.user.name = token.name as string;
session.idToken = token.idToken as string;
session.idTokenExpires = token.expiresAt as number;
const admins = (process.env.GOOGLE_WHITELIST || "").split(",");
if (admins.includes(session.user.email)) {
session.user.role = "editor";
} else {
session.user.role = "viewer";
}
if (Date.now() < ((session.idTokenExpires as number) * 1000 || 0)) {
return {
...session,
Expand Down
2 changes: 1 addition & 1 deletion app/api/contracts/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NextRequest, NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { prisma } from "@/lib/prisma";
import { ethers } from "ethers";
import { createResponse } from "@/lib/apiUtils";
Expand Down
31 changes: 18 additions & 13 deletions app/api/dapps/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,14 @@ import { prisma } from "@/lib/prisma";
import { ethers } from "ethers";
import { createResponse, formattedBalance } from "@/lib/apiUtils";
import { verify } from "@/lib/verifyToken";

type Dapp = {
name?: string;
url?: string;
balance?: number;
contracts?: Contracts[];
};

type Contracts = {
address: string;
};
import { Dapp } from "@/types";

export async function GET() {
try {
const dapps = await prisma.dApp.findMany({
include: {
contracts: true,
senders: true,
},
});

Expand All @@ -45,14 +36,17 @@ export async function POST(req: NextRequest) {
return createResponse("INTERNAL_ERROR", "Unauthorized");
}

const { name, url, balance, contracts } = await req.json();
const { name, url, balance, contracts, senders } = await req.json();

const data: any = {
name,
url,
contracts: {
create: contracts,
},
senders: {
create: senders,
},
};

if (
Expand All @@ -61,6 +55,7 @@ export async function POST(req: NextRequest) {
url,
balance,
contracts,
senders,
})
) {
return createResponse("BAD_REQUEST", "Invalid dapp data");
Expand All @@ -75,7 +70,10 @@ export async function POST(req: NextRequest) {
data,
});

return NextResponse.json(dapp);
return NextResponse.json({
...dapp,
balance: ethers.formatUnits(dapp.balance),
});
} catch (error) {
console.error("Error creating dapp:", JSON.stringify(error));
return createResponse("INTERNAL_ERROR", "Failed to create dapp");
Expand Down Expand Up @@ -179,6 +177,13 @@ const verifyDapp = (dapp: Dapp) => {
) {
return false;
}
if (
dapp.senders &&
dapp.senders.length !== 0 &&
!dapp.senders.every((sender) => ethers.isAddress(sender.address))
) {
return false;
}
return true;
};

Expand Down
6 changes: 2 additions & 4 deletions app/api/pool/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { createResponse } from "@/lib/apiUtils";
import { verify } from "@/lib/verifyToken";
import { JsonRpcProvider } from "@kaiachain/ethers-ext/v6";
import { NextRequest } from "next/server";
import { formattedBalance } from "@/lib/apiUtils";

const provider = new JsonRpcProvider(process.env.RPC_URL as string);
import pickProviderFromPool from "@/lib/rpcProvider";

export async function GET(req: NextRequest) {
try {
Expand All @@ -15,7 +13,7 @@ export async function GET(req: NextRequest) {
return createResponse("INTERNAL_ERROR", "Unauthorized");
}

const balance = await provider.getBalance(
const balance = await pickProviderFromPool().getBalance(
process.env.ACCOUNT_ADDRESS as string,
"latest"
);
Expand Down
89 changes: 89 additions & 0 deletions app/api/senders/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { NextRequest } from "next/server";
import { prisma } from "@/lib/prisma";
import { ethers } from "ethers";
import { createResponse } from "@/lib/apiUtils";
import { verify } from "@/lib/verifyToken";

export async function POST(req: NextRequest) {
try {
const { role } = await verify(
req.headers.get("Authorization")?.split(" ")[1] || ""
);
if (role !== "editor") {
return createResponse("INTERNAL_ERROR", "Unauthorized");
}

const { dappId, address } = await req.json();

if (!dappId || !address) {
return createResponse(
"BAD_REQUEST",
"Missing required fields: dappId, address"
);
}

if (ethers.isAddress(address) === false) {
return createResponse("BAD_REQUEST", "Invalid address");
}

if (
await prisma.sender.findFirst({
where: {
address,
},
})
) {
return createResponse("BAD_REQUEST", "Sender already exists");
}

const newSender = await prisma.sender.create({
data: {
address: address.toLowerCase(),
dappId,
},
});

return createResponse("SUCCESS", newSender);
} catch (error) {
console.error("Error adding sender:", error);
return createResponse("INTERNAL_ERROR", "Failed to add sender");
}
}

export async function DELETE(req: NextRequest) {
try {
const { role } = await verify(
req.headers.get("Authorization")?.split(" ")[1] || ""
);
if (role !== "editor") {
return createResponse("INTERNAL_ERROR", "Unauthorized");
}

const { id } = await req.json();

if (!id) {
return createResponse("BAD_REQUEST", "Missing required field: id");
}

const sender = await prisma.sender.findFirst({
where: {
id,
},
});

if (!sender) {
return createResponse("BAD_REQUEST", "Sender not found");
}

await prisma.sender.delete({
where: {
id,
},
});

return createResponse("SUCCESS", sender);
} catch (error) {
console.error("Error deleting sender:", error);
return createResponse("INTERNAL_ERROR", "Failed to delete sender");
}
}
51 changes: 38 additions & 13 deletions app/api/signAsFeePayer/route.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { NextRequest } from "next/server";
import {
Wallet,
parseTransaction,
JsonRpcProvider,
} from "@kaiachain/ethers-ext/v6";
import { Wallet, parseTransaction } from "@kaiachain/ethers-ext/v6";
import { createResponse } from "@/lib/apiUtils";
import { prisma } from "@/lib/prisma";
import { DApp } from "@prisma/client";

const provider = new JsonRpcProvider(process.env.RPC_URL as string);
import pickProviderFromPool from "@/lib/rpcProvider";

export async function POST(req: NextRequest) {
try {
Expand All @@ -25,20 +20,30 @@ export async function POST(req: NextRequest) {
// if it's testnet, allow all transactions
let dapp;
if (process.env.NETWORK === "mainnet") {
const targetContract = tx.to?.toLowerCase();
if (await isWhitelisted(targetContract as string)) {
const targetContract = tx.to?.toLowerCase() as string;
const sender = tx.from?.toLowerCase() as string;
if (
!(
(await isWhitelistedContract(targetContract)) ||
(await isWhitelistedSender(sender))
)
) {
return createResponse("BAD_REQUEST", "Contract is not whitelisted");
}
// balance check
dapp = await getDappfromContract(targetContract as string);
if (!dapp) {
return createResponse("BAD_REQUEST", "Contract not found");
dapp = await getDappfromSender(sender as string);
if (!dapp) {
return createResponse("BAD_REQUEST", "Contract not found");
}
}
if (!isEnoughBalance(BigInt(dapp.balance))) {
return createResponse("BAD_REQUEST", "Insufficient balance");
}
}

const provider = pickProviderFromPool();
const feePayer = new Wallet(
process.env.FEE_PAYER_PRIVATE_KEY as string,
provider
Expand All @@ -56,22 +61,32 @@ export async function POST(req: NextRequest) {
}

if (receipt?.status !== 1) {
return createResponse("BAD_REQUEST", "Transaction failed");
return createResponse("BAD_REQUEST", receipt);
}
return createResponse("SUCCESS", receipt);
} catch (error) {
console.log(JSON.stringify(error));
return createResponse("INTERNAL_ERROR", "An unexpected error occurred");
const msg = JSON.parse(JSON.stringify(error))?.error?.message || "";
if (msg === "")
return createResponse("INTERNAL_ERROR", "An unexpected error occurred");
return createResponse("INTERNAL_ERROR", msg);
}
}

const isWhitelisted = async (address: string) => {
const isWhitelistedContract = async (address: string) => {
const contract = await prisma.contract.findUnique({
where: { address },
});
return contract ? false : true;
};

const isWhitelistedSender = async (address: string) => {
const sender = await prisma.sender.findUnique({
where: { address },
});
return sender ? false : true;
};

const getDappfromContract = async (address: string) => {
const contract = await prisma.contract.findUnique({
where: { address },
Expand All @@ -82,6 +97,16 @@ const getDappfromContract = async (address: string) => {
return dapp;
};

const getDappfromSender = async (address: string) => {
const sender = await prisma.sender.findUnique({
where: { address },
});
const dapp = await prisma.dApp.findUnique({
where: { id: sender?.dappId },
});
return dapp;
};

const isEnoughBalance = (balance: bigint) => {
return balance > 0.1 ? true : false;
};
Expand Down
12 changes: 1 addition & 11 deletions app/components/AddDappBtn.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import React, { useState } from "react";
import AddDappModal from "./AddDappModal";

interface Contract {
address: string;
}

interface Dapp {
name: string;
url: string;
balance: number;
contracts: Contract[];
}
import { Dapp } from "@/types";

interface AddDappBtnProps {
onDappAdd: (dapp: Dapp) => void;
Expand Down
Loading

0 comments on commit b41b281

Please sign in to comment.