From c806bbd34ef667ebb04532212d63eba5441bc623 Mon Sep 17 00:00:00 2001 From: Jip Stavenuiter Date: Fri, 15 Mar 2024 12:35:49 -0600 Subject: [PATCH] (fix): check if all fractions exist and check if signer is owner of all fractions when creating order (#41) --- .../useCreateFractionalMakerAsk.ts | 60 +++++++++---------- pages/api/marketplace/order.ts | 51 +++++++++++++++- 2 files changed, 78 insertions(+), 33 deletions(-) diff --git a/hooks/marketplace/useCreateFractionalMakerAsk.ts b/hooks/marketplace/useCreateFractionalMakerAsk.ts index c0bbc0f..6f01799 100644 --- a/hooks/marketplace/useCreateFractionalMakerAsk.ts +++ b/hooks/marketplace/useCreateFractionalMakerAsk.ts @@ -51,6 +51,36 @@ export const useCreateFractionalMakerAsk = ({ throw new Error("Fractions not found"); } + if (!provider) { + throw new Error("Provider not initialized"); + } + + if (!signer) { + throw new Error("Signer not initialized"); + } + + const [contractAddress, tokenId] = values.fractionId.split("-"); + + if (!contractAddress || !isAddress(contractAddress)) { + throw new Error("Invalid contract address"); + } + + let tokenIdBigInt: BigInt | undefined; + try { + tokenIdBigInt = BigInt(tokenId); + } catch (e) { + console.error(e); + throw new Error("Error parsing token ID"); + } + + if (!tokenIdBigInt) { + throw new Error("Invalid token ID"); + } + + if (!walletClientData) { + throw new Error("Wallet client not initialized"); + } + onOpen([ { title: "Splitting", @@ -82,36 +112,6 @@ export const useCreateFractionalMakerAsk = ({ }, ]); - if (!provider) { - throw new Error("Provider not initialized"); - } - - if (!signer) { - throw new Error("Signer not initialized"); - } - - const [contractAddress, tokenId] = values.fractionId.split("-"); - - if (!contractAddress || !isAddress(contractAddress)) { - throw new Error("Invalid contract address"); - } - - let tokenIdBigInt: BigInt | undefined; - try { - tokenIdBigInt = BigInt(tokenId); - } catch (e) { - console.error(e); - throw new Error("Error parsing token ID"); - } - - if (!tokenIdBigInt) { - throw new Error("Invalid token ID"); - } - - if (!walletClientData) { - throw new Error("Wallet client not initialized"); - } - let signature: string | undefined; setStep("Create"); diff --git a/pages/api/marketplace/order.ts b/pages/api/marketplace/order.ts index 99690b8..260c562 100644 --- a/pages/api/marketplace/order.ts +++ b/pages/api/marketplace/order.ts @@ -1,6 +1,8 @@ import { NextApiRequest, NextApiResponse } from "next"; import { createClient } from "@supabase/supabase-js"; import { + EAS_CONTRACT_ADDRESS, + NFT_STORAGE_TOKEN, SUPABASE_HYPERCERTS_SERVICE_ROLE_KEY, SUPABASE_HYPERCERTS_URL, } from "@/config"; @@ -11,6 +13,7 @@ import { verifyTypedData } from "ethers"; import { Database } from "@/types/hypercerts-database"; import NextCors from "nextjs-cors"; import { addressesByNetwork } from "@hypercerts-org/marketplace-sdk"; +import { ClaimTokenByIdQuery, HypercertClient } from "@hypercerts-org/sdk"; const inputSchemaPost = z.object({ signature: z.string(), @@ -139,9 +142,51 @@ export default async function handler( console.log("[marketplace-api] Recovered address", recoveredAddress); if (!(recoveredAddress.toLowerCase() === makerOrder.signer.toLowerCase())) { - return res - .status(401) - .json({ message: "Invalid signature", success: false, data: null }); + return res.status(401).json({ + message: "Recovered address is not equal to signer of order", + success: false, + data: null, + }); + } + + const hypercertClient = new HypercertClient({ + chain: { id: chainId }, + nftStorageToken: NFT_STORAGE_TOKEN, + easContractAddress: EAS_CONTRACT_ADDRESS, + }); + const tokenIds = makerOrder.itemIds.map( + (id) => `${makerOrder.collection.toLowerCase()}-${id}`, + ); + console.log("[marketplace-api] Token IDs", tokenIds); + + const claimTokens = await Promise.all( + tokenIds.map( + (id) => hypercertClient.indexer.fractionById(id) as ClaimTokenByIdQuery, + ), + ); + console.log("[marketplace-api] Claim tokens", claimTokens); + + // Check if all fractions exist + if (claimTokens.some((claimToken) => !claimToken.claimToken)) { + return res.status(401).json({ + message: "Not all fractions in itemIds exist", + success: false, + data: null, + }); + } + + // Check if all fractions are owned by signer + if ( + !claimTokens.every( + (claimToken) => + claimToken.claimToken?.owner.toLowerCase() === recoveredAddress, + ) + ) { + return res.status(401).json({ + message: "Not all fractions are owned by signer", + success: false, + data: null, + }); } // Add to database