From 6cb66c675a49a389152918e719a8ae495abd3ed1 Mon Sep 17 00:00:00 2001 From: jnsdls Date: Mon, 28 Oct 2024 23:59:34 +0000 Subject: [PATCH] remove all farcaster frame logic for the moment (#5213) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## PR-Codex overview This PR primarily focuses on the removal of multiple files related to Farcaster frames and the `@coinbase/onchainkit` package, as well as some metadata updates in the `package.json` and `pnpm-lock.yaml` files. ### Detailed summary - Deleted various files related to Farcaster frames and their functionality. - Removed the `shortenAddress` function from `apps/dashboard/src/utils/string.ts`. - Updated `package.json` to remove `@coinbase/onchainkit` dependency. - Cleaned up `pnpm-lock.yaml` by removing references to deleted packages and dependencies. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/dashboard/package.json | 1 - apps/dashboard/src/classes/ConnectFrame.ts | 154 ---------------- .../src/classes/DO_NOT_ADD_THINGS_HERE.md | 3 - apps/dashboard/src/classes/SuperChainFrame.ts | 74 -------- .../src/classes/SuperchainFormFrame.ts | 127 -------------- .../src/classes/ThirdwebDegenEngine.ts | 69 -------- apps/dashboard/src/classes/Warpcast.ts | 40 ----- apps/dashboard/src/lib/connect-frames.ts | 29 --- apps/dashboard/src/lib/engine.ts | 63 ------- apps/dashboard/src/lib/farcaster-frames.ts | 18 -- apps/dashboard/src/lib/superchain-frames.ts | 59 ------- .../dashboard/src/pages/api/frame/base/abi.ts | 30 ---- .../src/pages/api/frame/base/get-tx-frame.ts | 57 ------ apps/dashboard/src/pages/api/frame/connect.ts | 59 ------- .../src/pages/api/frame/degen/mint.ts | 82 --------- apps/dashboard/src/pages/api/frame/engine.ts | 60 ------- .../dashboard/src/pages/api/frame/redirect.ts | 37 ---- .../src/pages/api/frame/superchain.ts | 76 -------- .../src/pages/api/superchain/frame.ts | 111 ------------ apps/dashboard/src/pages/connect.tsx | 18 -- apps/dashboard/src/pages/frame/degen/mint.tsx | 53 ------ .../src/pages/frame/mint/base/index.tsx | 54 ------ apps/dashboard/src/pages/grant/superchain.tsx | 15 -- apps/dashboard/src/utils/api.ts | 22 --- apps/dashboard/src/utils/string.ts | 4 - .../src/utils/superchain-embed-frame.ts | 66 ------- apps/dashboard/src/utils/tx-frame.ts | 16 -- pnpm-lock.yaml | 165 ------------------ 28 files changed, 1562 deletions(-) delete mode 100644 apps/dashboard/src/classes/ConnectFrame.ts delete mode 100644 apps/dashboard/src/classes/DO_NOT_ADD_THINGS_HERE.md delete mode 100644 apps/dashboard/src/classes/SuperChainFrame.ts delete mode 100644 apps/dashboard/src/classes/SuperchainFormFrame.ts delete mode 100644 apps/dashboard/src/classes/ThirdwebDegenEngine.ts delete mode 100644 apps/dashboard/src/classes/Warpcast.ts delete mode 100644 apps/dashboard/src/lib/connect-frames.ts delete mode 100644 apps/dashboard/src/lib/farcaster-frames.ts delete mode 100644 apps/dashboard/src/lib/superchain-frames.ts delete mode 100644 apps/dashboard/src/pages/api/frame/base/abi.ts delete mode 100644 apps/dashboard/src/pages/api/frame/base/get-tx-frame.ts delete mode 100644 apps/dashboard/src/pages/api/frame/connect.ts delete mode 100644 apps/dashboard/src/pages/api/frame/degen/mint.ts delete mode 100644 apps/dashboard/src/pages/api/frame/engine.ts delete mode 100644 apps/dashboard/src/pages/api/frame/redirect.ts delete mode 100644 apps/dashboard/src/pages/api/frame/superchain.ts delete mode 100644 apps/dashboard/src/pages/api/superchain/frame.ts delete mode 100644 apps/dashboard/src/pages/frame/degen/mint.tsx delete mode 100644 apps/dashboard/src/pages/frame/mint/base/index.tsx delete mode 100644 apps/dashboard/src/utils/api.ts delete mode 100644 apps/dashboard/src/utils/superchain-embed-frame.ts delete mode 100644 apps/dashboard/src/utils/tx-frame.ts diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index 0437d4256bd..e0b70a95d23 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -25,7 +25,6 @@ "@chakra-ui/react": "^2.8.2", "@chakra-ui/styled-system": "^2.9.2", "@chakra-ui/theme-tools": "^2.1.2", - "@coinbase/onchainkit": "0.14.2", "@emotion/react": "11.13.3", "@emotion/styled": "11.13.0", "@hookform/resolvers": "^3.9.0", diff --git a/apps/dashboard/src/classes/ConnectFrame.ts b/apps/dashboard/src/classes/ConnectFrame.ts deleted file mode 100644 index b00bcc950fe..00000000000 --- a/apps/dashboard/src/classes/ConnectFrame.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { getFrameHtmlResponse } from "@coinbase/onchainkit"; -import { connectFrames } from "lib/connect-frames"; -import * as engine from "lib/engine"; -import { getAbsoluteUrl } from "lib/vercel-utils"; -import { z } from "zod"; - -const validSteps = z.union([ - z.literal("1"), - z.literal("2"), - z.literal("3"), - z.literal("4"), - z.literal("5"), - z.literal("6"), - z.literal("7"), -]); - -type Step = z.infer; - -const nftContractAddress = "0x9D96603334B1e97554b846CA916a6b72161a5323"; - -// biome-ignore lint/complexity/noStaticOnlyClass: FIXME: refactor to standalone functions -export class ConnectFrame { - static getParsedButtonIndex = (buttonIndex: unknown) => { - return z.number().min(1).max(3).parse(buttonIndex); - }; - - static getParsedStep = (step: unknown) => { - return validSteps.parse(step); - }; - - static getShouldGoNext = (step: Step, buttonIndex: number): boolean => { - const buttonIdx = z.number().min(1).max(3).parse(buttonIndex); - - if (step === "1") { - return buttonIdx === 1; - } - if (step === "7") { - return false; - } - - return buttonIdx === 3; - }; - - static getShouldGoBack = (step: Step, buttonIndex: number) => { - const buttonIdx = z.number().min(1).max(3).parse(buttonIndex); - return step !== "1" && buttonIdx === 1; - }; - - static mintNftWithFrameHtmlResponse = async (address: string) => { - const owned = await engine.httpFetchOwned( - address, - 8453, - nftContractAddress, - ); - - if (!owned.result.length) { - await engine.httpMint(address, 8453, nftContractAddress); - } - - return getFrameHtmlResponse({ - buttons: [ - { - label: "← Back", - action: "post", - }, - { - label: "NFT Minted", - action: "post", - }, - { - label: "Start building", - action: "post_redirect", - }, - ], - image: connectFrames[7].imageUrl, - // hardcode to "7" - post_url: `${getAbsoluteUrl()}/api/frame/connect?step=7`, - }); - }; - - static getFrameHtmlResponse = (step: Step, direction: "next" | "back") => { - const readyStepNum = - direction === "next" ? Number(step) + 1 : Number(step) - 1; - const frameImg = - connectFrames[readyStepNum as keyof typeof connectFrames]?.imageUrl; - - if (!frameImg) { - throw new Error(`Image frame not found for step: ${step}`); - } - - return getFrameHtmlResponse( - readyStepNum === 7 - ? { - buttons: [ - { - label: "← Back", - action: "post", - }, - { - label: "Mint NFT", - action: "post", - }, - { - label: "Start building", - action: "post_redirect", - }, - ], - image: frameImg, - // hardcode to "7" - post_url: `${getAbsoluteUrl()}/api/frame/connect?step=7`, - } - : readyStepNum === 1 - ? { - buttons: [ - { - label: "Features →", - action: "post", - }, - { - label: "Start building", - action: "post_redirect", - }, - ], - image: frameImg, - // hardcode to "2" - post_url: `${getAbsoluteUrl()}/api/frame/connect?step=1`, - } - : { - buttons: [ - { - label: "← Back", - action: "post", - }, - { - label: "Start building", - action: "post_redirect", - }, - { - label: "Next →", - action: "post", - }, - ], - image: frameImg, - post_url: `${getAbsoluteUrl()}/api/frame/connect?step=${readyStepNum}`, - }, - ); - }; - - static getRedirectUrl = (step: Step) => { - return step === "6" - ? "https://portal.thirdweb.com/typescript/v5" - : `${getAbsoluteUrl()}/connect`; - }; -} diff --git a/apps/dashboard/src/classes/DO_NOT_ADD_THINGS_HERE.md b/apps/dashboard/src/classes/DO_NOT_ADD_THINGS_HERE.md deleted file mode 100644 index d869a3b0f16..00000000000 --- a/apps/dashboard/src/classes/DO_NOT_ADD_THINGS_HERE.md +++ /dev/null @@ -1,3 +0,0 @@ -# DO NOT ADD NEW THINGS INSIDE THIS FOLDER OR SUB_FOLDERS - -This part of the dashboard is deprecated, and we are actively working on removing it. Please do not add new things here. If you need to add new things, please add them to the appropriate folder in the src folder. \ No newline at end of file diff --git a/apps/dashboard/src/classes/SuperChainFrame.ts b/apps/dashboard/src/classes/SuperChainFrame.ts deleted file mode 100644 index 329ed2ea3a6..00000000000 --- a/apps/dashboard/src/classes/SuperChainFrame.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - type FrameMetadataType, - getFrameHtmlResponse, -} from "@coinbase/onchainkit"; -import { superchainFrameChains } from "lib/superchain-frames"; -import { getAbsoluteUrl } from "lib/vercel-utils"; -import { z } from "zod"; - -const validAction = z.union([ - z.literal("check"), - z.literal("growth"), - z.literal("final"), -]); - -const validChains = z.union([ - z.literal(superchainFrameChains.optimism.name), - z.literal(superchainFrameChains.base.name), - z.literal(superchainFrameChains.zora.name), -]); - -// biome-ignore lint/complexity/noStaticOnlyClass: FIXME: refactor to standalone functions -export class SuperChainFrame { - public static validateAction = (action: string) => { - return validAction.parse(action); - }; - - public static validateChain = (chain: string) => { - return validChains.parse(chain); - }; - - public static validateButtonIndex = (buttonIndex: number, max: number) => { - return z.number().min(1).max(max).parse(buttonIndex); - }; - - public static chainNameByButtonIndex = (buttonIndex: number) => { - switch (buttonIndex) { - case 1: - return "optimism"; - - case 2: - return "base"; - - case 3: - return "zora"; - - default: - throw new Error("Invalid button index"); - } - }; - - public static planByButtonIndex = (buttonIndex: number) => { - switch (buttonIndex) { - case 1: - return "250"; - - case 2: - return "2500"; - - case 3: - return "3000"; - - default: - throw new Error("Invalid button index"); - } - }; - - public static avgTransactionImage = (chainName: string, plan: string) => { - return `${getAbsoluteUrl()}/assets/dashboard/${chainName}-${plan}.png`; - }; - - public static htmlResponse = (frameMetaData: FrameMetadataType) => { - return getFrameHtmlResponse(frameMetaData); - }; -} diff --git a/apps/dashboard/src/classes/SuperchainFormFrame.ts b/apps/dashboard/src/classes/SuperchainFormFrame.ts deleted file mode 100644 index ad5f52fb0b7..00000000000 --- a/apps/dashboard/src/classes/SuperchainFormFrame.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { - type FrameMetadataType, - getFrameHtmlResponse, -} from "@coinbase/onchainkit"; -import * as Sentry from "@sentry/nextjs"; -import { z } from "zod"; - -type HubspotFields = [ - { - name: "email"; - value: string; - }, - { - name: "superchain_chain"; - value: string; - }, - { - name: "website"; - value: string; - }, - { - name: "farcaster_handle"; - value: string; - }, -]; - -const validChains = z.union([ - z.literal("base"), - z.literal("zora"), - z.literal("fraxtal"), - z.literal("op-mainnet"), - z.literal("mode"), -]); - -const validQueryType = z.union([ - z.literal("apply"), - z.literal("chain"), - z.literal("email"), - z.literal("website"), - z.literal("redirect"), -]); - -// biome-ignore lint/complexity/noStaticOnlyClass: FIXME: refactor to standalone functions -export class SuperChainFormFrame { - static getQueryType = (type: string) => { - return validQueryType.parse(type); - }; - - static getChain = (chain: string) => { - let lowercaseChain = chain.toLowerCase(); - if (lowercaseChain === "op mainnet") { - lowercaseChain = "op-mainnet"; - } - return validChains.parse(lowercaseChain); - }; - - static getConvertedChain = (chain: string) => { - let convertedChain: string; - - switch (chain) { - case "base": - convertedChain = "Base"; - break; - - case "fraxtal": - convertedChain = "Frax"; - break; - - case "mode": - convertedChain = "Mode"; - break; - - case "op-mainnet": - convertedChain = "Optimism"; - break; - - case "zora": - convertedChain = "Zora"; - break; - - default: - throw new Error("Valid chain not found"); - } - return convertedChain; - }; - - static getEmail = (email: string) => { - return z.string().email().parse(email); - }; - - static getWebsiteUrl = (url: string) => { - let _url = url; - if (!_url.startsWith("http://") && !_url.startsWith("https://")) { - _url = `https://${url}`; - } - // Validate URL - new URL(_url); - return _url; - }; - - public static htmlResponse = (frameMetaData: FrameMetadataType) => { - return getFrameHtmlResponse(frameMetaData); - }; - - public static sendFormToHubspot = async (fields: HubspotFields) => { - const response = await fetch( - "https://api.hsforms.com/submissions/v3/integration/secure/submit/23987964/38c5be6b-b260-4a91-a09a-868ea324d995", - { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.HUBSPOT_ACCESS_TOKEN}`, - }, - method: "POST", - body: JSON.stringify({ - fields, - }), - }, - ); - - if (!response.ok) { - const resp = await response.json(); - const errMessage = `Failed to send form to email: ${fields[0].value} and farcaster handle: ${fields[3].value}`; - Sentry.captureException(new Error(errMessage, { cause: resp })); - throw new Error("Failed to send form"); - } - }; -} diff --git a/apps/dashboard/src/classes/ThirdwebDegenEngine.ts b/apps/dashboard/src/classes/ThirdwebDegenEngine.ts deleted file mode 100644 index 19f4f75ec7a..00000000000 --- a/apps/dashboard/src/classes/ThirdwebDegenEngine.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { z } from "zod"; - -const mintResponseSchema = z.object({ - result: z.object({ - queueId: z.string(), - }), -}); - -const ownedResponseSchema = z.object({ - result: z.string(), -}); - -const validAction = z.union([z.literal("mint"), z.literal("redirect")]); - -const thirdwebEngineUrl = process.env.THIRDWEB_ENGINE_URL; -const thirdwebEngineWallet = process.env.DEGEN_THIRDWEB_ENGINE_WALLET; -const thirdwebEngineAccessToken = process.env.THIRDWEB_ACCESS_TOKEN; - -const degenChainId = 666666666; -const degenNftContractAddress = "0x1efacE838cdCD5B19d8D0CC4d22d7AEFdDfB0d6f"; - -// biome-ignore lint/complexity/noStaticOnlyClass: FIXME: refactor to standalone functions -export class ThirdwebDegenEngine { - public static mint = async (receiver: string) => { - const response = await fetch( - `${thirdwebEngineUrl}/contract/${degenChainId}/${degenNftContractAddress}/erc721/claim-to`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${thirdwebEngineAccessToken}`, - "x-backend-wallet-address": thirdwebEngineWallet as string, - }, - body: JSON.stringify({ - receiver: receiver.toLowerCase(), - quantity: "1", - }), - }, - ); - - const result = await response.json(); - - return mintResponseSchema.parse(result); - }; - - public static isNFTOwned = async (receiver: string) => { - const response = await fetch( - `${thirdwebEngineUrl}/contract/${degenChainId}/${degenNftContractAddress}/erc721/balance-of?walletAddress=${receiver.toLowerCase()}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${thirdwebEngineAccessToken}`, - "x-backend-wallet-address": thirdwebEngineWallet as string, - }, - }, - ); - - const result = await response.json(); - - const parsedResult = ownedResponseSchema.parse(result); - - return parsedResult.result !== "0"; - }; - - public static validateAction = (action: string) => { - return validAction.parse(action); - }; -} diff --git a/apps/dashboard/src/classes/Warpcast.ts b/apps/dashboard/src/classes/Warpcast.ts deleted file mode 100644 index ab5a2f5cb92..00000000000 --- a/apps/dashboard/src/classes/Warpcast.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { z } from "zod"; -import { hostnameEndsWith } from "../utils/url"; - -// Neynar's api -const apiUrl = "https://api.neynar.com"; -const apiKey = process.env.NEYNAR_API_KEY as string; - -const validateMessageSchema = z.object({ - // has to be true - valid: z.literal(true), -}); - -export const untrustedMetaDataSchema = z.object({ - url: z.string().refine((url) => { - return hostnameEndsWith(url, "thirdweb.com"); - }), -}); - -// biome-ignore lint/complexity/noStaticOnlyClass: FIXME: refactor to standalone functions -export class Warpcast { - public static async validateMessage(messageBytes: string) { - const url = `${apiUrl}/v2/farcaster/frame/validate`; - - const response = await fetch(url, { - headers: { - api_key: apiKey, - "content-type": "application/json", - }, - method: "POST", - body: JSON.stringify({ - message_bytes_in_hex: messageBytes, - }), - }); - - await response - .json() - .then((res) => res) - .then(validateMessageSchema.parse); - } -} diff --git a/apps/dashboard/src/lib/connect-frames.ts b/apps/dashboard/src/lib/connect-frames.ts deleted file mode 100644 index fef15d834a6..00000000000 --- a/apps/dashboard/src/lib/connect-frames.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { getAbsoluteUrl } from "./vercel-utils"; - -interface Frame { - imageUrl: string; -} - -export const connectFrames: Record<1 | 2 | 3 | 4 | 5 | 6 | 7, Frame> = { - 1: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-1.png`, - }, - 2: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-2.png`, - }, - 3: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-3.png`, - }, - 4: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-4.png`, - }, - 5: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-5.png`, - }, - 6: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-6.png`, - }, - 7: { - imageUrl: `${getAbsoluteUrl()}/assets/connect/frames/frame-7.png`, - }, -}; diff --git a/apps/dashboard/src/lib/engine.ts b/apps/dashboard/src/lib/engine.ts index 31449bbd6a4..cf89d270ac1 100644 --- a/apps/dashboard/src/lib/engine.ts +++ b/apps/dashboard/src/lib/engine.ts @@ -1,5 +1,3 @@ -import { z } from "zod"; - export type EngineBackendWalletType = "local" | "aws-kms" | "gcp-kms"; export const EngineBackendWalletOptions: { @@ -10,64 +8,3 @@ export const EngineBackendWalletOptions: { { key: "aws-kms", name: "AWS KMS" }, { key: "gcp-kms", name: "Google Cloud KMS" }, ]; - -const engineUrl = process.env.THIRDWEB_ENGINE_URL as string; - -const headers = { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.THIRDWEB_ENGINE_ACCESS_TOKEN as string}`, - "x-backend-wallet-address": process.env.THIRDWEB_ENGINE_WALLET as string, -}; - -const ownedResponseSchema = z.object({ - result: z.array( - z.object({ - owner: z.string().startsWith("0x"), - type: z.string(), - supply: z.string(), - }), - ), -}); - -const mintResponseSchema = z.object({ - result: z.object({ - queueId: z.string(), - }), -}); - -export const httpMint = async ( - receiver: string, - chainId: number, - contractAddress: string, -) => { - const response = await fetch( - `${engineUrl}/contract/${chainId}/${contractAddress}/erc721/claim-to`, - { - method: "POST", - headers, - body: JSON.stringify({ receiver: receiver.toLowerCase(), quantity: "1" }), - }, - ); - - const result = await response.json(); - - return mintResponseSchema.parse(result); -}; - -export const httpFetchOwned = async ( - address: string, - chainId: number, - contractAddress: string, -) => { - const response = await fetch( - `${engineUrl}/contract/${chainId}/${contractAddress}/erc721/get-owned?walletAddress=${address.toLowerCase()}`, - { - method: "GET", - headers, - }, - ); - - const result = await response.json(); - - return ownedResponseSchema.parse(result); -}; diff --git a/apps/dashboard/src/lib/farcaster-frames.ts b/apps/dashboard/src/lib/farcaster-frames.ts deleted file mode 100644 index d075b7a4782..00000000000 --- a/apps/dashboard/src/lib/farcaster-frames.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - type FrameRequest, - type FrameValidationData, - getFrameMessage, -} from "@coinbase/onchainkit"; - -export function validateFrameMessage(body: FrameRequest) { - return getFrameMessage(body, { - neynarApiKey: process.env.NEYNAR_API_KEY, - }); -} - -export function getFarcasterAccountAddress( - interactor: FrameValidationData["interactor"], -) { - // Get the first verified account or custody account if first verified account doesn't exist - return interactor.verified_accounts[0] ?? interactor.custody_address; -} diff --git a/apps/dashboard/src/lib/superchain-frames.ts b/apps/dashboard/src/lib/superchain-frames.ts deleted file mode 100644 index e2a10ff4740..00000000000 --- a/apps/dashboard/src/lib/superchain-frames.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { FrameMetadataType } from "@coinbase/onchainkit"; -import { getAbsoluteUrl } from "./vercel-utils"; - -export const superchainFrameChains = { - optimism: { - name: "optimism", - frameContentText: "OP Mainnet", - }, - base: { - name: "base", - frameContentText: "Base", - }, - zora: { - name: "zora", - frameContentText: "Zora", - }, - other: { - name: "other", - frameContentText: "Other", - }, -}; - -export const growthPlanFrameMetaData = ( - chainName: string, -): FrameMetadataType => { - return { - buttons: [ - { - label: "$250", - action: "post", - }, - { - label: "$2,500", - action: "post", - }, - { - label: "$3,000", - action: "post", - }, - ], - image: `${getAbsoluteUrl()}/assets/dashboard/growth.png`, - post_url: `${getAbsoluteUrl()}/api/frame/superchain?action=growth&chain=${chainName}`, - }; -}; - -export const finalGrowthPlanFrameMetaData = ( - imgUrl: string, -): FrameMetadataType => { - return { - buttons: [ - { - label: "Apply for Superchain credits", - action: "post_redirect", - }, - ], - image: imgUrl, - post_url: `${getAbsoluteUrl()}/api/frame/superchain?action=final`, - }; -}; diff --git a/apps/dashboard/src/pages/api/frame/base/abi.ts b/apps/dashboard/src/pages/api/frame/base/abi.ts deleted file mode 100644 index 60fbdf3379d..00000000000 --- a/apps/dashboard/src/pages/api/frame/base/abi.ts +++ /dev/null @@ -1,30 +0,0 @@ -export const abi = [ - { - inputs: [ - { internalType: "address", name: "_receiver", type: "address" }, - { internalType: "uint256", name: "_quantity", type: "uint256" }, - { internalType: "address", name: "_currency", type: "address" }, - { internalType: "uint256", name: "_pricePerToken", type: "uint256" }, - { - components: [ - { internalType: "bytes32[]", name: "proof", type: "bytes32[]" }, - { - internalType: "uint256", - name: "quantityLimitPerWallet", - type: "uint256", - }, - { internalType: "uint256", name: "pricePerToken", type: "uint256" }, - { internalType: "address", name: "currency", type: "address" }, - ], - internalType: "struct IDrop.AllowlistProof", - name: "_allowlistProof", - type: "tuple", - }, - { internalType: "bytes", name: "_data", type: "bytes" }, - ], - name: "claim", - outputs: [], - stateMutability: "payable", - type: "function", - }, -]; diff --git a/apps/dashboard/src/pages/api/frame/base/get-tx-frame.ts b/apps/dashboard/src/pages/api/frame/base/get-tx-frame.ts deleted file mode 100644 index 057fc3621c3..00000000000 --- a/apps/dashboard/src/pages/api/frame/base/get-tx-frame.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { getThirdwebClient } from "@/constants/thirdweb.server"; -import { - getFarcasterAccountAddress, - validateFrameMessage, -} from "lib/farcaster-frames"; -import type { NextApiRequest, NextApiResponse } from "next"; -import { getContract } from "thirdweb"; -import { base } from "thirdweb/chains"; -import { errorResponse } from "utils/api"; -import { getErc721PreparedEncodedData } from "utils/tx-frame"; -import { abi } from "./abi"; - -// https://thirdweb.com/base/0x352810fF1c51a42B568662D46570A30B590a715a -const contractAddress = "0x352810fF1c51a42B568662D46570A30B590a715a"; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse, -) { - // Return error response if method is not POST - if (req.method !== "POST") { - return errorResponse("Invalid method", 400); - } - - // Validate message with @coinbase/onchainkit - const { isValid, message } = await validateFrameMessage(req.body); - - // Validate if message is valid - if (!isValid || !message) { - return errorResponse("Invalid message", 400); - } - - // Get the first verified account address or custody address - const accountAddress = getFarcasterAccountAddress(message.interactor); - - // Get encoded data - const data = await getErc721PreparedEncodedData( - accountAddress, - getContract({ - chain: base, - address: contractAddress, - client: getThirdwebClient(), - }), - ); - - // Return transaction details response to farcaster - return res.status(200).json({ - chainId: "eip155:8453", - method: "eth_sendTransaction", - params: { - abi, - to: contractAddress, - data, - value: "0", - }, - }); -} diff --git a/apps/dashboard/src/pages/api/frame/connect.ts b/apps/dashboard/src/pages/api/frame/connect.ts deleted file mode 100644 index 2ecfb3ce0ab..00000000000 --- a/apps/dashboard/src/pages/api/frame/connect.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { ConnectFrame } from "classes/ConnectFrame"; -import { - getFarcasterAccountAddress, - validateFrameMessage, -} from "lib/farcaster-frames"; -import type { NextRequest } from "next/server"; -import { - errorResponse, - redirectResponse, - successHtmlResponse, -} from "utils/api"; - -export const config = { - runtime: "edge", -}; - -export default async function handler(req: NextRequest) { - if (req.method !== "POST") { - return errorResponse("Invalid method", 400); - } - - const body = await req.json(); - const { isValid, message } = await validateFrameMessage(body); - - if (!isValid || !message) { - return errorResponse("Invalid message", 400); - } - - const { searchParams } = new URL(req.url); - - const queryStep = searchParams.get("step"); - - const step = ConnectFrame.getParsedStep(queryStep); - const buttonIdx = ConnectFrame.getParsedButtonIndex(message.button); - - const shouldMint = buttonIdx === 2 && step === "7"; - - if (shouldMint) { - const faracsterAddress = getFarcasterAccountAddress(message.interactor); - const mintFrameHtmlResponse = - await ConnectFrame.mintNftWithFrameHtmlResponse(faracsterAddress); - return successHtmlResponse(mintFrameHtmlResponse, 200); - } - - const shouldGoNext = ConnectFrame.getShouldGoNext(step, message.button); - const shouldGoBack = ConnectFrame.getShouldGoBack(step, message.button); - - const shouldContinueSlideShow = shouldGoNext || shouldGoBack; - - if (shouldContinueSlideShow) { - const frameHtmlResponse = ConnectFrame.getFrameHtmlResponse( - step, - shouldGoNext ? "next" : "back", - ); - return successHtmlResponse(frameHtmlResponse, 200); - } - - return redirectResponse(ConnectFrame.getRedirectUrl(step), 302); -} diff --git a/apps/dashboard/src/pages/api/frame/degen/mint.ts b/apps/dashboard/src/pages/api/frame/degen/mint.ts deleted file mode 100644 index a8b3d834943..00000000000 --- a/apps/dashboard/src/pages/api/frame/degen/mint.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { getFrameHtmlResponse } from "@coinbase/onchainkit"; -import { ThirdwebDegenEngine } from "classes/ThirdwebDegenEngine"; -import { - getFarcasterAccountAddress, - validateFrameMessage, -} from "lib/farcaster-frames"; -import { getAbsoluteUrl } from "lib/vercel-utils"; -import type { NextRequest } from "next/server"; -import { - errorResponse, - redirectResponse, - successHtmlResponse, -} from "utils/api"; -import { shortenAddress } from "utils/string"; - -const postUrl = `${getAbsoluteUrl()}/api/frame/degen/mint`; -const imageUrl = `${getAbsoluteUrl()}/assets/og-image/degen-enchine-frame.png`; - -const thirdwebDashboardContractUrl = - "https://thirdweb.com/degen-chain/0x1efacE838cdCD5B19d8D0CC4d22d7AEFdDfB0d6f"; - -export const config = { - runtime: "edge", -}; - -export default async function handler(req: NextRequest) { - if (req.method !== "POST") { - return errorResponse("Invalid method", 400); - } - - const body = await req.json(); - - const { isValid, message } = await validateFrameMessage(body); - - if (!isValid || !message) { - return errorResponse("Invalid message", 400); - } - - const { searchParams } = new URL(req.url); - - const queryAction = searchParams.get("action"); - - const action = ThirdwebDegenEngine.validateAction(queryAction as string); - - if (action === "mint") { - const faracsterAddress = getFarcasterAccountAddress(message.interactor); - - const isNftOwned = await ThirdwebDegenEngine.isNFTOwned(faracsterAddress); - - if (isNftOwned) { - const htmlResponse = getFrameHtmlResponse({ - buttons: [ - { - label: "NFT already minted", - action: "post_redirect", - }, - ], - image: imageUrl, - post_url: `${postUrl}?action=redirect`, - }); - - return successHtmlResponse(htmlResponse, 200); - } - - await ThirdwebDegenEngine.mint(faracsterAddress); - - const htmlResponse = getFrameHtmlResponse({ - buttons: [ - { - label: `Successfully minted to address ${shortenAddress(faracsterAddress)}`, - action: "post_redirect", - }, - ], - image: imageUrl, - post_url: `${postUrl}?action=redirect`, - }); - - return successHtmlResponse(htmlResponse, 200); - } - - return redirectResponse(thirdwebDashboardContractUrl, 302); -} diff --git a/apps/dashboard/src/pages/api/frame/engine.ts b/apps/dashboard/src/pages/api/frame/engine.ts deleted file mode 100644 index f502485caf9..00000000000 --- a/apps/dashboard/src/pages/api/frame/engine.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ConnectFrame } from "classes/ConnectFrame"; -import { - getFarcasterAccountAddress, - validateFrameMessage, -} from "lib/farcaster-frames"; -import type { NextRequest } from "next/server"; -import { - errorResponse, - redirectResponse, - successHtmlResponse, -} from "utils/api"; - -export const config = { - runtime: "edge", -}; - -export default async function handler(req: NextRequest) { - if (req.method !== "POST") { - return errorResponse("Invalid method", 400); - } - - const body = await req.json(); - - const { isValid, message } = await validateFrameMessage(body); - - if (!isValid || !message) { - return errorResponse("Invalid message", 400); - } - - const { searchParams } = new URL(req.url); - - const queryStep = searchParams.get("step"); - - const step = ConnectFrame.getParsedStep(queryStep); - const buttonIdx = ConnectFrame.getParsedButtonIndex(message.button); - - const shouldMint = buttonIdx === 2 && step === "7"; - - if (shouldMint) { - const faracsterAddress = getFarcasterAccountAddress(message.interactor); - const mintFrameHtmlResponse = - await ConnectFrame.mintNftWithFrameHtmlResponse(faracsterAddress); - return successHtmlResponse(mintFrameHtmlResponse, 200); - } - - const shouldGoNext = ConnectFrame.getShouldGoNext(step, message.button); - const shouldGoBack = ConnectFrame.getShouldGoBack(step, message.button); - - const shouldContinueSlideShow = shouldGoNext || shouldGoBack; - - if (shouldContinueSlideShow) { - const frameHtmlResponse = ConnectFrame.getFrameHtmlResponse( - step, - shouldGoNext ? "next" : "back", - ); - return successHtmlResponse(frameHtmlResponse, 200); - } - - return redirectResponse(ConnectFrame.getRedirectUrl(step), 302); -} diff --git a/apps/dashboard/src/pages/api/frame/redirect.ts b/apps/dashboard/src/pages/api/frame/redirect.ts deleted file mode 100644 index 086bcd04229..00000000000 --- a/apps/dashboard/src/pages/api/frame/redirect.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Warpcast, untrustedMetaDataSchema } from "classes/Warpcast"; -import { type NextRequest, NextResponse } from "next/server"; -import { z } from "zod"; - -interface RequestBody { - trustedData: { - messageBytes: string; - }; - untrustedData: { - url: string; - }; -} - -export const config = { - runtime: "edge", -}; -// 1. Verify that the trusted data from warpcast is valid -// 2. Once verified just return the url that they've shared in the frame -// 3. Finally give a response of redirect with status code 302. More info here: https://warpcast.notion.site/Farcaster-Frames-4bd47fe97dc74a42a48d3a234636d8c5 -export default async function handler(req: NextRequest) { - if (req.method !== "POST") { - return NextResponse.json({ error: "invalid method" }, { status: 400 }); - } - - const body = (await req.json()) as RequestBody; - - const metadata = untrustedMetaDataSchema.parse(body.untrustedData); - - const trustedMessageByte = z.string().parse(body.trustedData?.messageBytes); - - // This will throw an exception if neynar's API doesn't validate the message - await Warpcast.validateMessage(trustedMessageByte); - - return NextResponse.redirect(metadata.url, { - status: 302, - }); -} diff --git a/apps/dashboard/src/pages/api/frame/superchain.ts b/apps/dashboard/src/pages/api/frame/superchain.ts deleted file mode 100644 index 174b2aa624a..00000000000 --- a/apps/dashboard/src/pages/api/frame/superchain.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { SuperChainFrame } from "classes/SuperChainFrame"; -import { validateFrameMessage } from "lib/farcaster-frames"; -import { - finalGrowthPlanFrameMetaData, - growthPlanFrameMetaData, -} from "lib/superchain-frames"; -import type { NextRequest } from "next/server"; -import { - errorResponse, - redirectResponse, - successHtmlResponse, -} from "utils/api"; - -export const config = { - runtime: "edge", -}; - -const superchainLandingUrl = "https://thirdweb.com/grant/superchain"; - -export default async function handler(req: NextRequest) { - if (req.method !== "POST") { - return errorResponse("Invalid method", 400); - } - - const body = await req.json(); - - const { isValid, message } = await validateFrameMessage(body); - - if (!isValid || !message) { - return errorResponse("Invalid message", 400); - } - - const { searchParams } = new URL(req.url); - - const queryAction = searchParams.get("action"); - - const action = SuperChainFrame.validateAction(queryAction as string); - - if (action === "check") { - const buttonIndex = SuperChainFrame.validateButtonIndex(message.button, 4); - - if (buttonIndex === 4) { - return redirectResponse(superchainLandingUrl, 302); - } - - const chainName = SuperChainFrame.chainNameByButtonIndex(buttonIndex); - - const htmlResponse = SuperChainFrame.htmlResponse( - growthPlanFrameMetaData(chainName), - ); - - return successHtmlResponse(htmlResponse, 200); - } - - if (action === "growth") { - const buttonIndex = SuperChainFrame.validateButtonIndex(message.button, 3); - - const queryChain = searchParams.get("chain"); - - const chain = SuperChainFrame.validateChain(queryChain as string); - - const plan = SuperChainFrame.planByButtonIndex(buttonIndex); - - const transactionImage = SuperChainFrame.avgTransactionImage(chain, plan); - - const htmlResponse = SuperChainFrame.htmlResponse( - finalGrowthPlanFrameMetaData(transactionImage), - ); - - return successHtmlResponse(htmlResponse, 200); - } - - if (action === "final") { - return redirectResponse(superchainLandingUrl, 302); - } -} diff --git a/apps/dashboard/src/pages/api/superchain/frame.ts b/apps/dashboard/src/pages/api/superchain/frame.ts deleted file mode 100644 index 9ae86eed0eb..00000000000 --- a/apps/dashboard/src/pages/api/superchain/frame.ts +++ /dev/null @@ -1,111 +0,0 @@ -import * as Sentry from "@sentry/nextjs"; -import { SuperChainFormFrame } from "classes/SuperchainFormFrame"; -import { validateFrameMessage } from "lib/farcaster-frames"; -import type { NextRequest } from "next/server"; -import { - errorResponse, - redirectResponse, - successHtmlResponse, -} from "utils/api"; -import { - getApplyFrameMetaData, - getEmailMetaData, - getSuccessMetaData, - getWebsiteMetaData, -} from "utils/superchain-embed-frame"; - -export const config = { - runtime: "edge", -}; - -const dashboardUrl = "https://thirdweb.com/dashboard"; - -export default async function handler(req: NextRequest) { - if (req.method !== "POST") { - return errorResponse("Invalid method", 400); - } - - try { - const body = await req.json(); - - const { isValid, message } = await validateFrameMessage(body); - - if (!isValid || !message) { - return errorResponse("Invalid message", 400); - } - - const { searchParams } = new URL(req.url); - - const queryType = searchParams.get("type"); - - const type = SuperChainFormFrame.getQueryType(queryType as string); - - if (type === "apply") { - const frameMetaData = getApplyFrameMetaData(); - return successHtmlResponse( - SuperChainFormFrame.htmlResponse(frameMetaData), - 200, - ); - } - - if (type === "chain") { - const chain = SuperChainFormFrame.getChain(message.input?.toLowerCase()); - const emailMetaData = getEmailMetaData(chain); - return successHtmlResponse( - SuperChainFormFrame.htmlResponse(emailMetaData), - 200, - ); - } - - if (type === "email") { - const queryChain = searchParams.get("chain"); - const chain = SuperChainFormFrame.getChain(queryChain as string); - const email = SuperChainFormFrame.getEmail(message.input); - - const websiteMetaData = getWebsiteMetaData(chain, email); - return successHtmlResponse( - SuperChainFormFrame.htmlResponse(websiteMetaData), - 200, - ); - } - - if (type === "website") { - const queryChain = searchParams.get("chain"); - const queryEmail = searchParams.get("email"); - - const chain = SuperChainFormFrame.getChain(queryChain as string); - const email = SuperChainFormFrame.getEmail(queryEmail as string); - - const website = SuperChainFormFrame.getWebsiteUrl(message.input); - - await SuperChainFormFrame.sendFormToHubspot([ - { name: "email", value: email }, - { - name: "superchain_chain", - value: SuperChainFormFrame.getConvertedChain(chain), - }, - { name: "website", value: website }, - { - name: "farcaster_handle", - value: message.raw.action.interactor.username ?? "unknown", - }, - ]); - - const websiteMetaData = getSuccessMetaData(); - return successHtmlResponse( - SuperChainFormFrame.htmlResponse(websiteMetaData), - 200, - ); - } - - if (type === "redirect") { - return redirectResponse(dashboardUrl, 302); - } - - return errorResponse("Type not valid", 400); - } catch (err) { - const errMessage = "Superchain frame embedded form failed"; - Sentry.captureException(new Error(errMessage, { cause: err })); - return errorResponse("Something went wrong!", 500); - } -} diff --git a/apps/dashboard/src/pages/connect.tsx b/apps/dashboard/src/pages/connect.tsx index 82f2cf351ad..eff3a80356b 100644 --- a/apps/dashboard/src/pages/connect.tsx +++ b/apps/dashboard/src/pages/connect.tsx @@ -11,7 +11,6 @@ import { LandingHeroWithSideImage } from "components/landing-pages/hero-with-sid import { LandingLayout } from "components/landing-pages/layout"; import { MiniPlayground } from "components/wallets/ConnectWalletMiniPlayground/MiniPlayground"; import { SupportedPlatformLink } from "components/wallets/SupportedPlatformLink"; -import { connectFrames } from "lib/connect-frames"; import { getAbsoluteUrl } from "lib/vercel-utils"; import Head from "next/head"; import { PageId } from "page-id"; @@ -129,23 +128,6 @@ const ConnectLanding: ThirdwebNextPage = () => { }, }} > - {/* Farcaster frames headers */} - - - - - - - - - -