diff --git a/apps/web/.env.example b/apps/web/.env.example
index 79c3856..ef3b496 100644
--- a/apps/web/.env.example
+++ b/apps/web/.env.example
@@ -1,5 +1,5 @@
NEXT_PUBLIC_EVENTS_FACTORY_CONTRACT_ADDRESS=
-NEXT_PUBLIC_PINATA_GATEWAY=
+PINATA_IPFS_ENDPOINT=
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=
LINEA_TEST_RPC_ENDPOINT=
@@ -8,6 +8,6 @@ PINATA_API_KEY=
INFURA_API_KEY=
INFURA_API_SECRET=
-
+ACCOUNT_PRIVATE_KEY
NETWORK=localhost
diff --git a/apps/web/.gitignore b/apps/web/.gitignore
index 1437c53..849ad97 100644
--- a/apps/web/.gitignore
+++ b/apps/web/.gitignore
@@ -32,3 +32,6 @@ yarn-error.log*
# vercel
.vercel
+
+# generated contract artifacts
+lib/contracts/*
\ No newline at end of file
diff --git a/apps/web/app/api/gas/route.ts b/apps/web/app/api/gas/route.ts
index e5c80dc..20b73bb 100644
--- a/apps/web/app/api/gas/route.ts
+++ b/apps/web/app/api/gas/route.ts
@@ -1,11 +1,12 @@
import { NextResponse } from "next/server";
+import { env } from "@/env.mjs";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const chainId = searchParams.get("chainId");
const Auth = Buffer.from(
- process.env.INFURA_API_KEY + ":" + process.env.INFURA_API_SECRET
+ env.INFURA_API_KEY + ":" + env.INFURA_API_SECRET
).toString("base64");
const gasPricesResp = await fetch(
diff --git a/apps/web/app/api/ipfs/route.ts b/apps/web/app/api/ipfs/route.ts
new file mode 100644
index 0000000..af132a6
--- /dev/null
+++ b/apps/web/app/api/ipfs/route.ts
@@ -0,0 +1,28 @@
+import { env } from "@/env.mjs";
+
+export async function POST(request: Request) {
+ const data = await request.formData();
+ const baseUrl = env.INFURA_IPFS_ENDPOINT;
+
+ try {
+ const res = await fetch(`${baseUrl}/api/v0/add`, {
+ method: "POST",
+ headers: {
+ Authorization:
+ "Basic " +
+ Buffer.from(
+ env.INFURA_API_KEY + ":" + env.INFURA_API_SECRET
+ ).toString("base64"),
+ },
+ body: data,
+ });
+
+
+ const json = await res.json();
+
+ return Response.json({ hash: json.Hash });
+ } catch (error) {
+ console.error(error);
+ throw new Error("Error adding file");
+ }
+}
diff --git a/apps/web/app/events/[eventId]/layout.tsx b/apps/web/app/events/[eventId]/layout.tsx
index a164dfa..97d84f5 100644
--- a/apps/web/app/events/[eventId]/layout.tsx
+++ b/apps/web/app/events/[eventId]/layout.tsx
@@ -1,5 +1,4 @@
-import { getEventContract } from "@/lib/getEventContract";
-import { ContractPermission } from "@/types";
+import { getEventById } from "@/lib/actions";
import Image from "next/image";
import { notFound } from "next/navigation";
@@ -12,17 +11,7 @@ export async function generateMetadata({
return notFound();
}
- const eventContract = await getEventContract({
- address: eventId,
- permission: ContractPermission.READ,
- });
-
- const eventData = await Promise.all([
- eventContract.title(),
- eventContract.description(),
- ]);
-
- const [title, description] = eventData;
+ const { title, description } = await getEventById(eventId);
return {
title: `${title} - Eventsea`,
diff --git a/apps/web/app/events/[eventId]/page.tsx b/apps/web/app/events/[eventId]/page.tsx
index f418d52..edf0704 100644
--- a/apps/web/app/events/[eventId]/page.tsx
+++ b/apps/web/app/events/[eventId]/page.tsx
@@ -1,12 +1,12 @@
import { notFound } from "next/navigation";
import GetTickets from "@/components/GetTickets";
import Image from "next/image";
-import { getEventContract } from "@/lib/getEventContract";
import { format } from "date-fns";
-import { getTicketContract } from "@/lib/getTicketContract";
-import { ContractPermission } from "@/types";
import EventLocationMap from "@/components/event-location-map";
+import { env } from "@/env.mjs";
+import { getEventById, getTicketById } from "@/lib/actions";
+
type PageProps = {
params: {
eventId: string;
@@ -18,48 +18,16 @@ const EventPage = async ({ params: { eventId } }: PageProps) => {
return notFound();
}
- const eventContract = await getEventContract({
- address: eventId,
- permission: ContractPermission.READ,
- });
-
- const eventData = await Promise.all([
- eventContract.title(),
- eventContract.description(),
- eventContract.location(),
- eventContract.eventType(),
- eventContract.image(),
- eventContract.date(),
- eventContract.ticketNFT(),
- ]);
-
- const [title, description, location, eventType, image, date, ticketNFT] =
- eventData;
-
- const ticketContract = await getTicketContract({
- address: ticketNFT,
- permission: ContractPermission.READ,
- });
-
- const ticketPrice = await ticketContract._ticketPrice();
-
- const ticketId = await ticketContract.tokenId();
+ const { title, eventType, description, location, date, ticketNFT, image } =
+ await getEventById(eventId);
+ const { id, price } = await getTicketById(ticketNFT);
const formattedDate = format(new Date(Number(date) * 1000), "MMM. d");
return (
-
+
@@ -88,11 +56,11 @@ const EventPage = async ({ params: { eventId } }: PageProps) => {
diff --git a/apps/web/components/CardSkeleton.tsx b/apps/web/components/CardSkeleton.tsx
index e381c3f..f90b908 100644
--- a/apps/web/components/CardSkeleton.tsx
+++ b/apps/web/components/CardSkeleton.tsx
@@ -17,7 +17,7 @@ export const CardSkeleton = ({
onLoad={() => setIsLoading(false)}
onError={() => setIsLoading(false)}
className="opacity-0"
- />
+ />
);
};
\ No newline at end of file
diff --git a/apps/web/components/EventCard.tsx b/apps/web/components/EventCard.tsx
index 66cd12c..0752491 100644
--- a/apps/web/components/EventCard.tsx
+++ b/apps/web/components/EventCard.tsx
@@ -14,7 +14,7 @@ export const EventCard = ({ event }: { event: EventSea.Event }) => {
return (
<>
- {isLoading ? (
+ {false ? (
) : (
{
setIsLoading(false)}
objectFit="cover"
alt={event.title}
diff --git a/apps/web/components/ForYou.tsx b/apps/web/components/ForYou.tsx
index a5d7ec1..265a6f9 100644
--- a/apps/web/components/ForYou.tsx
+++ b/apps/web/components/ForYou.tsx
@@ -36,7 +36,7 @@ const ForYou: React.FC = ({ events }) => {
{events.map((event, index) => {
return (
-
+
= ({ events }) => {
>
= ({
};
const handleMinTickets = async () => {
- const nftContract = await getTicketContract({
- address: ticketNFT,
- permission: ContractPermission.WRITE,
- });
+ const provider = new ethers.BrowserProvider(window.ethereum!);
+
+ const signer = await provider.getSigner();
+
+ const ticketsContract = new ethers.Contract(
+ ticketNFT,
+ TicketContract.abi,
+ signer
+ ) as unknown as Ticket;
+
if (numberOfTickets <= 0) {
console.log("Please select number of tickets");
return;
@@ -78,7 +84,7 @@ const GetTickets: React.FC = ({
const Hash = await handleUploadSVG();
const totalAmount = ticketPrice * BigInt(numberOfTickets);
const token = (
- await nftContract.mint(
+ await ticketsContract.mint(
numberOfTickets,
`https://ipfs.io/ipfs/${Hash}`,
{
diff --git a/apps/web/components/Navbar.tsx b/apps/web/components/Navbar.tsx
index 6355d5d..e3dc5d4 100644
--- a/apps/web/components/Navbar.tsx
+++ b/apps/web/components/Navbar.tsx
@@ -2,45 +2,37 @@
import Link from "next/link";
import { useSDK } from "@metamask/sdk-react";
+import { isHexString } from "ethers";
import EventSeaLogo from "../public/icons/EventSeaLogo";
import WalletIcon from "../public/icons/WalletIcon";
import CreateEvent from "@/components/create-event/create-event-form";
import { Button } from "./ui/Button";
import { SearchBar } from "./SearchBar";
-import { formatAddress } from "./../lib/utils";
+import { formatAddress, getAppChainId } from "./../lib/utils";
import {
Popover,
PopoverTrigger,
PopoverContent,
} from "@/components/ui/popover";
import MetaMaskProvider from "@/providers/MetamaskProvider";
-import { useEffect, useState } from "react";
-const LINEA_TESTNET_CHAIN = "0xe704";
+import { env } from "@/env.mjs";
+
+const appChainId = getAppChainId();
const switchEthereumChain = async () => {
if (!window.ethereum) return;
await window.ethereum.request({
method: "wallet_switchEthereumChain",
- params: [{ chainId: LINEA_TESTNET_CHAIN }],
+ params: [{ chainId: appChainId }],
});
window.location.reload();
};
export const ConnectWalletButton = () => {
- const [chainId, setChainId] = useState(null);
- const { sdk, connected, connecting, account } = useSDK();
-
- useEffect(() => {
- if (window?.ethereum?.chainId) {
- setChainId(window?.ethereum?.chainId);
- }
- }, []);
-
- const isOnLineaTestnet = chainId === LINEA_TESTNET_CHAIN;
- const isOnLocal = chainId === "0x7a69";
+ const { sdk, connected, connecting, chainId, account } = useSDK();
const connect = async () => {
try {
@@ -59,7 +51,7 @@ export const ConnectWalletButton = () => {
return (
{connected ? (
- isOnLineaTestnet || isOnLocal ? (
+ chainId === appChainId ? (
@@ -81,7 +73,7 @@ export const ConnectWalletButton = () => {
) : (
)
) : (
diff --git a/apps/web/components/create-event/create-event-form.tsx b/apps/web/components/create-event/create-event-form.tsx
index f455a95..4d4747f 100644
--- a/apps/web/components/create-event/create-event-form.tsx
+++ b/apps/web/components/create-event/create-event-form.tsx
@@ -1,12 +1,16 @@
"use client";
-import { useEffect, useState, useTransition } from "react";
+import { useState } from "react";
import { z } from "zod";
import { useRouter } from "next/navigation";
import { useSDK } from "@metamask/sdk-react";
import { useForm } from "react-hook-form";
+import { zodResolver } from "@hookform/resolvers/zod";
import { RotateCw, Plus } from "lucide-react";
-import { parseEther } from "ethers";
+import { ethers, parseEther } from "ethers";
+
+import EventFactoryContract from "lib/contracts/artifacts/EventsFactory.sol/EventsFactory.json";
+import { EventsFactory } from "@/lib/contracts/typechain-types";
import {
Dialog,
@@ -20,39 +24,30 @@ import {
import { Button } from "../ui/Button";
import { Form } from "@/components/ui/form";
-import { getEventFactoryContract } from "@/lib/getEventFactoryContract";
-import { add } from "@/lib/ipfs";
import { formSchema } from "./schema";
-import { ContractPermission, EventSea } from "@/types";
+import { EventSea } from "@/types";
import Step1 from "./step-1";
import Step2 from "./step-2";
import Step3 from "./step-3";
+import { getAppChainId } from "@/lib/utils";
+import { env } from "@/env.mjs";
const NUM_OF_STEPS = 3;
-const LINEA_TESTNET_CHAIN = "0xe704";
const CreateEventForm = () => {
const [step, setStep] = useState(1);
const [open, setOpen] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
- const [isPending, startTransition] = useTransition();
- const [chainId, setChainId] = useState
(null);
- useEffect(() => {
- if (window?.ethereum?.chainId) {
- setChainId(window?.ethereum?.chainId);
- }
- }, []);
+ const appChainId = getAppChainId();
- const { connected } = useSDK();
- const isOnLineaTestnet = chainId === LINEA_TESTNET_CHAIN;
- const isOnLocal = chainId === "0x7a69";
+ const { connected, chainId } = useSDK();
const router = useRouter();
const form = useForm>({
- // resolver: zodResolver(formSchema),
+ resolver: zodResolver(formSchema),
defaultValues: {
title: "",
location: {
@@ -95,9 +90,6 @@ const CreateEventForm = () => {
async function onSubmit(values: z.infer) {
setIsSubmitting(true);
- const eventFactory = await getEventFactoryContract({
- permission: ContractPermission.WRITE,
- });
const {
title,
@@ -110,39 +102,54 @@ const CreateEventForm = () => {
image,
} = values;
- startTransition(async () => {
- const formData = new FormData();
- let imageHash: string | undefined;
+ const formData = new FormData();
+ let imageHash: string | undefined;
- if (image) {
- formData.append("file", image);
- imageHash = await add(formData);
- }
+ if (image) {
+ formData.append("file", image);
+ const response = await fetch('/api/ipfs', {
+ method: "POST",
+ body: formData
+ })
- const ticketPriceInWei = parseEther(ticketPrice.price.toString());
-
- try {
- const resp = await eventFactory.createEvent(
- title,
- description,
- location.placeId,
- type,
- imageHash || "",
- Math.floor(dateTime.getTime() / 1000),
- ticketPriceInWei,
- BigInt(amountOfTickets)
- );
-
- await resp.wait();
- form.reset();
- setIsSubmitting(false);
- router.refresh();
- setOpen((open) => !open);
- } catch (error) {
- console.log(error);
- setIsSubmitting(false);
+ if(response.ok ) {
+ imageHash = (await response.json()).hash
}
- });
+ }
+
+ const ticketPriceInWei = parseEther(ticketPrice.price.toString());
+
+ const provider = new ethers.BrowserProvider(window.ethereum!);
+
+ const signer = await provider.getSigner();
+
+ const eventFactory = new ethers.Contract(
+ env.NEXT_PUBLIC_EVENTS_FACTORY_CONTRACT_ADDRESS,
+ EventFactoryContract.abi,
+ signer
+ ) as unknown as EventsFactory;
+
+ try {
+ const resp = await eventFactory.createEvent(
+ title,
+ description,
+ location.placeId,
+ type,
+ imageHash || "",
+ Math.floor(dateTime.getTime() / 1000),
+ ticketPriceInWei,
+ BigInt(amountOfTickets)
+ );
+
+ await resp.wait();
+ form.reset();
+ setIsSubmitting(false);
+ router.refresh();
+ setOpen((open) => !open);
+ } catch (error) {
+ console.log(error);
+ setIsSubmitting(false);
+ }
}
return (
@@ -155,13 +162,12 @@ const CreateEventForm = () => {
}}
>
- {(connected && isOnLineaTestnet) ||
- (isOnLocal && (
-
- ))}
+ {connected && chainId === appChainId && (
+
+ )}