---
# System prepended metadata

title: Frames v2 Research
tags: [farcastle]

---

# Frames v2 Research 

[We're dogfooding v2 frames at Merkle and making them open source.](https://warpcast.com/dwr.eth/0xcafbc039)

## Horsefacts

### [Farcaster frames v2 demo app walkthrough](https://www.youtube.com/watch?v=5wAbo_YsuC4)

- [frames-v2-demo](https://github.com/farcasterxyz/frames-v2-demo)
- [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/)

#### Load SDK

Client side only package that requires access to Window

```tsx
import sdk, {
  FrameNotificationDetails,
  type FrameContext,
} from "@farcaster/frame-sdk";
```

![image](https://hackmd.io/_uploads/rk_F8Cw4yl.png)

#### Call SDK Actions Ready 

```tsx
  useEffect(() => {
    const load = async () => {
      setContext(await sdk.context);
      sdk.actions.ready({});
    };
    if (sdk && !isSDKLoaded) {
      setIsSDKLoaded(true);
      load();
    }
  }, [isSDKLoaded]);
```

#### Call SDK Actions (to interact with Farcaster client)

![image](https://hackmd.io/_uploads/rJQw1CvEkl.png)

```tsx
  const openUrl = useCallback(() => {
    sdk.actions.openUrl("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
  }, []);
```

```html
<Button onClick={openUrl}>Open Link</Button>
```

#### Use Provider to Interact With Wallet

wagmi and/or viem React hooks

```tsx
import {
  useAccount,
  useSendTransaction,
  useSignMessage,
  useSignTypedData,
  useWaitForTransactionReceipt,
  useDisconnect,
  useConnect,
  useSwitchChain,
  useChainId,
} from "wagmi";
```

```tsx
  const {
    sendTransaction,
    error: sendTxError,
    isError: isSendTxError,
    isPending: isSendTxPending,
  } = useSendTransaction();
```

```tsx
  const {
    sendTransaction,
    data,
    error: sendTxError,
    isError: isSendTxError,
    isPending: isSendTxPending,
  } = useSendTransaction();
```

---

`layout.tsx`

Entrypoint to the app

```tsx
import "~/app/globals.css";
```

```tsx
export const metadata: Metadata = {
  title: "Farcaster Frames v2 Demo",
  description: "A Farcaster Frames v2 demo app",
};
```

---

`providers.tsx`

```tsx
import dynamic from "next/dynamic";
```

---

`WagmiProvider.tsx`

```tsx
export const config = createConfig({
  chains: [base, optimism],
  transports: {
    [base.id]: http(),
    [optimism.id]: http(),
  },
  connectors: [frameConnector()],
});
```

`frameConnector` is the Farcaster magic

---

`connector.ts`

They are adding this to the SDK

---

`page.tsx`

---

Tunnels, Next.js, React hooks, 

metadata and web standards

was able to have a fuctional frame in a day and teach a workshop to devs. spent 4 hours and don't even have the demo app running locally

Does this lock us into Vercel?

What can we do to strip it down?

Make sure to do the dynamic imports correctly

### [Farcaster Frames v2: Dev Tools, App Manifest, Account Association, Embeds](https://www.youtube.com/watch?v=S1KuwHYPtxU)

#### Developer Mode

##### Frames

##### Domains

`proposals.farcastle.net`

Can put this in the API route or a static file. What is the benefit of dynamically generating the `appUrl` in `route.ts`?

`/.well-known/farcaster.json`

```json
{
  "accountAssociation": {
    "header": "eyJmaWQiOjUwMzcsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHhGNWIzZGU5MTU5NEU3OGMyMUQ3NmEwOTllOTZFMDVBNDI1MkIyNWE5In0",
    "payload": "eyJkb21haW4iOiJwcm9wb3NhbHMuZmFyY2FzdGxlLm5ldCJ9",
    "signature": "MHg5N2JmMGJjMWViNzYzZTg0MmNiNmRiOTRlY2Y2OGJiNDFiNDQwNjZiNzA4Y2YzZjczMGQwMWYxM2EwMzcyODkwM2JjYjljM2NlNjY5Y2RmOGNmNmI3MWJiYjY4ZTg1ODg3MDU5ZWE1MjhhOGFjZmExOWJmYmE4MzkyYzlmNGY0ZTFj"
  },
  "frame": {
    "name": "Example Frame",
    "version": "0.0.1",
    "iconUrl": "https://example.com/icon.png",
    "homeUrl": "https://example.com",
    "splashImageUrl": "https://example.com/splash.png",
    "splashBackgroundColor": "#eeccff",
    "webhookUrl": "https://example.com/webhook"
  }
}
```

![image](https://hackmd.io/_uploads/SycDzy_Ekg.png)

Header will contain the domain and the account that signed it as attribution.

#### Frame Embeds

Inject metatags into the header of the app

`imageUrl` can dynamically generate an image in `opengraph-image.tsx` or serve a static image

:point_down: `title` is where the text on the button is defined

```tsx
const frame = {
  version: "next",
  imageUrl: `${appUrl}/opengraph-image`,
  button: {
    title: "Launch Frame",
    action: {
      type: "launch_frame",
      name: "Farcaster Frames v2 Demo",
      url: appUrl,
      splashImageUrl: `${appUrl}/splash.png`,
      splashBackgroundColor: "#f7f7f7",
    },
  },
};
```

```tsx
export async function generateMetadata(): Promise<Metadata> {
  return {
    title: "Farcaster Frames v2 Demo",
    openGraph: {
      title: "Farcaster Frames v2 Demo",
      description: "A Farcaster Frames v2 demo app.",
    },
    other: {
      "fc:frame": JSON.stringify(frame),
    },
  };
}
```