diff --git a/app/api/moment/comments/route.ts b/app/api/moment/comments/route.ts index 0cec5f55..675faade 100644 --- a/app/api/moment/comments/route.ts +++ b/app/api/moment/comments/route.ts @@ -20,10 +20,10 @@ export async function GET(req: NextRequest) { const { searchParams } = new URL(req.url); const queryParams = { moment: { - contractAddress: searchParams.get("contractAddress") as Address, + collectionAddress: searchParams.get("collectionAddress") as Address, tokenId: searchParams.get("tokenId") || "1", + chainId: Number(searchParams.get("chainId")) || CHAIN_ID, }, - chainId: Number(searchParams.get("chainId")) || CHAIN_ID, offset: Number(searchParams.get("offset")) || 0, }; diff --git a/app/api/moment/route.ts b/app/api/moment/route.ts index 7f243a84..9cf0f81d 100644 --- a/app/api/moment/route.ts +++ b/app/api/moment/route.ts @@ -1,16 +1,16 @@ import { NextRequest, NextResponse } from "next/server"; -import { getAddress } from "viem"; -import getTokenInfo from "@/lib/viem/getTokenInfo"; import { fetchTokenMetadata } from "@/lib/protocolSdk/ipfs/token-metadata"; +import selectAdmins from "@/lib/supabase/in_process_admins/selectAdmins"; +import { getMomentAdvancedInfo } from "@/lib/moment/getMomentAdvancedInfo"; +import { getAddress } from "viem"; import { getMomentSchema } from "@/lib/schema/getMomentSchema"; -import { selectInProcessToken } from "@/lib/supabase/in_process_tokens/selectInProcessToken"; -import { CHAIN_ID } from "@/lib/consts"; +import { Moment } from "@/types/moment"; export async function GET(req: NextRequest) { try { const { searchParams } = new URL(req.url); const queryParams = { - tokenContract: searchParams.get("tokenContract"), + collectionAddress: searchParams.get("collectionAddress"), tokenId: searchParams.get("tokenId"), chainId: searchParams.get("chainId"), }; @@ -27,51 +27,22 @@ export async function GET(req: NextRequest) { ); } - const { tokenContract, tokenId, chainId } = parseResult.data; - const chainIdNum = chainId ? parseInt(chainId, 10) : CHAIN_ID; - - // Get token info from chain - const tokenInfo = await getTokenInfo(getAddress(tokenContract), tokenId, chainIdNum); - - if (!tokenInfo.tokenUri) { - return NextResponse.json({ error: "Token URI not found" }, { status: 404 }); - } - - // Fetch metadata from URI - const metadata = await fetchTokenMetadata(tokenInfo.tokenUri); - - const token = await selectInProcessToken({ - address: getAddress(tokenContract), - chainId: chainIdNum, - }); - - if (!token) { - return NextResponse.json({ error: "Token not found" }, { status: 404 }); - } - - // Validate saleConfig exists and has all required fields - if (!tokenInfo.saleConfig) { - return NextResponse.json( - { error: "Sale configuration not found for this token" }, - { status: 400 } - ); - } - - const { pricePerToken, saleStart, saleEnd, maxTokensPerAddress } = tokenInfo.saleConfig; - - const saleConfig: any = { - ...tokenInfo.saleConfig, - pricePerToken: pricePerToken.toString(), - saleStart: Number(saleStart), - saleEnd: Number(saleEnd), - maxTokensPerAddress: Number(maxTokensPerAddress), + const { collectionAddress, tokenId, chainId } = parseResult.data; + const moment: Moment = { + collectionAddress: getAddress(collectionAddress), + tokenId, + chainId: parseInt(chainId, 10), }; + const { uri, owner, saleConfig } = await getMomentAdvancedInfo(moment); + const metadata = await fetchTokenMetadata(uri || ""); + const admins = await selectAdmins(moment); + return NextResponse.json({ - uri: tokenInfo.tokenUri, - owner: getAddress(tokenInfo.owner), + uri, + owner, saleConfig, - momentAdmins: token.token_admins.map((admin) => admin.artist_address), + momentAdmins: admins.map((admin) => admin.artist_address), metadata: { name: metadata.name || "", image: metadata.image || "", diff --git a/app/api/moment/update-uri/route.ts b/app/api/moment/update-uri/route.ts index b95b6a79..0a300641 100644 --- a/app/api/moment/update-uri/route.ts +++ b/app/api/moment/update-uri/route.ts @@ -4,6 +4,7 @@ import { updateMomentURI } from "@/lib/moment/updateMomentURI"; import { authMiddleware } from "@/middleware/authMiddleware"; import { updateMomentURISchema } from "@/lib/schema/updateMomentURISchema"; import { Address } from "viem"; +import { Moment } from "@/types/moment"; // CORS headers for allowing cross-origin requests const corsHeaders = getCorsHeader(); @@ -37,8 +38,7 @@ export async function POST(req: NextRequest) { } const data = parseResult.data; const result = await updateMomentURI({ - tokenContractAddress: data.moment.contractAddress as Address, - tokenId: data.moment.tokenId, + moment: data.moment as Moment, newUri: data.newUri, artistAddress: artistAddress as Address, }); diff --git a/app/api/og/artist/route.tsx b/app/api/og/artist/route.tsx index e98240c1..3871a3c6 100644 --- a/app/api/og/artist/route.tsx +++ b/app/api/og/artist/route.tsx @@ -38,7 +38,7 @@ export async function GET(req: NextRequest) { let imageMetadata = null; if (metadata) { - if (metadata.content.mime === "text/plain") { + if (metadata.content?.mime === "text/plain") { const response = await fetch(getFetchableUrl(metadata.content.uri) || ""); const data = await response.text(); writingText = data; @@ -85,7 +85,7 @@ export async function GET(req: NextRequest) { > {metadata ? ( <> - {metadata.content.mime === "text/plain" ? ( + {metadata.content?.mime === "text/plain" ? ( ) : ( diff --git a/app/api/og/token/route.tsx b/app/api/og/token/route.tsx index 3f80e531..c324ec55 100644 --- a/app/api/og/token/route.tsx +++ b/app/api/og/token/route.tsx @@ -33,7 +33,7 @@ export async function GET(req: NextRequest) { if (!metadata) throw Error("failed to get token metadata"); const previewBackgroundUrl = getFetchableUrl(metadata.image); - const isWriting = metadata.content.mime === "text/plain"; + const isWriting = metadata.content?.mime === "text/plain"; let orientation = 1; let originalWidth = 1; @@ -43,7 +43,7 @@ export async function GET(req: NextRequest) { let writingText = ""; if (isWriting) { - const response = await fetch(getFetchableUrl(metadata.content.uri) || ""); + const response = await fetch(getFetchableUrl(metadata.content?.uri) || ""); const data = await response.text(); writingText = data; const paragraphs = writingText.split("\n"); diff --git a/components/ArtSlider/CarouselItem.tsx b/components/ArtSlider/CarouselItem.tsx index 8f324e82..2d4d2296 100644 --- a/components/ArtSlider/CarouselItem.tsx +++ b/components/ArtSlider/CarouselItem.tsx @@ -1,12 +1,12 @@ import { getFetchableUrl } from "@/lib/protocolSdk/ipfs/gateway"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import PdfViewer from "../Renderers/PdfViewer"; import VideoPlayer from "../Renderers/VideoPlayer"; import AudioPlayer from "../Renderers/AudioPlayer"; import Writing from "../Renderers/Writing"; interface CarouselItemProps { - metadata: Metadata; + metadata: MomentMetadata; } const CarouselItem = ({ metadata }: CarouselItemProps) => { @@ -38,7 +38,7 @@ const CarouselItem = ({ metadata }: CarouselItemProps) => { return (
diff --git a/components/CollectionManagePage/CollectionOverview.tsx b/components/CollectionManagePage/CollectionOverview.tsx index 8b87c6ab..b52d1b9a 100644 --- a/components/CollectionManagePage/CollectionOverview.tsx +++ b/components/CollectionManagePage/CollectionOverview.tsx @@ -2,7 +2,7 @@ import ContentRenderer from "../Renderers"; import { useCollectionProvider } from "@/providers/CollectionProvider"; import { useRouter } from "next/navigation"; import { Skeleton } from "../ui/skeleton"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { networkConfigByChain } from "@/lib/protocolSdk/apis/chain-constants"; import CopyButton from "../CopyButton"; @@ -39,7 +39,7 @@ const CollectionOverview = () => { {isLoading ? ( ) : ( - + )}
diff --git a/components/CollectionManagePage/TokenOverview.tsx b/components/CollectionManagePage/TokenOverview.tsx index 19b5287b..2a4b7776 100644 --- a/components/CollectionManagePage/TokenOverview.tsx +++ b/components/CollectionManagePage/TokenOverview.tsx @@ -3,11 +3,11 @@ import { useRouter } from "next/navigation"; import { Skeleton } from "../ui/skeleton"; import { networkConfigByChain } from "@/lib/protocolSdk/apis/chain-constants"; import CopyButton from "../CopyButton"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useCollectionProvider } from "@/providers/CollectionProvider"; const TokenOverview = () => { - const { metadata, isLoading } = useTokenProvider(); + const { metadata, isLoading } = useMomentProvider(); const { push } = useRouter(); const { collection } = useCollectionProvider(); diff --git a/components/CreatedMoment/CreatedMomentAirdrop.tsx b/components/CreatedMoment/CreatedMomentAirdrop.tsx index 8c073263..125febbd 100644 --- a/components/CreatedMoment/CreatedMomentAirdrop.tsx +++ b/components/CreatedMoment/CreatedMomentAirdrop.tsx @@ -3,9 +3,9 @@ import { useMomentCreateProvider } from "@/providers/MomentCreateProvider/MomentCreateProvider"; import { Fragment } from "react"; import MomentAirdrop from "../MomentAirdrop"; -import { Address } from "viem"; -import { TokenProvider } from "@/providers/TokenProvider"; +import { MomentProvider } from "@/providers/MomentProvider"; import { CHAIN_ID } from "@/lib/consts"; +import { Address } from "viem"; const CreatedMomentAirdrop = () => { const { createdContract, createdTokenId } = useMomentCreateProvider(); @@ -13,12 +13,15 @@ const CreatedMomentAirdrop = () => { if (!createdContract || !createdTokenId) return ; return ( - - + ); }; diff --git a/components/HorizontalFeed/FeedHover.tsx b/components/HorizontalFeed/FeedHover.tsx index e40a3576..fda8a735 100644 --- a/components/HorizontalFeed/FeedHover.tsx +++ b/components/HorizontalFeed/FeedHover.tsx @@ -1,11 +1,11 @@ import { FC } from "react"; import { Skeleton } from "../ui/skeleton"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import ContentRenderer from "../Renderers/ContentRenderer"; interface FeedHoverProps { isLoading: boolean; - data: Metadata; + data: MomentMetadata; } const FeedHover: FC = ({ isLoading, data }) => { diff --git a/components/Renderers/ContentRenderer.tsx b/components/Renderers/ContentRenderer.tsx index 6368d082..dd4fcf80 100644 --- a/components/Renderers/ContentRenderer.tsx +++ b/components/Renderers/ContentRenderer.tsx @@ -1,6 +1,6 @@ import { getFetchableUrl } from "@/lib/protocolSdk/ipfs/gateway"; import { usePathname } from "next/navigation"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import PdfViewer from "./PdfViewer"; import VideoPlayer from "./VideoPlayer"; import AudioPlayer from "./AudioPlayer"; @@ -8,7 +8,7 @@ import useIsMobile from "@/hooks/useIsMobile"; import Writing from "./Writing"; interface ContentRendererProps { - metadata: Metadata; + metadata: MomentMetadata; } const ContentRenderer = ({ metadata }: ContentRendererProps) => { diff --git a/components/TokenManagePage/AirdropButton.tsx b/components/TokenManagePage/AirdropButton.tsx index 6f1b867a..0d076a30 100644 --- a/components/TokenManagePage/AirdropButton.tsx +++ b/components/TokenManagePage/AirdropButton.tsx @@ -1,11 +1,11 @@ import { AirdropItem } from "@/hooks/useAirdrop"; import { useAirdropProvider } from "@/providers/AirdropProvider"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useUserProvider } from "@/providers/UserProvider"; const AirdropButton = () => { const { airdopToItems, onAirdrop, loading } = useAirdropProvider(); - const { owner, tokenAdmins } = useTokenProvider(); + const { owner, tokenAdmins } = useMomentProvider(); const { connectedAddress, artistWallet } = useUserProvider(); const canAirdrop = Boolean(owner?.toLowerCase() === connectedAddress?.toLowerCase()) || diff --git a/components/TokenManagePage/AnimationUpload.tsx b/components/TokenManagePage/AnimationUpload.tsx index 7be1a37d..929d26a2 100644 --- a/components/TokenManagePage/AnimationUpload.tsx +++ b/components/TokenManagePage/AnimationUpload.tsx @@ -2,13 +2,13 @@ import NoFileSelected from "@/components/MetadataCreation/NoFileSelected"; import MediaUploaded from "@/components/MetadataCreation/MediaUploaded"; import ResetButton from "@/components/MetadataCreation/ResetButton"; import useUpdateMomentURI from "@/hooks/useUpdateMomentURI"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useRef } from "react"; import { useMomentMetadataProvider } from "@/providers/MomentMetadataProvider"; import { useMomentFormProvider } from "@/providers/MomentFormProvider"; const AnimationUpload = () => { - const { isOwner } = useTokenProvider(); + const { isOwner } = useMomentProvider(); const { imageUri, animationUri, setImageUri, setAnimationUri } = useMomentFormProvider(); const { fileUpload, fileUploading } = useMomentMetadataProvider(); const { isLoading: isSaving } = useUpdateMomentURI(); diff --git a/components/TokenManagePage/Media.tsx b/components/TokenManagePage/Media.tsx index 267ad931..321e739e 100644 --- a/components/TokenManagePage/Media.tsx +++ b/components/TokenManagePage/Media.tsx @@ -1,7 +1,7 @@ "use client"; import { Fragment } from "react"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import MediaSkeleton from "./MediaSkeleton"; @@ -13,7 +13,7 @@ import AnimationUpload from "./AnimationUpload"; import { useMomentFormProvider } from "@/providers/MomentFormProvider"; const Media = () => { - const { metadata, isOwner, isLoading } = useTokenProvider(); + const { metadata, isOwner, isLoading } = useMomentProvider(); const { form } = useMomentFormProvider(); const { isLoading: isSaving } = useUpdateMomentURI(); diff --git a/components/TokenManagePage/OwnerWarning.tsx b/components/TokenManagePage/OwnerWarning.tsx index f4a779b9..b6282afe 100644 --- a/components/TokenManagePage/OwnerWarning.tsx +++ b/components/TokenManagePage/OwnerWarning.tsx @@ -1,8 +1,8 @@ "use client"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; const OwnerWarning = () => { - const { isOwner } = useTokenProvider(); + const { isOwner } = useMomentProvider(); if (isOwner) return null; diff --git a/components/TokenManagePage/Sale.tsx b/components/TokenManagePage/Sale.tsx index 17626c01..7a76e87c 100644 --- a/components/TokenManagePage/Sale.tsx +++ b/components/TokenManagePage/Sale.tsx @@ -1,11 +1,11 @@ import useSaleConfig from "@/hooks/useSaleConfig"; import { Fragment } from "react"; import { DateTimePicker } from "../ui/date-time-picker"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; const Sale = () => { const { saleStart, setSaleStart, setSale, isLoading } = useSaleConfig(); - const { saleConfig } = useTokenProvider(); + const { saleConfig } = useMomentProvider(); if (!saleConfig) return ; return ( diff --git a/components/TokenManagePage/SaveMediaButton.tsx b/components/TokenManagePage/SaveMediaButton.tsx index 2f7bf0dc..cf0c6623 100644 --- a/components/TokenManagePage/SaveMediaButton.tsx +++ b/components/TokenManagePage/SaveMediaButton.tsx @@ -1,12 +1,12 @@ "use client"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import useUpdateMomentURI from "@/hooks/useUpdateMomentURI"; import { toast } from "sonner"; import { useFormState } from "react-hook-form"; import { useMomentFormProvider } from "@/providers/MomentFormProvider"; const SaveMediaButton = () => { - const { isOwner } = useTokenProvider(); + const { isOwner } = useMomentProvider(); const { updateTokenURI, isLoading: isSaving } = useUpdateMomentURI(); const { form } = useMomentFormProvider(); const { errors } = useFormState({ control: form.control }); diff --git a/components/TokenManagePage/TokenManagePage.tsx b/components/TokenManagePage/TokenManagePage.tsx index 43920f88..f2170dc5 100644 --- a/components/TokenManagePage/TokenManagePage.tsx +++ b/components/TokenManagePage/TokenManagePage.tsx @@ -5,7 +5,7 @@ import ManageTabs, { MANAGE_TABS } from "./ManageTabs"; import Sale from "./Sale"; import Media from "./Media"; import { useParams } from "next/navigation"; -import { TokenProvider } from "@/providers/TokenProvider"; +import { MomentProvider } from "@/providers/MomentProvider"; import { useCollectionProvider } from "@/providers/CollectionProvider"; import TokenOverview from "../CollectionManagePage/TokenOverview"; import MomentAirdrop from "../MomentAirdrop"; @@ -17,12 +17,12 @@ const TokenManagePage = () => { const tokenId = params.tokenId as string; return ( - { {selectedTab === MANAGE_TABS.SALE && } {selectedTab === MANAGE_TABS.MEDIA && }
- + ); }; diff --git a/components/TokenPage/BackToTimeline.tsx b/components/TokenPage/BackToTimeline.tsx index 37bfe0bb..9f58a175 100644 --- a/components/TokenPage/BackToTimeline.tsx +++ b/components/TokenPage/BackToTimeline.tsx @@ -1,6 +1,6 @@ "use client"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useArtistProfile } from "@/hooks/useArtistProfile"; import truncateAddress from "@/lib/truncateAddress"; import Link from "next/link"; @@ -8,7 +8,7 @@ import { ChevronLeft } from "lucide-react"; import { Skeleton } from "@/components/ui/skeleton"; const BackToTimeline = () => { - const { owner } = useTokenProvider(); + const { owner } = useMomentProvider(); const { data: artistProfile, isLoading } = useArtistProfile(owner || undefined); if (!owner) return null; diff --git a/components/TokenPage/CollectModal.tsx b/components/TokenPage/CollectModal.tsx index 0bf043c5..a8d5f325 100644 --- a/components/TokenPage/CollectModal.tsx +++ b/components/TokenPage/CollectModal.tsx @@ -1,6 +1,6 @@ import { Dialog, DialogContent, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { Label } from "../ui/label"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useMomentCommentsProvider } from "@/providers/MomentCommentsProvider"; import CommentButton from "../CommentButton/CommentButton"; import { Fragment, MouseEvent } from "react"; @@ -16,7 +16,7 @@ import Advanced from "./Advanced"; const CollectModal = () => { const { comment, isOpenCommentModal, setIsOpenCommentModal, setComment } = useMomentCommentsProvider(); - const { saleConfig, isLoading, isSetSale, metadata } = useTokenProvider(); + const { saleConfig, isLoading, isSetSale, metadata } = useMomentProvider(); const { amountToCollect } = useMomentCollectProvider(); const { isPrepared } = useUserProvider(); diff --git a/components/TokenPage/CommentSection.tsx b/components/TokenPage/CommentSection.tsx index 5e5fe90d..051fccec 100644 --- a/components/TokenPage/CommentSection.tsx +++ b/components/TokenPage/CommentSection.tsx @@ -1,4 +1,4 @@ -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import CommentsContainer from "./CommentsContainer"; import { Skeleton } from "../ui/skeleton"; import { Comment } from "./Comment"; @@ -7,7 +7,7 @@ import { useMomentCommentsProvider } from "@/providers/MomentCommentsProvider"; const CommentSection = () => { const { comments, hasMore, isLoading, fetchMore } = useMomentCommentsProvider(); - const { isSetSale } = useTokenProvider(); + const { isSetSale } = useMomentProvider(); if (isLoading) return ( diff --git a/components/TokenPage/MetaAndComments.tsx b/components/TokenPage/MetaAndComments.tsx index 2e5b082f..4826f034 100644 --- a/components/TokenPage/MetaAndComments.tsx +++ b/components/TokenPage/MetaAndComments.tsx @@ -1,4 +1,4 @@ -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { Fragment } from "react"; import { Skeleton } from "../ui/skeleton"; import CommentSection from "./CommentSection"; @@ -16,7 +16,7 @@ interface MetaAndCommentsProps { } const MetaAndComments = ({ priceHidden = false, commentsHidden = false }: MetaAndCommentsProps) => { - const { saleConfig, metadata, isLoading, isSetSale } = useTokenProvider(); + const { saleConfig, metadata, isLoading, isSetSale } = useMomentProvider(); const { balanceOf } = useBalanceOf(); const { download } = useDownload(); diff --git a/components/TokenPage/Token.tsx b/components/TokenPage/Token.tsx index 29310b8a..3b093aa0 100644 --- a/components/TokenPage/Token.tsx +++ b/components/TokenPage/Token.tsx @@ -1,6 +1,6 @@ "use client"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import CollectModal from "./CollectModal"; import MetaAndComments from "./MetaAndComments"; import MomentCollected from "./MomentCollected"; @@ -12,7 +12,7 @@ import MomentAirdrop from "../MomentAirdrop/MomentAirdrop"; import { useMomentCollectProvider } from "@/providers/MomentCollectProvider"; const Token = () => { - const { metadata, isOwner } = useTokenProvider(); + const { metadata, isOwner } = useMomentProvider(); const { collected } = useMomentCollectProvider(); const isMobile = useIsMobile(); diff --git a/components/TokenPage/TokenPage.tsx b/components/TokenPage/TokenPage.tsx index bd54e019..12ce04ed 100644 --- a/components/TokenPage/TokenPage.tsx +++ b/components/TokenPage/TokenPage.tsx @@ -2,7 +2,7 @@ import Token from "./Token"; import { ZORA_TO_VIEM, ZoraChains } from "@/lib/zora/zoraToViem"; -import { TokenProvider } from "@/providers/TokenProvider"; +import { MomentProvider } from "@/providers/MomentProvider"; import { MomentCommentsProvider } from "@/providers/MomentCommentsProvider"; import { MomentCollectProvider } from "@/providers/MomentCollectProvider"; import { useParams } from "next/navigation"; @@ -18,8 +18,8 @@ const TokenPage = () => { const viemChainName = ZORA_TO_VIEM[chain as ZoraChains]; const viemChain = chains[viemChainName]; - const token = { - tokenContractAddress: address as Address, + const moment = { + collectionAddress: address as Address, tokenId, chainId: viemChain.id, }; @@ -27,13 +27,13 @@ const TokenPage = () => { return (
- + - +
); diff --git a/hooks/useAirdrop.ts b/hooks/useAirdrop.ts index 77f9934b..c7b46a7b 100644 --- a/hooks/useAirdrop.ts +++ b/hooks/useAirdrop.ts @@ -8,7 +8,7 @@ import { toast } from "sonner"; import { useSmartWalletProvider } from "@/providers/SmartWalletProvider"; import { usePrivy } from "@privy-io/react-auth"; import { executeAirdrop } from "@/lib/moment/executeAirdrop"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; export interface AirdropItem { address: string; @@ -16,8 +16,8 @@ export interface AirdropItem { ensName: string; } const useAirdrop = () => { - const { token } = useTokenProvider(); - const { tokenContractAddress: momentContract, tokenId } = token; + const { moment } = useMomentProvider(); + const { collectionAddress: momentContract, tokenId } = moment; const [airdopToItems, setAirdropToItems] = useState([]); const { artistWallet, isPrepared } = useUserProvider(); const { smartWallet } = useSmartWalletProvider(); diff --git a/hooks/useBalanceOf.ts b/hooks/useBalanceOf.ts index fde36c45..be403c9f 100644 --- a/hooks/useBalanceOf.ts +++ b/hooks/useBalanceOf.ts @@ -1,5 +1,5 @@ import { getPublicClient } from "@/lib/viem/publicClient"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useUserProvider } from "@/providers/UserProvider"; import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; import { useEffect, useState } from "react"; @@ -7,23 +7,23 @@ import { Address } from "viem"; const useBalanceOf = () => { const [balanceOf, setBalanceOf] = useState(0); - const { token } = useTokenProvider(); + const { moment } = useMomentProvider(); const { connectedAddress } = useUserProvider(); useEffect(() => { const getBalanceOf = async () => { const publicClient = getPublicClient(); const response = await publicClient.readContract({ - address: token.tokenContractAddress as Address, + address: moment.collectionAddress as Address, abi: zoraCreator1155ImplABI, functionName: "balanceOf", - args: [connectedAddress as Address, BigInt(token.tokenId)], + args: [connectedAddress as Address, BigInt(moment.tokenId)], }); setBalanceOf(parseInt(response.toString(), 10)); }; - if (token && connectedAddress) getBalanceOf(); - }, [token, connectedAddress]); + if (moment && connectedAddress) getBalanceOf(); + }, [moment, connectedAddress]); return { balanceOf, diff --git a/hooks/useCollectBalanceValidation.ts b/hooks/useCollectBalanceValidation.ts index 69277c55..1b850420 100644 --- a/hooks/useCollectBalanceValidation.ts +++ b/hooks/useCollectBalanceValidation.ts @@ -1,5 +1,5 @@ import { formatEther, formatUnits } from "viem"; -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; import { SaleConfig } from "@/types/moment"; import { useSmartWalletProvider } from "@/providers/SmartWalletProvider"; import { showInsufficientBalanceError } from "@/lib/balance/showInsufficientBalanceError"; @@ -11,7 +11,7 @@ const useCollectBalanceValidation = () => { const ethPrice = formatEther(saleConfig.pricePerToken * BigInt(mintCount)); const usdcPrice = formatUnits(saleConfig.pricePerToken * BigInt(mintCount), 6); - if (saleConfig.type === MintType.Erc20Mint) { + if (saleConfig.type === MomentType.Erc20Mint) { if (Number(balance) < Number(usdcPrice)) { showInsufficientBalanceError("usdc"); } diff --git a/hooks/useCollection.ts b/hooks/useCollection.ts index 20c84e51..d6117c67 100644 --- a/hooks/useCollection.ts +++ b/hooks/useCollection.ts @@ -1,10 +1,10 @@ import { getPublicClient } from "@/lib/viem/publicClient"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { useQuery } from "@tanstack/react-query"; import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; import { Address } from "viem"; -async function fetchCollectionURI(address: Address, chainId: number): Promise { +async function fetchCollectionURI(address: Address, chainId: number): Promise { const publicClient = getPublicClient(chainId); const uri = await publicClient.readContract({ address, diff --git a/hooks/useComments.ts b/hooks/useComments.ts index 2dd194d5..41c57894 100644 --- a/hooks/useComments.ts +++ b/hooks/useComments.ts @@ -3,24 +3,20 @@ import { useCallback, useMemo } from "react"; import { useInfiniteQuery, useQueryClient, InfiniteData } from "@tanstack/react-query"; import { MintComment } from "@/types/moment"; import fetchComments from "@/lib/moment/fetchComments"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; const COMMENTS_PER_PAGE = 20; export function useComments() { - const { token } = useTokenProvider(); + const { moment } = useMomentProvider(); const queryClient = useQueryClient(); - const { tokenContractAddress: contractAddress, tokenId, chainId } = token; + const { collectionAddress: contractAddress, tokenId, chainId } = moment; const query = useInfiniteQuery({ queryKey: ["comments", contractAddress, tokenId, chainId], queryFn: ({ pageParam = 0 }) => fetchComments({ - moment: { - contractAddress: contractAddress!, - tokenId: tokenId!, - }, - chainId: chainId!, + moment, offset: pageParam as number, }), enabled: Boolean(contractAddress && tokenId && chainId), diff --git a/hooks/useDownload.ts b/hooks/useDownload.ts index 10e2d0b3..c7213292 100644 --- a/hooks/useDownload.ts +++ b/hooks/useDownload.ts @@ -1,9 +1,9 @@ import { getFetchableUrl } from "@/lib/protocolSdk/ipfs/gateway"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useState } from "react"; const useDownload = () => { - const { metadata } = useTokenProvider(); + const { metadata } = useMomentProvider(); const [isDownloading, setIsDownloading] = useState(false); const download = async () => { diff --git a/hooks/useMediaInitialization.ts b/hooks/useMediaInitialization.ts index 85e7f5df..9466e940 100644 --- a/hooks/useMediaInitialization.ts +++ b/hooks/useMediaInitialization.ts @@ -1,8 +1,8 @@ import { useEffect, useRef } from "react"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { useMomentFormProvider } from "@/providers/MomentFormProvider"; -const useMediaInitialization = (meta: Metadata | undefined) => { +const useMediaInitialization = (meta: MomentMetadata | undefined) => { const { name, description, diff --git a/hooks/useMetadata.ts b/hooks/useMetadata.ts index db446e2b..d6433096 100644 --- a/hooks/useMetadata.ts +++ b/hooks/useMetadata.ts @@ -1,8 +1,8 @@ import { getFetchableUrl } from "@/lib/protocolSdk/ipfs/gateway"; -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { useQuery } from "@tanstack/react-query"; -async function fetchMetadata(uri: string): Promise { +async function fetchMetadata(uri: string): Promise { const response = await fetch(`${getFetchableUrl(uri)}`); if (!response.ok) { return { diff --git a/hooks/useTokenInfo.ts b/hooks/useMoment.ts similarity index 79% rename from hooks/useTokenInfo.ts rename to hooks/useMoment.ts index 5025e0cf..abe8e6c1 100644 --- a/hooks/useTokenInfo.ts +++ b/hooks/useMoment.ts @@ -1,16 +1,18 @@ -import { Address, getAddress } from "viem"; +import { getAddress } from "viem"; import { useMemo } from "react"; import { useQuery } from "@tanstack/react-query"; import { useUserProvider } from "@/providers/UserProvider"; import { getMomentApi } from "@/lib/moment/getMomentApi"; +import { Moment } from "@/types/moment"; -const useTokenInfo = (tokenContract: Address, tokenId: string, chainId: number) => { +const useMoment = (moment: Moment) => { + const { collectionAddress, tokenId, chainId } = moment; const { artistWallet } = useUserProvider(); const query = useQuery({ - queryKey: ["tokenInfo", tokenContract, tokenId, chainId], - queryFn: () => getMomentApi(tokenContract, tokenId, chainId), - enabled: Boolean(tokenContract && tokenId && chainId), + queryKey: ["moment", collectionAddress, tokenId, chainId], + queryFn: () => getMomentApi(moment), + enabled: Boolean(collectionAddress && tokenId && chainId), staleTime: 1000 * 60 * 5, // 5 minutes retry: (failureCount) => failureCount < 3, }); @@ -50,4 +52,4 @@ const useTokenInfo = (tokenContract: Address, tokenId: string, chainId: number) }; }; -export default useTokenInfo; +export default useMoment; diff --git a/hooks/useMomentCollect.ts b/hooks/useMomentCollect.ts index 6b39b9e1..5fa4a39a 100644 --- a/hooks/useMomentCollect.ts +++ b/hooks/useMomentCollect.ts @@ -3,7 +3,7 @@ import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; import { zoraCreatorFixedPriceSaleStrategyAddress } from "@/lib/protocolSdk/constants"; import { CHAIN } from "@/lib/consts"; import { Address, encodeAbiParameters, parseAbiParameters } from "viem"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { useUserProvider } from "@/providers/UserProvider"; import { toast } from "sonner"; import useCollectBalanceValidation from "./useCollectBalanceValidation"; @@ -33,7 +33,7 @@ const useMomentCollect = () => { const [collected, setCollected] = useState(false); const { artistWallet } = useUserProvider(); const [isLoading, setIsLoading] = useState(false); - const { token, saleConfig } = useTokenProvider(); + const { saleConfig, moment } = useMomentProvider(); const { comment, addComment, setComment, setIsOpenCommentModal } = useMomentCommentsProvider(); const { validateBalance } = useCollectBalanceValidation(); const { getAccessToken } = usePrivy(); @@ -50,12 +50,12 @@ const useMomentCollect = () => { if (saleConfig.pricePerToken === BigInt(0)) { await mintOnSmartWallet({ - address: token.tokenContractAddress, + address: moment.collectionAddress, abi: zoraCreator1155ImplABI, functionName: "mint", args: [ zoraCreatorFixedPriceSaleStrategyAddress[CHAIN.id], - token.tokenId, + moment.tokenId, amountToCollect, [], minterArguments, @@ -67,15 +67,7 @@ const useMomentCollect = () => { if (!accessToken) { throw new Error("Failed to get access token"); } - await collectMomentApi( - { - contractAddress: token.tokenContractAddress, - tokenId: token.tokenId, - }, - amountToCollect, - comment, - accessToken - ); + await collectMomentApi(moment, amountToCollect, comment, accessToken); } addComment({ sender: artistWallet as Address, diff --git a/hooks/useSaleConfig.ts b/hooks/useSaleConfig.ts index 737103f2..fe34c5d7 100644 --- a/hooks/useSaleConfig.ts +++ b/hooks/useSaleConfig.ts @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { Address, encodeFunctionData } from "viem"; import useSignTransaction from "./useSignTransaction"; import { getPublicClient } from "@/lib/viem/publicClient"; @@ -12,9 +12,9 @@ import { zoraCreatorFixedPriceSaleStrategyAddress } from "@/lib/protocolSdk/cons import { useUserProvider } from "@/providers/UserProvider"; const useSaleConfig = () => { - const { saleConfig: sale } = useTokenProvider(); + const { saleConfig: sale } = useMomentProvider(); const [saleStart, setSaleStart] = useState(new Date()); - const { token, fetchTokenInfo } = useTokenProvider(); + const { moment, fetchTokenInfo } = useMomentProvider(); const { signTransaction } = useSignTransaction(); const { connectedAddress } = useUserProvider(); const [isLoading, setIsLoading] = useState(false); @@ -29,14 +29,14 @@ const useSaleConfig = () => { const calldata = encodeFunctionData({ abi: zoraCreatorFixedPriceSaleStrategyABI, functionName: "setSale", - args: [BigInt(token.tokenId), newSale], + args: [BigInt(moment.tokenId), newSale], }); const publicClient = getPublicClient(CHAIN_ID); const hash = await signTransaction({ - address: token.tokenContractAddress, + address: moment.collectionAddress, abi: zoraCreator1155ImplABI, functionName: "callSale", - args: [token.tokenId, zoraCreatorFixedPriceSaleStrategyAddress[CHAIN_ID], calldata], + args: [moment.tokenId, zoraCreatorFixedPriceSaleStrategyAddress[CHAIN_ID], calldata], account: connectedAddress as Address, chain: CHAIN, }); diff --git a/hooks/useShareMoment.ts b/hooks/useShareMoment.ts index 424fc1ee..ab8f47b9 100644 --- a/hooks/useShareMoment.ts +++ b/hooks/useShareMoment.ts @@ -1,15 +1,15 @@ import { CHAIN, SITE_ORIGINAL_URL } from "@/lib/consts"; import { getShortNetworkName } from "@/lib/zora/zoraToViem"; -import { useTokenProvider } from "@/providers/TokenProvider"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { toast } from "sonner"; const useShareMoment = () => { - const { token } = useTokenProvider(); + const { moment } = useMomentProvider(); const share = async () => { const shortNetworkName = getShortNetworkName(CHAIN.name.toLowerCase()); await navigator.clipboard.writeText( - `${SITE_ORIGINAL_URL}/collect/${shortNetworkName}:${token.tokenContractAddress}/${token.tokenId}` + `${SITE_ORIGINAL_URL}/collect/${shortNetworkName}:${moment.collectionAddress}/${moment.tokenId}` ); toast.success("copied!"); }; diff --git a/hooks/useToken.ts b/hooks/useToken.ts deleted file mode 100644 index cbdb3ea4..00000000 --- a/hooks/useToken.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { getPublicClient } from "@/lib/viem/publicClient"; -import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; -import { Address } from "abitype"; -import { useEffect, useState } from "react"; - -const useToken = (collectionAddress: Address, tokenId: string, chainId: number) => { - const [tokenUri, setTokenUri] = useState(""); - useEffect(() => { - const init = async () => { - const publicClient = getPublicClient(chainId); - const uri = await publicClient.readContract({ - address: collectionAddress, - abi: zoraCreator1155ImplABI, - functionName: "uri", - args: [BigInt(tokenId)], - }); - - setTokenUri(uri as string); - }; - if (collectionAddress && chainId && tokenId) init(); - }, [collectionAddress, chainId, tokenId]); - - return { - tokenUri, - }; -}; - -export default useToken; diff --git a/hooks/useUpdateMomentURI.ts b/hooks/useUpdateMomentURI.ts index 538047a1..1b38d28e 100644 --- a/hooks/useUpdateMomentURI.ts +++ b/hooks/useUpdateMomentURI.ts @@ -1,17 +1,16 @@ import { useState } from "react"; -import { useTokenProvider } from "@/providers/TokenProvider"; -import { CHAIN_ID } from "@/lib/consts"; +import { useMomentProvider } from "@/providers/MomentProvider"; import { usePrivy } from "@privy-io/react-auth"; import { uploadJson } from "@/lib/arweave/uploadJson"; import { fetchTokenMetadata } from "@/lib/protocolSdk/ipfs/token-metadata"; -import getTokenInfo from "@/lib/viem/getTokenInfo"; +import getMomentOnChainInfo from "@/lib/viem/getTokenInfo"; import { toast } from "sonner"; import { callUpdateMomentURI } from "@/lib/moment/callUpdateMomentURI"; import { useMomentFormProvider } from "@/providers/MomentFormProvider"; import { migrateMuxToArweaveApi } from "@/lib/mux/migrateMuxToArweaveApi"; const useUpdateMomentURI = () => { - const { token, fetchTokenInfo } = useTokenProvider(); + const { moment, fetchTokenInfo } = useMomentProvider(); const { name: providerName, description: providerDescription, @@ -27,7 +26,7 @@ const useUpdateMomentURI = () => { const updateTokenURI = async () => { setIsLoading(true); try { - const tokenInfo = await getTokenInfo(token.tokenContractAddress, token.tokenId, CHAIN_ID); + const tokenInfo = await getMomentOnChainInfo(moment); const current = await fetchTokenMetadata(tokenInfo.tokenUri); const updatedAnimationUrl = animationUri || current?.animation_url; @@ -37,17 +36,19 @@ const useUpdateMomentURI = () => { const name = providerName || current?.name; const description = providerDescription || current?.description; + const isImage = mimeType?.includes("image"); + const updated = { ...(current || {}), name, description, image: imageUri || current?.image, - animation_url: updatedAnimationUrl, + animation_url: isImage ? imageUri : updatedAnimationUrl, content: - (updatedContentUri || updatedMimeType) && !updatedMimeType?.includes("image") + updatedContentUri || updatedMimeType ? { mime: updatedMimeType || current?.content?.mime || "", - uri: updatedContentUri || current?.content?.uri || "", + uri: isImage ? imageUri : updatedContentUri || current?.content?.uri || "", } : current?.content, }; @@ -56,7 +57,7 @@ const useUpdateMomentURI = () => { const newUri = await uploadJson(updated); - if (!token?.tokenContractAddress || !token?.tokenId) { + if (!moment?.collectionAddress || !moment?.tokenId) { throw new Error("Missing token context"); } @@ -66,16 +67,15 @@ const useUpdateMomentURI = () => { } await callUpdateMomentURI({ - tokenContractAddress: token.tokenContractAddress, - tokenId: token.tokenId, + moment, newUri, accessToken, }); if (updatedMimeType?.includes("video")) { await migrateMuxToArweaveApi({ - tokenContractAddress: token.tokenContractAddress, - tokenId: token.tokenId, + tokenContractAddress: moment.collectionAddress, + tokenId: moment.tokenId, accessToken, }); resetForm(); diff --git a/lib/fetchArtistLatestMint.ts b/lib/fetchArtistLatestMint.ts index d0c4b74b..55758a45 100644 --- a/lib/fetchArtistLatestMint.ts +++ b/lib/fetchArtistLatestMint.ts @@ -1,11 +1,11 @@ -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { VERCEL_OG } from "./og/consts"; import fetchTokenMetadata from "./fetchTokenMetadata"; const getArtistLatestMint = async ( artistAddress: string, chainId: number -): Promise => { +): Promise => { try { const response = await fetch( `${VERCEL_OG}/api/artist/latest_mint?artistAddress=${artistAddress}&chainId=${chainId}` diff --git a/lib/fetchTokenMetadata.ts b/lib/fetchTokenMetadata.ts index e3fb6270..61d61b5d 100644 --- a/lib/fetchTokenMetadata.ts +++ b/lib/fetchTokenMetadata.ts @@ -1,10 +1,10 @@ -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { VERCEL_OG } from "./og/consts"; const fetchTokenMetadata = async ( tokenContract: string, tokenId: string -): Promise => { +): Promise => { try { const response = await fetch( `${VERCEL_OG}/api/token/metadata?tokenId=${BigInt(tokenId).toString()}&collection=${tokenContract}` diff --git a/lib/getArtistLatestMoment.ts b/lib/getArtistLatestMoment.ts index aadbf3b1..7274e886 100644 --- a/lib/getArtistLatestMoment.ts +++ b/lib/getArtistLatestMoment.ts @@ -1,11 +1,11 @@ -import { Metadata } from "@/types/token"; +import { MomentMetadata } from "@/types/moment"; import { VERCEL_OG } from "./og/consts"; import fetchTokenMetadata from "./fetchTokenMetadata"; const getArtistLatestMoment = async ( artistAddress: string, chainId: number -): Promise => { +): Promise => { try { const response = await fetch( `${VERCEL_OG}/api/collections?artistAddress=${artistAddress}&chainId=${chainId}`, diff --git a/lib/getPrice.ts b/lib/getPrice.ts index 077407bd..f09dc385 100644 --- a/lib/getPrice.ts +++ b/lib/getPrice.ts @@ -1,9 +1,9 @@ -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; import { formatUnits } from "viem"; const getPrice = (pricePerToken: bigint | number | string, type: string | undefined) => { if (!type) return ""; - return formatUnits(BigInt(pricePerToken), type === MintType.Erc20Mint ? 6 : 18); + return formatUnits(BigInt(pricePerToken), type === MomentType.Erc20Mint ? 6 : 18); }; export default getPrice; diff --git a/lib/getPriceUnit.ts b/lib/getPriceUnit.ts index 58334222..726efd3f 100644 --- a/lib/getPriceUnit.ts +++ b/lib/getPriceUnit.ts @@ -1,8 +1,8 @@ -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; const getPriceUnit = (type: string | undefined) => { if (!type) return ""; - return type === MintType.Erc20Mint ? "usdc" : "eth"; + return type === MomentType.Erc20Mint ? "usdc" : "eth"; }; export default getPriceUnit; diff --git a/lib/getSaleConfigType.ts b/lib/getSaleConfigType.ts index fb71dc3b..bf817839 100644 --- a/lib/getSaleConfigType.ts +++ b/lib/getSaleConfigType.ts @@ -1,9 +1,9 @@ -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; const getSaleConfigType = (value: "erc20Mint" | "timed" | "fixedPrice") => { - if (value === "erc20Mint") return MintType.Erc20Mint; - if (value === "timed") return MintType.TimedMint; - return MintType.FixedPriceMint; + if (value === "erc20Mint") return MomentType.Erc20Mint; + if (value === "timed") return MomentType.TimedMint; + return MomentType.FixedPriceMint; }; export default getSaleConfigType; diff --git a/lib/moment/callUpdateMomentURI.ts b/lib/moment/callUpdateMomentURI.ts index 7eb236eb..56ac5399 100644 --- a/lib/moment/callUpdateMomentURI.ts +++ b/lib/moment/callUpdateMomentURI.ts @@ -1,6 +1,7 @@ +import { Moment } from "@/types/moment"; + export interface CallUpdateMomentURIInput { - tokenContractAddress: string; - tokenId: string; + moment: Moment; newUri: string; accessToken: string; } @@ -10,8 +11,7 @@ export interface CallUpdateMomentURIInput { * Handles authentication and error responses. */ export async function callUpdateMomentURI({ - tokenContractAddress, - tokenId, + moment, newUri, accessToken, }: CallUpdateMomentURIInput): Promise { @@ -23,10 +23,7 @@ export async function callUpdateMomentURI({ authorization: `Bearer ${accessToken}`, }, body: JSON.stringify({ - moment: { - contractAddress: tokenContractAddress, - tokenId: tokenId, - }, + moment, newUri, }), }); diff --git a/lib/moment/collectMoment.ts b/lib/moment/collectMoment.ts index 1240a7a9..2fae895e 100644 --- a/lib/moment/collectMoment.ts +++ b/lib/moment/collectMoment.ts @@ -4,10 +4,10 @@ import { CHAIN_ID, IS_TESTNET, USDC_ADDRESS } from "@/lib/consts"; import { sendUserOperation } from "@/lib/coinbase/sendUserOperation"; import { getOrCreateSmartWallet } from "../coinbase/getOrCreateSmartWallet"; import { collectSchema } from "../schema/collectSchema"; -import getTokenInfo from "../viem/getTokenInfo"; +import getMomentOnChainInfo from "../viem/getTokenInfo"; import { distributeSplitFunds } from "../splits/distributeSplitFunds"; import isSplitContract from "../splits/isSplitContract"; -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; import getCollectCall from "../viem/getCollectCall"; import { validateBalanceAndAllowance } from "./validateBalanceAndAllowance"; import { Call } from "@coinbase/coinbase-sdk/dist/types/calls"; @@ -35,17 +35,16 @@ export async function collectMoment({ }); // Get token info and sale config - const { saleConfig } = await getTokenInfo( - moment.contractAddress as Address, - moment.tokenId, - CHAIN_ID - ); + const { saleConfig } = await getMomentOnChainInfo({ + ...moment, + collectionAddress: moment.collectionAddress as Address, + }); const approveCall = await validateBalanceAndAllowance(smartAccount.address, saleConfig, amount); // Get the collect call using the shared function const collectCall = getCollectCall( - moment.contractAddress as Address, + moment.collectionAddress as Address, Number(moment.tokenId), saleConfig, artistAddress, @@ -69,7 +68,7 @@ export async function collectMoment({ if (isSplit) { await distributeSplitFunds({ splitAddress: saleConfig.fundsRecipient, - tokenAddress: saleConfig.type === MintType.Erc20Mint ? USDC_ADDRESS : zeroAddress, // zeroAddress for native ETH + tokenAddress: saleConfig.type === MomentType.Erc20Mint ? USDC_ADDRESS : zeroAddress, // zeroAddress for native ETH smartAccount, }); } diff --git a/lib/moment/collectMomentApi.ts b/lib/moment/collectMomentApi.ts index 8008357d..d7bc2a7c 100644 --- a/lib/moment/collectMomentApi.ts +++ b/lib/moment/collectMomentApi.ts @@ -14,10 +14,7 @@ export const collectMomentApi = async ( Authorization: `Bearer ${accessToken}`, }, body: JSON.stringify({ - moment: { - contractAddress: moment.contractAddress, - tokenId: moment.tokenId, - }, + moment, amount, comment, }), diff --git a/lib/moment/fetchComments.ts b/lib/moment/fetchComments.ts index 1cb1bfe1..a50e10e7 100644 --- a/lib/moment/fetchComments.ts +++ b/lib/moment/fetchComments.ts @@ -1,28 +1,12 @@ -import { - CommentsQueryParams, - MintComment, - MomentCommentsInput, - MomentCommentsResult, -} from "@/types/moment"; +import { MintComment, MomentCommentsInput, MomentCommentsResult } from "@/types/moment"; -async function fetchComments({ - moment, - chainId, - offset, -}: MomentCommentsInput): Promise { +async function fetchComments({ moment, offset }: MomentCommentsInput): Promise { try { - const params: CommentsQueryParams = { - contractAddress: moment.contractAddress, - tokenId: moment.tokenId, - chainId, - offset, - }; - const queryString = new URLSearchParams({ - contractAddress: params.contractAddress, - tokenId: params.tokenId, - chainId: params.chainId.toString(), - offset: params.offset?.toString() || "0", + collectionAddress: moment.collectionAddress.toString(), + tokenId: moment.tokenId, + chainId: moment.chainId.toString(), + offset: offset.toString(), }); const response = await fetch(`/api/moment/comments?${queryString}`); diff --git a/lib/moment/getMomentAdvancedInfo.ts b/lib/moment/getMomentAdvancedInfo.ts new file mode 100644 index 00000000..7bc0b50d --- /dev/null +++ b/lib/moment/getMomentAdvancedInfo.ts @@ -0,0 +1,42 @@ +import { Moment, MomentAdvancedInfo } from "@/types/moment"; +import selectMoment from "@/lib/supabase/in_process_moments/selectMoment"; +import selectSale from "@/lib/supabase/in_process_sales/selectSale"; +import getMomentOnChainInfo from "@/lib/viem/getTokenInfo"; +import { convertDatabaseSaleToApi } from "@/lib/sales/convertDatabaseSaleToApi"; +import { convertOnChainSaleToApi } from "@/lib/sales/convertOnChainSaleToApi"; + +export const getMomentAdvancedInfo = async (moment: Moment): Promise => { + const momentdata = await selectMoment(moment); + + if (momentdata) { + const uri = momentdata.uri; + const owner = momentdata.collection.default_admin; + const sale = await selectSale(momentdata.id); + + if (sale) { + return { + uri, + owner, + saleConfig: convertDatabaseSaleToApi(sale), + }; + } + + const { saleConfig: onChainSale } = await getMomentOnChainInfo(moment); + return { + uri, + owner, + saleConfig: convertOnChainSaleToApi(onChainSale), + }; + } + + const { + saleConfig: onChainSale, + owner: tokenOwner, + tokenUri, + } = await getMomentOnChainInfo(moment); + return { + uri: tokenUri, + owner: tokenOwner as string, + saleConfig: convertOnChainSaleToApi(onChainSale), + }; +}; diff --git a/lib/moment/getMomentApi.ts b/lib/moment/getMomentApi.ts index 66ccc1ac..0b62e69e 100644 --- a/lib/moment/getMomentApi.ts +++ b/lib/moment/getMomentApi.ts @@ -1,10 +1,10 @@ -import { Address } from "viem"; +import { Moment } from "@/types/moment"; -export const getMomentApi = async (tokenContract: Address, tokenId: string, chainId: number) => { +export const getMomentApi = async (moment: Moment) => { const params = new URLSearchParams({ - tokenContract, - tokenId, - chainId: String(chainId), + collectionAddress: moment.collectionAddress.toString(), + tokenId: moment.tokenId, + chainId: moment.chainId.toString(), }); const res = await fetch(`/api/moment?${params.toString()}`); if (!res.ok) { diff --git a/lib/moment/indexMoment.ts b/lib/moment/indexMoment.ts index d06e3ae7..071bea4d 100644 --- a/lib/moment/indexMoment.ts +++ b/lib/moment/indexMoment.ts @@ -2,11 +2,15 @@ import { Address } from "viem"; import { getInProcessTokens } from "@/lib/supabase/in_process_tokens/getInProcessTokens"; import { updateInProcessTokens } from "@/lib/supabase/in_process_tokens/updateInProcessTokens"; import { insertInProcessTokens } from "@/lib/supabase/in_process_tokens/insertInProcessTokens"; -import getTokenInfo from "../viem/getTokenInfo"; +import getMomentOnChainInfo from "../viem/getTokenInfo"; const indexMoment = async (address: Address, tokenId: number, chainId: number) => { // Fetch onchain details - const { tokenUri: uri, owner: admin } = await getTokenInfo(address, tokenId.toString(), chainId); + const { tokenUri: uri, owner: admin } = await getMomentOnChainInfo({ + collectionAddress: address, + tokenId: tokenId.toString(), + chainId, + }); // Look for existing moment const { data: existingRows, error: fetchError } = await getInProcessTokens({ diff --git a/lib/moment/momentComments.ts b/lib/moment/momentComments.ts index d7cc4092..c778186f 100644 --- a/lib/moment/momentComments.ts +++ b/lib/moment/momentComments.ts @@ -1,6 +1,6 @@ import { z } from "zod"; import { commentsSchema } from "../schema/commentsSchema"; -import selectMoments from "../supabase/in_process_moments/selectMoments"; +import selectMoment from "../supabase/in_process_moments/selectMoment"; import { Address } from "viem"; import selectComments from "../supabase/in_process_moment_comments/selectComments"; import { MomentCommentsResult } from "@/types/moment"; @@ -9,23 +9,20 @@ export type GetCommentsInput = z.infer; export async function momentComments({ moment, - chainId, offset, }: GetCommentsInput): Promise { - const data = await selectMoments({ - collectionAddress: moment.contractAddress as Address, + const momentdata = await selectMoment({ + collectionAddress: moment.collectionAddress as Address, tokenId: moment.tokenId, - chainId, + chainId: moment.chainId, }); - const momentData = data[0]; - - if (!momentData) { + if (!momentdata) { throw new Error("Moment not found"); } const comments = await selectComments({ - momentId: momentData.id, + momentId: momentdata.id, offset, }); diff --git a/lib/moment/updateMomentURI.ts b/lib/moment/updateMomentURI.ts index 1a974198..ccb53b38 100644 --- a/lib/moment/updateMomentURI.ts +++ b/lib/moment/updateMomentURI.ts @@ -3,10 +3,10 @@ import { CHAIN_ID, IS_TESTNET } from "@/lib/consts"; import { sendUserOperation } from "@/lib/coinbase/sendUserOperation"; import getUpdateTokenURICall from "@/lib/viem/getUpdateTokenURICall"; import { getOrCreateSmartWallet } from "@/lib/coinbase/getOrCreateSmartWallet"; +import { Moment } from "@/types/moment"; export interface UpdateMomentURIInput { - tokenContractAddress: Address; - tokenId: string; + moment: Moment; newUri: string; artistAddress: Address; } @@ -21,8 +21,7 @@ export interface UpdateMomentURIResult { * Handles the transaction on the backend side. */ export async function updateMomentURI({ - tokenContractAddress, - tokenId, + moment, newUri, artistAddress, }: UpdateMomentURIInput): Promise { @@ -30,7 +29,11 @@ export async function updateMomentURI({ address: artistAddress, }); - const updateTokenURICall = getUpdateTokenURICall(tokenContractAddress, tokenId, newUri); + const updateTokenURICall = getUpdateTokenURICall( + moment.collectionAddress, + moment.tokenId, + newUri + ); // Send the transaction and wait for receipt using the helper const transaction = await sendUserOperation({ diff --git a/lib/moment/validateBalanceAndAllowance.ts b/lib/moment/validateBalanceAndAllowance.ts index 1ae9de7f..b518435f 100644 --- a/lib/moment/validateBalanceAndAllowance.ts +++ b/lib/moment/validateBalanceAndAllowance.ts @@ -6,7 +6,7 @@ import getUsdcBalance from "@/lib/balance/getUsdcBalance"; import getEthBalance from "@/lib/balance/getEthBalance"; import getAllowance from "@/lib/viem/getAllowance"; import getApproveCall from "@/lib/viem/getApproveCall"; -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; /** * Validates balance and checks allowance for moment collection. @@ -18,7 +18,7 @@ export async function validateBalanceAndAllowance( amount: number ) { const approveCall = []; - const isErc20Mint = saleConfig.type === MintType.Erc20Mint; + const isErc20Mint = saleConfig.type === MomentType.Erc20Mint; if (isErc20Mint) { const pricePerToken = formatUnits(saleConfig.pricePerToken, 6); diff --git a/lib/mux/migrateMuxToArweave.ts b/lib/mux/migrateMuxToArweave.ts index 3fd50e55..6baad776 100644 --- a/lib/mux/migrateMuxToArweave.ts +++ b/lib/mux/migrateMuxToArweave.ts @@ -3,7 +3,7 @@ import { downloadVideoFromMux } from "@/lib/mux/downloadVideoFromMux"; import { deleteMuxAsset } from "@/lib/mux/deleteMuxAsset"; import { findMuxAssetIdFromPlaybackUrl } from "@/lib/mux/findMuxAssetIdFromPlaybackUrl"; import { fetchTokenMetadata } from "@/lib/protocolSdk/ipfs/token-metadata"; -import getTokenInfo from "@/lib/viem/getTokenInfo"; +import getMomentOnChainInfo from "@/lib/viem/getTokenInfo"; import getUpdateTokenURICall from "@/lib/viem/getUpdateTokenURICall"; import getUpdateContractMetadataCall from "@/lib/viem/getUpdateContractMetadataCall"; import { CHAIN_ID, IS_TESTNET } from "@/lib/consts"; @@ -44,7 +44,11 @@ export async function migrateMuxToArweave({ }: MigrateMuxToArweaveInput): Promise { try { // Step 1: Get token info using viem and fetch metadata from IPFS - const tokenInfo = await getTokenInfo(tokenContractAddress, tokenId, CHAIN_ID); + const tokenInfo = await getMomentOnChainInfo({ + collectionAddress: tokenContractAddress, + tokenId, + chainId: CHAIN_ID, + }); const currentMetadata = await fetchTokenMetadata(tokenInfo.tokenUri); if (!currentMetadata) { diff --git a/lib/sales/convertDatabaseSaleToApi.ts b/lib/sales/convertDatabaseSaleToApi.ts new file mode 100644 index 00000000..f7c26657 --- /dev/null +++ b/lib/sales/convertDatabaseSaleToApi.ts @@ -0,0 +1,15 @@ +import { Address, zeroAddress } from "viem"; +import { MomentType, MomentApiSaleConfig } from "@/types/moment"; +import { DatabaseSale } from "@/types/sale"; + +export const convertDatabaseSaleToApi = (sale: DatabaseSale): MomentApiSaleConfig => ({ + pricePerToken: sale.price_per_token.toString(), + saleStart: Number(sale.sale_start), + saleEnd: Number(sale.sale_end), + maxTokensPerAddress: Number(sale.max_tokens_per_address), + fundsRecipient: sale.funds_recipient as Address, + type: + sale.currency.toLowerCase() === zeroAddress.toLowerCase() + ? MomentType.FixedPriceMint + : MomentType.Erc20Mint, +}); diff --git a/lib/sales/convertOnChainSaleToApi.ts b/lib/sales/convertOnChainSaleToApi.ts new file mode 100644 index 00000000..776c7998 --- /dev/null +++ b/lib/sales/convertOnChainSaleToApi.ts @@ -0,0 +1,11 @@ +import { MomentApiSaleConfig } from "@/types/moment"; +import { OnChainSaleConfig } from "@/types/sale"; + +export const convertOnChainSaleToApi = (sale: OnChainSaleConfig): MomentApiSaleConfig => ({ + pricePerToken: sale.pricePerToken.toString(), + saleStart: Number(sale.saleStart), + saleEnd: Number(sale.saleEnd), + maxTokensPerAddress: Number(sale.maxTokensPerAddress), + fundsRecipient: sale.fundsRecipient, + type: sale.type, +}); diff --git a/lib/schema/collectSchema.ts b/lib/schema/collectSchema.ts index d2c8e1d0..b189b801 100644 --- a/lib/schema/collectSchema.ts +++ b/lib/schema/collectSchema.ts @@ -1,9 +1,11 @@ import { z } from "zod"; import addressSchema from "./addressSchema"; +import { CHAIN_ID } from "../consts"; export const momentSchema = z.object({ tokenId: z.string(), - contractAddress: addressSchema, + collectionAddress: addressSchema, + chainId: z.number().optional().default(CHAIN_ID), }); export const collectSchema = z.object({ diff --git a/lib/schema/commentsSchema.ts b/lib/schema/commentsSchema.ts index 89abf761..453b8071 100644 --- a/lib/schema/commentsSchema.ts +++ b/lib/schema/commentsSchema.ts @@ -1,13 +1,14 @@ import { z } from "zod"; import addressSchema from "./addressSchema"; +import { CHAIN_ID } from "../consts"; export const momentSchema = z.object({ tokenId: z.string(), - contractAddress: addressSchema, + collectionAddress: addressSchema, + chainId: z.number().optional().default(CHAIN_ID), }); export const commentsSchema = z.object({ moment: momentSchema, - chainId: z.number(), offset: z.number(), }); diff --git a/lib/schema/getMomentSchema.ts b/lib/schema/getMomentSchema.ts index f7195d1f..32a6aa56 100644 --- a/lib/schema/getMomentSchema.ts +++ b/lib/schema/getMomentSchema.ts @@ -1,13 +1,15 @@ import { z } from "zod"; import addressSchema from "./addressSchema"; +import { CHAIN_ID } from "../consts"; export const getMomentSchema = z.object({ - tokenContract: addressSchema, + collectionAddress: addressSchema, tokenId: z.string().min(1, "Token ID is required"), chainId: z .string() .optional() .refine((val) => !val || !isNaN(parseInt(val, 10)), { message: "Chain ID must be a valid number", - }), + }) + .default(CHAIN_ID.toString()), }); diff --git a/lib/supabase/in_process_admins/selectAdmins.ts b/lib/supabase/in_process_admins/selectAdmins.ts new file mode 100644 index 00000000..dae80ddd --- /dev/null +++ b/lib/supabase/in_process_admins/selectAdmins.ts @@ -0,0 +1,14 @@ +import { Moment } from "@/types/moment"; +import { supabase } from "../client"; + +const selectAdmins = async (moment: Moment) => { + const { data, error } = await supabase + .from("in_process_admins") + .select("*") + .eq("collection", moment.collectionAddress) + .or(`token_id.in.(0,${moment.tokenId})`); + if (error) return []; + return data || []; +}; + +export default selectAdmins; diff --git a/lib/supabase/in_process_moments/selectMoments.ts b/lib/supabase/in_process_moments/selectMoment.ts similarity index 60% rename from lib/supabase/in_process_moments/selectMoments.ts rename to lib/supabase/in_process_moments/selectMoment.ts index 288be188..82150e4e 100644 --- a/lib/supabase/in_process_moments/selectMoments.ts +++ b/lib/supabase/in_process_moments/selectMoment.ts @@ -1,15 +1,8 @@ -import { Address } from "viem"; import { supabase } from "../client"; +import { Moment } from "@/types/moment"; -const selectMoments = async ({ - collectionAddress, - tokenId, - chainId, -}: { - collectionAddress: Address; - tokenId: string; - chainId: number; -}) => { +const selectMoment = async (moment: Moment) => { + const { collectionAddress, tokenId, chainId } = moment; let query = supabase .from("in_process_moments") .select("*, collection:in_process_collections!inner(*)"); @@ -24,9 +17,9 @@ const selectMoments = async ({ query = query.eq("token_id", Number(tokenId)); } - const { data, error } = await query; - if (error) throw error; + const { data, error } = await query.single(); + if (error) return null; return data; }; -export default selectMoments; +export default selectMoment; diff --git a/lib/supabase/in_process_sales/selectSale.ts b/lib/supabase/in_process_sales/selectSale.ts new file mode 100644 index 00000000..e4405d7d --- /dev/null +++ b/lib/supabase/in_process_sales/selectSale.ts @@ -0,0 +1,13 @@ +import { supabase } from "../client"; + +const selectSale = async (momentId: string) => { + const { data, error } = await supabase + .from("in_process_sales") + .select("*") + .eq("moment", momentId) + .single(); + if (error) return null; + return data; +}; + +export default selectSale; diff --git a/lib/supabase/in_process_tokens/selectInProcessToken.ts b/lib/supabase/in_process_tokens/selectInProcessToken.ts deleted file mode 100644 index 2aa59957..00000000 --- a/lib/supabase/in_process_tokens/selectInProcessToken.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { supabase } from "@/lib/supabase/client"; - -/** - * Fetches tokens from the "in_process_tokens" table. - * @param filters Optional filters to apply (e.g. by artist address, chainId, etc). - * @returns Array of token rows, or throws on error. - */ -export async function selectInProcessToken({ - address, - chainId, -}: { - chainId?: number; - address?: string; -}) { - let query = supabase - .from("in_process_tokens") - .select("*, token_admins:in_process_token_admins(*)"); - - if (address) { - query = query.eq("address", address.toLowerCase()); - } - - if (chainId !== undefined) { - query = query.eq("chainId", chainId); - } - - const { data, error } = await query.single(); - if (error) { - throw error; - } - return data; -} diff --git a/lib/viem/getCollectCall.ts b/lib/viem/getCollectCall.ts index 9b5320e0..9364d0c2 100644 --- a/lib/viem/getCollectCall.ts +++ b/lib/viem/getCollectCall.ts @@ -2,7 +2,7 @@ import { SaleConfig } from "@/types/moment"; import { erc20MinterABI, zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; import { Address, encodeAbiParameters, encodeFunctionData, parseAbiParameters } from "viem"; import { CHAIN_ID, USDC_ADDRESS } from "../consts"; -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; import { erc20MinterAddresses, zoraCreatorFixedPriceSaleStrategyAddress, @@ -22,7 +22,7 @@ const getCollectCall = ( ]); const totalPrice = sale.pricePerToken * BigInt(amount); - if (sale.type === MintType.Erc20Mint) { + if (sale.type === MomentType.Erc20Mint) { return { to: erc20MinterAddresses[CHAIN_ID], data: encodeFunctionData({ diff --git a/lib/viem/getNextTokenIds.ts b/lib/viem/getNextTokenIds.ts deleted file mode 100644 index 61f4816b..00000000 --- a/lib/viem/getNextTokenIds.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { getPublicClient } from "./publicClient"; -import { zoraCreator1155ImplABI } from "@zoralabs/protocol-deployments"; -import { Collection } from "@/types/token"; - -export type CollectionAndNextTokenId = Collection & { - nextTokenId: number; -}; - -const getNextTokenIds = async (collections: Collection[]) => { - const groupedFeedByNetwork = collections.reduce( - (acc: { [network: string]: Collection[] }, item: Collection) => { - const network = item.chainId; - if (!acc[network]) { - acc[network] = []; - } - acc[network].push(item); - return acc; - }, - {} - ); - - const promise = Object.entries(groupedFeedByNetwork).map(async ([chainId, collections]) => { - const publicClient = getPublicClient(parseInt(chainId, 10)); - const calls = collections.map((c: Collection) => ({ - address: c.newContract, - abi: zoraCreator1155ImplABI, - functionName: "nextTokenId", - })); - const returnValues = await publicClient.multicall({ - contracts: calls as any, - }); - return collections.map((c: Collection, i) => ({ - ...c, - nextTokenId: Number(returnValues[i].result as bigint), - })); - }); - const result = await Promise.all(promise); - return result.flat() as CollectionAndNextTokenId[]; -}; - -export default getNextTokenIds; diff --git a/lib/viem/getTokenInfo.ts b/lib/viem/getTokenInfo.ts index b6565cae..119015c9 100644 --- a/lib/viem/getTokenInfo.ts +++ b/lib/viem/getTokenInfo.ts @@ -1,5 +1,4 @@ import { getPublicClient } from "@/lib/viem/publicClient"; -import { CHAIN_ID } from "@/lib/consts"; import { erc20MinterAddresses, zoraCreatorFixedPriceSaleStrategyAddress, @@ -9,20 +8,17 @@ import { zoraCreator1155ImplABI, zoraCreatorFixedPriceSaleStrategyABI, } from "@zoralabs/protocol-deployments"; -import { Address } from "viem"; -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; +import { Moment } from "@/types/moment"; -const getTokenInfo = async ( - tokenContract: Address, - tokenId: string, - chainId: number = CHAIN_ID -) => { +const getMomentOnChainInfo = async (moment: Moment) => { + const { collectionAddress, tokenId, chainId } = moment; const publicClient: any = getPublicClient(chainId); const erc20SaleConfigCall = { address: erc20MinterAddresses[chainId as keyof typeof erc20MinterAddresses], abi: erc20MinterABI, functionName: "sale", - args: [tokenContract, tokenId], + args: [collectionAddress, tokenId], }; const fixedSaleConfigCall = { address: @@ -31,16 +27,16 @@ const getTokenInfo = async ( ], abi: zoraCreatorFixedPriceSaleStrategyABI, functionName: "sale", - args: [tokenContract, tokenId], + args: [collectionAddress, tokenId], }; const uriCall = { - address: tokenContract, + address: collectionAddress, abi: zoraCreator1155ImplABI, functionName: "uri", args: [tokenId], }; const ownerCall = { - address: tokenContract, + address: collectionAddress, abi: zoraCreator1155ImplABI, functionName: "owner", args: [], @@ -54,11 +50,11 @@ const getTokenInfo = async ( infoCalls[0]?.result?.saleEnd > BigInt(0) ? { ...infoCalls[0]?.result, - type: MintType.Erc20Mint, + type: MomentType.Erc20Mint, } : { ...infoCalls[1]?.result, - type: MintType.FixedPriceMint, + type: MomentType.FixedPriceMint, }; return { @@ -68,4 +64,4 @@ const getTokenInfo = async ( }; }; -export default getTokenInfo; +export default getMomentOnChainInfo; diff --git a/lib/zora/getSalesConfig.tsx b/lib/zora/getSalesConfig.tsx index a138b75f..f157c10d 100644 --- a/lib/zora/getSalesConfig.tsx +++ b/lib/zora/getSalesConfig.tsx @@ -1,7 +1,7 @@ import { TimedSaleParamsType } from "@/lib/protocolSdk"; import { maxUint64, parseEther, parseUnits } from "viem"; import { USDC_ADDRESS } from "../consts"; -import { MintType } from "@/types/zora"; +import { MomentType } from "@/types/moment"; const getSalesConfig = (saleStrategy: string, price: string, saleStart: Date | undefined) => { const timedSaleConfig = { @@ -30,11 +30,11 @@ const getSalesConfig = (saleStrategy: string, price: string, saleStart: Date | u if (price === "0") return fixedPriceSaleConfig; switch (saleStrategy) { - case MintType.FixedPriceMint: + case MomentType.FixedPriceMint: return fixedPriceSaleConfig; - case MintType.TimedMint: + case MomentType.TimedMint: return timedSaleConfig; - case MintType.Erc20Mint: + case MomentType.Erc20Mint: return erc20MintSaleConfig; default: return erc20MintSaleConfig; diff --git a/providers/MomentProvider.tsx b/providers/MomentProvider.tsx new file mode 100644 index 00000000..3c507ad7 --- /dev/null +++ b/providers/MomentProvider.tsx @@ -0,0 +1,34 @@ +import { createContext, useContext, ReactNode } from "react"; +import { Moment } from "@/types/moment"; +import useMoment from "@/hooks/useMoment"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const MomentContext = createContext< + | (ReturnType & { + moment: Moment; + }) + | undefined +>(undefined); + +export function MomentProvider({ children, moment }: { children: ReactNode; moment: Moment }) { + const momentData = useMoment(moment); + + return ( + + {children} + + ); +} + +export function useMomentProvider() { + const context = useContext(MomentContext); + if (context === undefined) { + throw new Error("useMomentProvider must be used within a MomentProvider"); + } + return context; +} diff --git a/providers/TokenProvider.tsx b/providers/TokenProvider.tsx deleted file mode 100644 index dca4c8f1..00000000 --- a/providers/TokenProvider.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import useTokenInfo from "@/hooks/useTokenInfo"; -import { TokenInfo } from "@/types/token"; -import { createContext, useContext, ReactNode } from "react"; - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const TokenContext = createContext< - | (ReturnType & { - token: TokenInfo; - }) - | undefined ->(undefined); - -export function TokenProvider({ - children, - token, - chainId, -}: { - children: ReactNode; - token: TokenInfo; - chainId: number; -}) { - const tokenInfo = useTokenInfo(token.tokenContractAddress, token.tokenId, chainId); - - return ( - - {children} - - ); -} - -export function useTokenProvider() { - const context = useContext(TokenContext); - if (context === undefined) { - throw new Error("useTokenProvider must be used within a TokenProvider"); - } - return context; -} diff --git a/types/dune.ts b/types/dune.ts deleted file mode 100644 index d05a7e14..00000000 --- a/types/dune.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Address } from "viem"; - -export type DuneDecoded = { - name: string; - inputs: Array<{ - name: string; - type: string; - value: string | Array; - }>; -}; - -export type DuneDecodedEvent = { - chain: string; - chain_id: number; - address: Address; - block_time: string; - block_number: number; - index: number; - hash: string; - block_hash: string; - value: string; - transaction_type: "Sender" | "Receiver"; - from: Address; - to: Address; - nonce: string; - gas_price: string; - gas_used: string; - effective_gas_price: string; - success: boolean; - data: string; - decoded: DuneDecoded; - logs: Array<{ - address: Address; - data: string; - topics: Array; - decoded?: DuneDecoded; - }>; -}; diff --git a/types/fetch-collections.ts b/types/fetch-collections.ts deleted file mode 100644 index 9fc54bf3..00000000 --- a/types/fetch-collections.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Collection } from "./token"; - -export interface CollectionsOffset { - factory?: string; - smartWallet?: string; -} -export interface CollectionsResponse { - collections: Collection[]; - nextOffsets: CollectionsOffset; - artistAddress?: string; -} - -export interface PageParam { - offsets: CollectionsOffset | undefined; - artistAddress: string | undefined; -} diff --git a/types/jam.ts b/types/jam.ts deleted file mode 100644 index 448c09e9..00000000 --- a/types/jam.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface CustomData { - label: string; - isEditing: boolean; - color: string; -} diff --git a/types/moment.ts b/types/moment.ts index bbe0d745..1f4afadc 100644 --- a/types/moment.ts +++ b/types/moment.ts @@ -2,13 +2,13 @@ import { Address } from "viem"; import type { Database } from "@/lib/supabase/types"; export interface Moment { - contractAddress: Address; + collectionAddress: Address; tokenId: string; + chainId: number; } export interface MomentCommentsInput { moment: Moment; - chainId: number; offset: number; } @@ -58,3 +58,44 @@ export type SaleConfig = { fundsRecipient: Address; type: string; }; + +export interface MomentMetadata { + image: string; + name: string; + description: string; + external_url?: string; + content?: { + mime: string; + uri: string; + } | null; + animation_url?: string; +} + +export enum MomentType { + Erc20Mint = "erc20Mint", + TimedMint = "timed", + FixedPriceMint = "fixedPrice", +} + +export type MomentApiSaleConfig = { + pricePerToken: string; + saleStart: number; + saleEnd: number; + maxTokensPerAddress: number; + fundsRecipient: Address; + type: MomentType; +}; + +export type MomentResponse = { + uri: string | null; + owner: string | null; + saleConfig: MomentApiSaleConfig | null; + momentAdmins: string[]; + metadata: MomentMetadata; +}; + +export type MomentAdvancedInfo = { + uri: string | null; + owner: string | null; + saleConfig: MomentApiSaleConfig | null; +}; diff --git a/types/sale.ts b/types/sale.ts new file mode 100644 index 00000000..952245df --- /dev/null +++ b/types/sale.ts @@ -0,0 +1,20 @@ +import { Address } from "viem"; +import { MomentType } from "@/types/moment"; + +export type OnChainSaleConfig = { + pricePerToken: bigint; + saleStart: bigint; + saleEnd: bigint; + maxTokensPerAddress: bigint; + fundsRecipient: Address; + type: MomentType; +}; + +export type DatabaseSale = { + price_per_token: number; + sale_start: number; + sale_end: number; + max_tokens_per_address: number; + funds_recipient: string; + currency: string; +}; diff --git a/types/token.ts b/types/token.ts deleted file mode 100644 index e4bd75cb..00000000 --- a/types/token.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Address } from "viem"; - -export interface TokenMetadata { - name?: string; - description?: string; - image?: string; - content?: { - mime: string; - uri: string; - }; - canvas_url?: string; -} - -export interface TokenInfo { - tokenId: string; - tokenContractAddress: Address; - chainId?: number; -} - -export interface Metadata { - image: string; - name: string; - description: string; - external_url?: string; - content: { - mime: string; - uri: string; - }; - animation_url?: string; -} - -export interface Collection { - contractURI: string; - creator: Address; - defaultAdmin: Address; - defaultRoyaltyConfiguration: [string, string, string]; - name: string; - newContract: Address; - released_at: number; - chain: string; - chainId: number; -} diff --git a/types/zora.ts b/types/zora.ts deleted file mode 100644 index d1f7d381..00000000 --- a/types/zora.ts +++ /dev/null @@ -1,41 +0,0 @@ -export interface CollectionStyle { - theme: { - color: { - background: string; - text: string; - accent: string; - accentText: string; - border: string; - }; - font: { - heading: { - fontFamily: string; - fontSize: string; - lineHeight: string; - }; - body: { - fontFamily: string; - fontSize: string; - lineHeight: string; - }; - caption: { - fontFamily: string; - fontSize: string; - lineHeight: string; - }; - }; - button: { - shape: string; - }; - }; - unit: { - radius: string; - base: string; - }; -} - -export enum MintType { - Erc20Mint = "erc20Mint", - TimedMint = "timed", - FixedPriceMint = "fixedPrice", -}