Skip to content

Commit

Permalink
Merge pull request #736 from xmtp/fixes
Browse files Browse the repository at this point in the history
Frames updates
  • Loading branch information
fabriguespe committed May 4, 2024
2 parents f5d30ae + 6def603 commit e4da3a9
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 53 deletions.
105 changes: 76 additions & 29 deletions docs/build/frames.md
Expand Up @@ -9,7 +9,7 @@ import TabItem from "@theme/TabItem";

# Chat Frames with XMTP

The XMTP community has been actively discussing and implementing ways to enhance user experience by supporting frames within XMTP applications. An effort in this direction is detailed in a community post [Supporting Frames in XMTP](https://community.xmtp.org/t/supporting-frames-in-xmtp/535).
The XMTP community has implemented ways to enhance user experience by supporting frames within XMTP applications by supporting [Open Frames](https://www.openframes.xyz). More details in this community post [Supporting Frames in XMTP](https://community.xmtp.org/t/supporting-frames-in-xmtp/535).

## Libraries

Expand Down Expand Up @@ -97,35 +97,93 @@ const acceptedProtocols: ClientProtocolId[] = [
**Validate incoming messages**:

```jsx
import { getXmtpFrameMessage, isXmtpFrameActionPayload } from "frames.js/xmtp";

let fid: number | undefined;
let walletAddress: string | undefined;

import {
isXmtpFrameRequest,
getXmtpFrameMessage,
} from "@coinbase/onchainkit/xmtp";
import { NextResponse } from "next/server";
import type { FrameRequest } from "@coinbase/onchainkit";

async function getResponse(req: any): Promise<NextResponse> {
const body: FrameRequest = await req.json();
if (isXmtpFrameRequest(body)) {
const { isValid, message } = await getXmtpFrameMessage(body);
walletAddress = frameMessage?.verifiedWalletAddress;
} else {
// ...
}
if (isXmtpFrameActionPayload(previousFrame.postBody)) {
const frameMessage = await getXmtpFrameMessage(previousFrame.postBody);
const { verifiedWalletAddress } = frameMessage;
// Do something with xmtp wallet address
} else {
// Do something else
}
```

- [Frames.js](https://framesjs.org/reference/js/xmtp): Official Framesjs Documentation.
- [Quickstart](https://github.com/framesjs/frames.js/tree/main/templates/next-starter-with-examples/): Onchainkit quickstart that integrates XMTP.
- [Quickstart](https://github.com/framesjs/frames.js/tree/main/templates/next-starter-with-examples/): Frames.js example that integrates XMTP.

</details>

<details><summary><b>Frog</b></summary>

- [Frog](https://frog.fm/getting-started): There is an active [discussion](https://github.com/wevm/frog/discussions/51) to integrate Open Frames.
**Metadata**

To build a Frame with XMTP, you must first add XMTP metadata.

```jsx
const addMetaTags = (client: string, version?: string) => {
// Follow the OpenFrames meta tags spec
return {
unstable_metaTags: [
{ property: `of:accepts`, content: version || "vNext" },
{ property: `of:accepts:${client}`, content: version || "vNext" },
],
};
};

export const app = new Frog(addMetaTags("xmtp"));
```

**Validate incoming messages**:

Install the `@xmtp/frames-validator` package to validate incoming messages.

```bash
npm install @xmtp/frames-validator
```

Add the middleware to validate incoming messages.

```jsx
import { validateFramesPost } from "@xmtp/frames-validator";

const xmtpSupport = async (c: Context, next: Next) => {
// Check if the request is a POST and relevant for XMTP processing
if (c.req.method === "POST") {
const requestBody = (await c.req.json().catch(() => {})) || {};
if (requestBody?.clientProtocol?.includes("xmtp")) {
c.set("client", "xmtp");
const { verifiedWalletAddress } = await validateFramesPost(requestBody);
c.set("verifiedWalletAddress", verifiedWalletAddress);
} else {
// Add farcaster check
c.set("client", "farcaster");
}
}
await next();
};

app.use(xmtpSupport);
```
**Access verified wallet address**:
```jsx
app.frame("/", (c) => {
/* Get Frame variables */
const { buttonValue, inputText, status } = c;

// XMTP verified address
const { verifiedWalletAddress } = c?.var || {};

/* return */
});
```
- [Frog](https://frog.fm/concepts/middleware#xmtp-frames-middleware): XMTP Frog official middleware
- [Quickstart](https://github.com/fabriguespe/frog-starter): Frog open frame XMTP quickstart
</details>
Expand All @@ -139,14 +197,3 @@ Some clients are fully XMTP compatible and can render Frames signing XMTP payloa
- [**Converse**](https://converse.xyz): Converse is Frame compatible. Send your Frames through Converse.
- [**Dev Inbox**](https://github.com/xmtp/dev-inbox/): Engage with Frames firsthand by trying them on web.
:::info
### Open Frames
XMTP contributes to the Open Frames standard, fostering interoperability and open standards.
- [**Open Frames Spec**](https://github.com/open-frames/standard/blob/v0.0.1/README.md): Make Farcaster Frames interoperable.
- [**Awesome Open Frames**](https://github.com/open-frames/awesome-open-frames.git): Curated list of Open Frames compatible Frames.
:::
2 changes: 1 addition & 1 deletion docs/build/get-started/examples.md
Expand Up @@ -140,7 +140,7 @@ Wallet connectors are essential components in decentralized applications (dApps)
<li><a href="https://github.com/xmtp-labs/xmtp-quickstart-privy" class="plausible-event-name=Quickstart">Privy</a><br/><small>Quickstart app for building an app with a Privy wallet connector</small></li>
<li><a href="https://github.com/xmtp-labs/xmtp-quickstart-thirdweb" class="plausible-event-name=Quickstart">ThirdWeb</a><br/><small>Quickstart app for building an app with a Thirdweb wallet connector</small></li>
<li><a href="https://github.com/xmtp-labs/xmtp-quickstart-walletconnect" class="plausible-event-name=Quickstart">WalletConnect</a><br/><small>Quickstart app for building an app with a WalletConnect wallet connector</small></li>
<li><a href="https://github.com/xmtp-labs/xmtp-quickstart-walletconnect" class="plausible-event-name=Quickstart">RainbowKit</a><br/><small>Quickstart app for building with a RainbowKit and Viem wallet connector</small></li>
<li><a href="https://github.com/xmtp-labs/quickstart-rainbowkit" class="plausible-event-name=Quickstart">RainbowKit</a><br/><small>Quickstart app for building with a RainbowKit and Viem wallet connector</small></li>
</ul>

</div>
Expand Down
98 changes: 78 additions & 20 deletions docs/farhack.md
Expand Up @@ -64,7 +64,7 @@ This prize goes to the best Frame compatible with messaging apps.

**Metadata**

In compliance with [Open Frames](https://github.com/open-frames/standard/blob/v0.0.1/README.md), Use a meta tag in your frame's HTML to declare the client protocols your frame supports.
In compliance with [Open Frames](https://www.openframes.xyz/), Use a meta tag in your frame's HTML to declare the client protocols your frame supports.

```html
<meta property="of:accepts:xmtp" content="vNext" />
Expand All @@ -89,7 +89,7 @@ export function handler(requestBody: any) {

**Frameworks**

Popular frameworks have already integrated Open Frames into their stacks:
Popular frameworks have already integrated Open Frames into their stack:

<details><summary><b>OnChainKit</b></summary>

Expand Down Expand Up @@ -140,7 +140,7 @@ async function getResponse(req: any): Promise<NextResponse> {
```

- [OnChainKit](https://onchainkit.xyz/xmtp/introduction): Official OnchainKit documentation.
- [Quickstart](https://github.com/daria-github/a-frame-in-100-lines/): OnchainKit quickstart that integrates XMTP.
- [Quickstart](https://github.com/daria-github/a-frame-in-100-lines/): Onchainkit quickstart that integrates XMTP.

</details>

Expand All @@ -166,35 +166,93 @@ const acceptedProtocols: ClientProtocolId[] = [
**Validate incoming messages**:

```jsx
import { getXmtpFrameMessage, isXmtpFrameActionPayload } from "frames.js/xmtp";

let fid: number | undefined;
let walletAddress: string | undefined;

import {
isXmtpFrameRequest,
getXmtpFrameMessage,
} from "@coinbase/onchainkit/xmtp";
import { NextResponse } from "next/server";
import type { FrameRequest } from "@coinbase/onchainkit";

async function getResponse(req: any): Promise<NextResponse> {
const body: FrameRequest = await req.json();
if (isXmtpFrameRequest(body)) {
const { isValid, message } = await getXmtpFrameMessage(body);
walletAddress = frameMessage?.verifiedWalletAddress;
} else {
// ...
}
if (isXmtpFrameActionPayload(previousFrame.postBody)) {
const frameMessage = await getXmtpFrameMessage(previousFrame.postBody);
const { verifiedWalletAddress } = frameMessage;
// Do something with xmtp wallet address
} else {
// Do something else
}
```

- [Frames.js](https://framesjs.org/reference/js/xmtp): Official Framesjs Documentation.
- [Quickstart](https://github.com/framesjs/frames.js/tree/main/templates/next-starter-with-examples/): Onchainkit quickstart that integrates XMTP.
- [Quickstart](https://github.com/framesjs/frames.js/tree/main/templates/next-starter-with-examples/): Frames.js example that integrates XMTP.

</details>

<details><summary><b>Frog</b></summary>

- [Frog](https://frog.fm/getting-started): There is an active [discussion](https://github.com/wevm/frog/discussions/51) to integrate Open Frames.
**Metadata**

To build a Frame with XMTP, you must first add XMTP metadata.

```jsx
const addMetaTags = (client: string, version?: string) => {
// Follow the OpenFrames meta tags spec
return {
unstable_metaTags: [
{ property: `of:accepts`, content: version || "vNext" },
{ property: `of:accepts:${client}`, content: version || "vNext" },
],
};
};

export const app = new Frog(addMetaTags("xmtp"));
```

**Validate incoming messages**:

Install the `@xmtp/frames-validator` package to validate incoming messages.

```bash
npm install @xmtp/frames-validator
```

Add the middleware to validate incoming messages.

```jsx
import { validateFramesPost } from "@xmtp/frames-validator";

const xmtpSupport = async (c: Context, next: Next) => {
// Check if the request is a POST and relevant for XMTP processing
if (c.req.method === "POST") {
const requestBody = (await c.req.json().catch(() => {})) || {};
if (requestBody?.clientProtocol?.includes("xmtp")) {
c.set("client", "xmtp");
const { verifiedWalletAddress } = await validateFramesPost(requestBody);
c.set("verifiedWalletAddress", verifiedWalletAddress);
} else {
// Add farcaster check
c.set("client", "farcaster");
}
}
await next();
};

app.use(xmtpSupport);
```
**Access verified wallet address**:
```jsx
app.frame("/", (c) => {
/* Get Frame variables */
const { buttonValue, inputText, status } = c;

// XMTP verified address
const { verifiedWalletAddress } = c?.var || {};

/* return */
});
```
- [Frog](https://frog.fm/concepts/middleware#xmtp-frames-middleware): XMTP Frog official middleware
- [Quickstart](https://github.com/fabriguespe/frog-starter): Frog open frame XMTP quickstart
</details>
Expand Down
4 changes: 1 addition & 3 deletions docs/tutorials/transaction-frames.md
Expand Up @@ -41,7 +41,7 @@ const isTransactionFrame = button.action === "tx";

### Determine the transaction target and post URL

If the button action indicates the Frame is transactional, get the `target` and `postUrl` from the button. To learn more, see Frame Metadata [Optional Properties](https://github.com/open-frames/standard?tab=readme-ov-file#optional-properties).
If the button action indicates the Frame is transactional, get the `target` and `postUrl` from the button. To learn more, see Frame Metadata [Optional Properties](https://www.openframes.xyz/#optional-properties).

```jsx
if (isTransactionFrame) {
Expand Down Expand Up @@ -150,8 +150,6 @@ For more transaction Frame security considerations as well as mitigation strateg

Follow these steps to build a transaction Open Frame that can be displayed in an app built with XMTP.

Ensure the app meets the requirements covered in [Support a transactional Open Frame in an app built with XMTP](https://www.notion.so/Support-a-transactional-Open-Frame-in-an-app-built-with-XMTP-56abbbb7bc4e4a1188bd2801265d6b36?pvs=21).

**To build a transaction Open Frame:**

1. Create a boilerplate Next.js app.
Expand Down

0 comments on commit e4da3a9

Please sign in to comment.