Skip to content

Commit

Permalink
feat: polish FrameValidationData (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zizzamia authored Feb 1, 2024
1 parent caa2788 commit 0355c73
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 292 deletions.
11 changes: 11 additions & 0 deletions .changeset/new-dragons-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@coinbase/onchainkit': minor
---

- **feat**: deprecated `getFrameAccountAddress` as now `getFrameMessage` returns also the Account Address. #60
- **feat**: integrated with Neynars api to get validated messages + additional context like recast/follow/etc. By @robpolak #59
- **fix**: removed farcaster references as they were generating build errors and compatibility issues. By @robpolak #59

BREAKING CHANGES

I will write the breaking changes in the next PR
64 changes: 1 addition & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<img src='./docs/logo-v-0-3.png' width='800' alt='OnchainKit'>
<img src='./docs/logo-v-0-4.png' width='800' alt='OnchainKit'>

# [OnchainKit](https://github.com/coinbase/onchainkit/)

Expand Down Expand Up @@ -32,73 +32,12 @@ Creating a frame is easy: select an image and add clickable buttons. When a butt

Utilities:

- [getFrameAccountAddress()](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframeaccountaddressmessage-options): Retrieves the user **Account Address** from a Frame message.
- [getFrameHtmlResponse()](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframehtmlresponseframemetadata): Retrieves the **Frame HTML** for your HTTP responses.
- [getFrameMessage()](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframemessageframerequest): Retrieves a valid **Frame message** from the Frame Signature Packet.
- [getFrameMetadata()](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframeframemetadata): Retrieves valid **Frame metadata** for your initial HTML page.

<br />

### getFrameAccountAddress(message, options)

When a user interacts with your Frame, you will receive a JSON message called the "Frame Signature Packet." Once you validate this `message`, you can extract the Account Address by using the `getFrameAccountAddress(message)` function.

This Account Address can then be utilized for subsequent operations, enhancing the personalized experience of each individual using the Frame.

Note: To utilize this function, we rely on [Neynar APIs](https://docs.neynar.com/reference/user-bulk). In order to avoid rate limiting, please ensure that you have your own API KEY. Sign up [here](https://neynar.com).

```ts
// Steps 1. import getFrameAccountAddress from @coinbase/onchainkit
import { FrameRequest, getFrameAccountAddress, getFrameMessage } from '@coinbase/onchainkit';
import { NextRequest, NextResponse } from 'next/server';

async function getResponse(req: NextRequest): Promise<NextResponse> {
let accountAddress = '';
// Step 2. Read the body from the Next Request
const body: FrameRequest = await req.json();
// Step 3. Validate the message
const { isValid, message } = await getFrameMessage(body);

// Step 4. Determine the experience based on the validity of the message
if (isValid) {
// Step 5. Get from the message the Account Address of the user using the Frame
accountAddress = await getFrameAccountAddress(message, { NEYNAR_API_KEY: 'NEYNAR_ONCHAIN_KIT' });
} else {
// sorry, the message is not valid and it will be undefined
}

...
}

export async function POST(req: NextRequest): Promise<Response> {
return getResponse(req);
}

export const dynamic = 'force-dynamic';
```

**@Param**

```ts
type AccountAddressRequest = {
// The validated message from the getFrameMessage() function
message: FrameData;
options: {
// The NEYNAR_API_KEY used to access Neynar Farcaster Indexer
// https://docs.neynar.com/reference/user-bulk
NEYNAR_API_KEY: string;
};
};
```

**@Returns**

```ts
type AccountAddressResponse = Promise<string | undefined>;
```

<br />

### getFrameHtmlResponse(frameMetadata)

When you need to send an HTML Frame Response, the `getFrameHtmlResponse` method is here to assist you.
Expand All @@ -108,7 +47,6 @@ It generates a valid HTML string response with a frame and utilizes `FrameMetada
```ts
import {
FrameRequest,
getFrameAccountAddress,
getFrameMessage,
getFrameHtmlResponse,
} from '@coinbase/onchainkit';
Expand Down
Binary file added docs/logo-v-0-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 29 additions & 12 deletions src/core/farcasterTypes.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
import { NeynarFrameValidationResponse } from '../utils/neynar/frame/neynarFrameModels';

export interface FrameRequest {
untrustedData: FrameData;
trustedData: {
messageBytes: string;
};
}

export type FrameValidationResponse =
| { isValid: true; message: NeynarFrameValidationResponse }
| { isValid: false; message: undefined };
import { NeynarFrameValidationInternalModel } from '../utils/neynar/frame/types';

export interface FrameData {
fid: number;
Expand All @@ -24,6 +13,34 @@ export interface FrameData {
};
}

export interface FrameRequest {
untrustedData: FrameData;
trustedData: {
messageBytes: string;
};
}

/**
* Simplified Object model with the raw Neynar data if-needed.
*/
export interface FrameValidationData {
valid: boolean;
button: number;
liked: boolean;
recasted: boolean;
following: boolean;
interactor: {
fid: number;
custody_address: string;
verified_accounts: string[];
};
raw: NeynarFrameValidationInternalModel;
}

export type FrameValidationResponse =
| { isValid: true; message: FrameValidationData }
| { isValid: false; message: undefined };

export function convertToFrame(json: any) {
return {
fid: json.fid,
Expand Down
34 changes: 0 additions & 34 deletions src/core/getFrameAccountAddress.test.ts

This file was deleted.

38 changes: 0 additions & 38 deletions src/core/getFrameAccountAddress.ts

This file was deleted.

9 changes: 3 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// 🌲
const version = '0.3.1';

export { version };
// 🌲☀️🌲
export { version } from './version';
export { getFrameHtmlResponse } from './core/getFrameHtmlResponse';
export { getFrameAccountAddress } from './core/getFrameAccountAddress';
export { getFrameMetadata } from './core/getFrameMetadata';
export { getFrameMessage } from './core/getFrameMessage';
export type { FrameRequest, FrameData } from './core/farcasterTypes';
export type { FrameRequest, FrameValidationData } from './core/farcasterTypes';
13 changes: 10 additions & 3 deletions src/utils/neynar/frame/neynarFrameFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { version } from '../../../version';
import { FrameValidationData } from '../../../core/farcasterTypes';
import { FetchError } from '../exceptions/FetchError';
import { convertToNeynarResponseModel, NeynarFrameValidationResponse } from './neynarFrameModels';
import { convertToNeynarResponseModel } from './neynarFrameModels';

export const NEYNAR_DEFAULT_API_KEY = 'NEYNAR_ONCHAIN_KIT';

Expand All @@ -8,11 +10,16 @@ export async function neynarFrameValidation(
apiKey: string = NEYNAR_DEFAULT_API_KEY,
castReactionContext = true,
followContext = true,
): Promise<NeynarFrameValidationResponse | undefined> {
): Promise<FrameValidationData | undefined> {
const options = {
method: 'POST',
url: `https://api.neynar.com/v2/farcaster/frame/validate`,
headers: { accept: 'application/json', api_key: apiKey, 'content-type': 'application/json' },
headers: {
accept: 'application/json',
api_key: apiKey,
'content-type': 'application/json',
onchainkit_version: version,
},
body: JSON.stringify({
message_bytes_in_hex: messageBytes,
cast_reaction_context: castReactionContext, // Returns if the user has liked/recasted
Expand Down
Loading

0 comments on commit 0355c73

Please sign in to comment.