Skip to content

OnchainKit is a collection of tools to build world-class onchain apps with CSS, React, and typescript.

License

Notifications You must be signed in to change notification settings

DEFCONPRO/onchainkit

Β 
Β 

Repository files navigation

OnchainKit logo vibes

OnchainKit

OnchainKit is a collection of tools to build world-class onchain apps with CSS, React, and Typescript.

Version MIT License Downloads per month

Getting Started

Add OnchainKit to your project, install the required packages.

# Use Yarn
yarn add @coinbase/onchainkit [email protected] react@18 react-dom@18

# Use NPM
npm install @coinbase/onchainkit [email protected] react@18 react-dom@18

# Use PNPM
pnpm add @coinbase/onchainkit [email protected] react@18 react-dom@18

OnchainKit is divided into various theme utilities and components that are available for your use:



Frame Kit πŸ–ΌοΈ

A Frame transforms any cast into an interactive app.

Creating a frame is easy: select an image and add clickable buttons. When a button is clicked, you receive a callback and can send another image with more buttons. To learn more, check out "Farcaster Frames Official Documentation".

React component:

  • <FrameMetadata />: This component renders all the Frame metadata elements in one place.

Typescript utilities:


<FrameMetadata />

This component is utilized for incorporating Frame metadata elements into the React page.

Note: If you are using Next.js with App routing, it is recommended to use getFrameMetadata instead.

export default function HomePage() {
  return (
    ...
    <FrameMetadata
      buttons={[
        {
          label: 'Tell me the story',
        },
        {
          action: 'link',
          label: 'Link to Google',
          target: 'https://www.google.com'
        },
        {
          action: 'post_redirect',
          label: 'Redirect to cute pictures',
        },
      ]}
      image={{
       src: 'https://zizzamia.xyz/park-3.png',
       aspectRatio: '1:1'
      }}
      input={{
        text: 'Tell me a boat story',
      }}
      postUrl="https://zizzamia.xyz/api/frame"
    />
    ...
  );
}

@Props

type FrameButtonMetadata =
  | {
      action: 'link' | 'mint';
      label: string;
      target: string;
    }
  | {
      action?: 'post' | 'post_redirect';
      label: string;
    };

type FrameImageMetadata = {
  src: string;
  aspectRatio?: '1.91:1' | '1:1';
};

type FrameInputMetadata = {
  text: string;
};

type FrameMetadataType = {
  // A list of strings which are the label for the buttons in the frame (max 4 buttons).
  buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
  // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1 or 1:1
  image: FrameImageMetadata;
  // The text input to use for the Frame.
  input?: FrameInputMetadata;
  // A valid POST URL to send the Signature Packet to.
  postUrl?: string;
  // A period in seconds at which the app should expect the image to update.
  refreshPeriod?: number;
};

type FrameMetadataReact = FrameMetadataType & {
  wrapper?: React.ComponentType<any>;
};

@Returns

<meta name="fc:frame" content="vNext" />
<meta name="fc:frame:button:1" content="Tell me the story" />
<meta name="fc:frame:button:2" content="Link to Google" />
<meta name="fc:frame:button:2:action" content="link" />
<meta name="fc:frame:button:2:target" content="https://www.google.com" />
<meta name="fc:frame:button:3" content="Redirect to cute pictures" />
<meta name="fc:frame:button:3:action" content="post_redirect" />
<meta name="fc:frame:image" content="https://zizzamia.xyz/park-3.png" />
<meta name="fc:frame:image:aspect_ratio" content="1:1" />
<meta name="fc:frame:input:text" content="Tell me a boat story" />
<meta name="fc:frame:post_url" content="https://zizzamia.xyz/api/frame" />

getFrameHtmlResponse(frameMetadata)

When you need to send an HTML Frame Response, the getFrameHtmlResponse method is here to assist you.

It generates a valid HTML string response with a frame and utilizes FrameMetadata types for page metadata. This eliminates the need to manually create server-side HTML strings.

// Step 1. import getFrameHtmlResponse from @coinbase/onchainkit
import { getFrameHtmlResponse } from '@coinbase/onchainkit';
import { NextRequest, NextResponse } from 'next/server';

async function getResponse(req: NextRequest): Promise<NextResponse> {
  // Step 2. Build your Frame logic
  ...

  return new NextResponse(
    // Step 3. Use getFrameHtmlResponse to create a Frame response
    getFrameHtmlResponse({
      buttons: [
        {
          label: `We love BOAT`,
        },
      ],
      image: 'https://build-onchain-apps.vercel.app/release/v-0-17.png',
      postUrl: 'https://build-onchain-apps.vercel.app/api/frame',
    }),
  );
}

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

@Param

type FrameButtonMetadata =
  | {
      action: 'link' | 'mint';
      label: string;
      target: string;
    }
  | {
      action?: 'post' | 'post_redirect';
      label: string;
    };

type FrameImageMetadata = {
  src: string;
  aspectRatio?: '1.91:1' | '1:1';
};

type FrameInputMetadata = {
  text: string;
};

type FrameMetadataType = {
  // A list of strings which are the label for the buttons in the frame (max 4 buttons).
  buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
  // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1 or 1:1
  image: FrameImageMetadata;
  // The text input to use for the Frame.
  input?: FrameInputMetadata;
  // A valid POST URL to send the Signature Packet to.
  postUrl?: string;
  // A period in seconds at which the app should expect the image to update.
  refreshPeriod?: number;
};

@Returns

type FrameHTMLResponse = string;

getFrameMessage(frameRequest)

When a user interacts with your Frame, you receive a JSON message called the "Frame Signature Packet". Decode and validate this message using the getFrameMessage function.

You can also use getFrameMessage to access useful information such as:

  • button: number
  • fid: number
  • following: boolean
  • liked: boolean
  • recasted: boolean
  • verified_accounts: string[]

Note that if the message is not valid, it will be undefined.

// Step 1. import getFrameMessage from @coinbase/onchainkit
import { FrameRequest, getFrameMessage } from '@coinbase/onchainkit';
import { NextRequest, NextResponse } from 'next/server';

async function getResponse(req: NextRequest): Promise<NextResponse> {
  // 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 , {
    neynarApiKey: 'NEYNAR_ONCHAIN_KIT'
  });

  // Step 4. Determine the experience based on the validity of the message
  if (isValid) {
    // the message is valid
  } else {
    // sorry, the message is not valid and it will be undefined
  }

  ...
}

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

@Param

// The Frame Signature Packet body
type FrameMessage = {
  body: FrameRequest;
  messageOptions?: FrameMessageOptions;
};

type FrameMessageOptions =
  | {
      // The API key to use for validation. Default: NEYNAR_ONCHAIN_KIT
      neynarApiKey?: string;
      // Whether to cast the reaction context. Default: true
      castReactionContext?: boolean;
      // Whether to follow the context. Default: true
      followContext?: boolean;
    }
  | undefined;

@Returns

type Promise<FrameValidationResponse>;

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

interface FrameValidationData {
  button: number; // Number of the button clicked
  following: boolean; // Indicates if the viewer clicking the frame follows the cast author
  input: string; // Text input from the viewer typing in the frame
  interactor: {
    fid: number; // Viewer Farcaster ID
    custody_address: string; // Viewer custody address
    verified_accounts: string[]; // Viewer account addresses
  };
  liked: boolean; // Indicates if the viewer clicking the frame liked the cast
  raw: NeynarFrameValidationInternalModel;
  recasted: boolean; // Indicates if the viewer clicking the frame recasted the cast
  valid: boolean; // Indicates if the frame is valid
}

getFrameMetadata(frameMetadata)

With Next.js App routing, use the getFrameMetadata() inside your page.ts to get the metadata need it for your Frame.

// Step 1. import getFrameMetadata from @coinbase/onchainkit
import { getFrameMetadata } from '@coinbase/onchainkit';
import type { Metadata } from 'next';
import HomePage from './home';

// Step 2. Use getFrameMetadata to shape your Frame metadata
const frameMetadata = getFrameMetadata({
  buttons: [
    {
      label: 'We love BOAT',
    },
  ],
  image: 'https://build-onchain-apps.vercel.app/release/v-0-17.png',
  postUrl: 'https://build-onchain-apps.vercel.app/api/frame',
});

// Step 3. Add your metadata in the Next.js metadata utility
export const metadata: Metadata = {
  manifest: '/manifest.json',
  other: {
    ...frameMetadata
  },
};

export default function Page() {
  return <HomePage />;
}

@Param

type FrameButtonMetadata =
  | {
      action: 'link' | 'mint';
      label: string;
      target: string;
    }
  | {
      action?: 'post' | 'post_redirect';
      label: string;
    };

type FrameImageMetadata = {
  src: string;
  aspectRatio?: '1.91:1' | '1:1';
};

type FrameInputMetadata = {
  text: string;
};

type FrameMetadataType = {
  // A list of strings which are the label for the buttons in the frame (max 4 buttons).
  buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
  // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1
  image: FrameImageMetadata;
  // The text input to use for the Frame.
  input?: FrameInputMetadata;
  // A valid POST URL to send the Signature Packet to.
  postUrl?: string;
  // A period in seconds at which the app should expect the image to update.
  refreshPeriod?: number;
};

@Returns

type FrameMetadataResponse = Record<string, string>;


Identity Kit πŸ‘¨β€πŸš€

Name

The Name component is used to display ENS names associated with Ethereum addresses. When an ENS name is not available, it defaults to showing a truncated version of the address.

import { Name } from '@coinbase/onchainkit';

<Name address="0x1234567890abcdef1234567890abcdef12345678" sliced={false} />;

@Props

type UseName = {
  // Ethereum address to be resolved from ENS.
  address: Address;
  // Optional CSS class for custom styling.
  className?: string;
  // Determines if the address should be sliced when no ENS name is available.
  sliced?: boolean;
  // Additional HTML attributes for the span element.
  props?: React.HTMLAttributes<HTMLSpanElement>;
};

Avatar

The Avatar component is used to display ENS avatar associated with Ethereum addresses. When an ENS avatar is not available, it defaults to blue color avatar.

import { Avatar } from '@coinbase/onchainkit';

<Avatar address="0x1234567890abcdef1234567890abcdef12345678" />;

@Props

type UseAvatar = {
  // Ethereum address to be resolved from ENS.
  address: Address;
  // Optional CSS class for custom styling.
  className?: string;
  // Additional HTML attributes for the span element.
  props?: React.HTMLAttributes<HTMLSpanElement>;
};


The Team and Our Community ☁️ 🌁 ☁️

OnchainKit is all about community; for any questions, feel free to:

  1. Reach out to the core maintainers on Twitter or Farcaster

Leonardo Zizzamia

Rob Polak

Alvaro Raminelli

Taylor Caldwell

Chris Nascone

Wesley Pickett

License

This project is licensed under the MIT License - see the LICENSE.md file for details

About

OnchainKit is a collection of tools to build world-class onchain apps with CSS, React, and typescript.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 99.3%
  • JavaScript 0.7%