├── .gitignore
├── .husky
└── pre-commit
├── .prettierrc.yml
├── README.md
├── docs
├── .vitepress
│ ├── config.mts
│ └── theme
│ │ ├── custom.css
│ │ └── index.js
├── assets
│ ├── actions
│ │ ├── frame_type.png
│ │ └── message_type.png
│ ├── architecture.png
│ ├── contracts.png
│ ├── frame_app.png
│ ├── frame_og.png
│ ├── frame_poll.png
│ ├── gcp_compute_engine_api.png
│ ├── gcp_hubble_running.png
│ ├── gcp_project_id.png
│ ├── gcp_terraform_apply.png
│ ├── gcp_terraform_plan.png
│ ├── gcp_vm_overview.png
│ ├── google_cloud_shell.png
│ ├── high-level.png
│ ├── hub.png
│ ├── registry-contracts.png
│ └── usernames.png
├── auth-kit
│ ├── auth-kit-provider.md
│ ├── client
│ │ ├── app
│ │ │ ├── client.md
│ │ │ ├── create-channel.md
│ │ │ ├── status.md
│ │ │ ├── verify-sign-in-message.md
│ │ │ └── watch-status.md
│ │ ├── introduction.md
│ │ └── wallet
│ │ │ ├── authenticate.md
│ │ │ ├── build-sign-in-message.md
│ │ │ ├── client.md
│ │ │ └── parse-sign-in-uri.md
│ ├── examples.md
│ ├── hooks
│ │ ├── use-profile.md
│ │ ├── use-sign-in-message.md
│ │ └── use-sign-in.md
│ ├── index.md
│ ├── installation.md
│ ├── service-providers.md
│ └── sign-in-button.md
├── developers
│ ├── frames
│ │ ├── advanced.md
│ │ ├── best-practices.md
│ │ ├── frog_frame_preview.png
│ │ ├── getting-started.md
│ │ ├── index.md
│ │ ├── resources.md
│ │ ├── safari_frame.gif
│ │ └── spec.md
│ ├── guides
│ │ ├── accounts
│ │ │ ├── change-custody.md
│ │ │ ├── change-fname.md
│ │ │ ├── change-recovery.md
│ │ │ ├── create-account-key.md
│ │ │ ├── create-account.md
│ │ │ ├── find-by-name.md
│ │ │ └── register-ens.md
│ │ ├── advanced
│ │ │ ├── decode-key-metadata.md
│ │ │ └── query-signups.md
│ │ ├── apps
│ │ │ └── feed.md
│ │ ├── basics
│ │ │ └── hello-world.md
│ │ ├── querying
│ │ │ ├── fetch-casts.md
│ │ │ ├── fetch-channel-casts.md
│ │ │ └── fetch-profile.md
│ │ └── writing
│ │ │ ├── casts.md
│ │ │ ├── messages.md
│ │ │ ├── submit-messages.md
│ │ │ └── verify-address.md
│ ├── index.md
│ ├── resources.md
│ ├── siwf
│ │ ├── index.md
│ │ └── siwf_demo.avifs
│ └── utilities.md
├── examples
│ └── contracts
│ │ ├── clients.ts
│ │ ├── metadata.ts
│ │ └── signer.ts
├── index.md
├── learn
│ ├── architecture
│ │ ├── contracts.md
│ │ ├── ens-names.md
│ │ └── overview.md
│ ├── contributing
│ │ ├── fips.md
│ │ ├── governance.md
│ │ └── overview.md
│ ├── index.md
│ └── what-is-farcaster
│ │ ├── accounts.md
│ │ ├── apps.md
│ │ ├── channels.md
│ │ ├── messages.md
│ │ └── usernames.md
├── public
│ ├── icon.png
│ └── og-image.png
└── reference
│ ├── actions
│ └── spec.md
│ ├── contracts
│ ├── deployments.md
│ ├── faq.md
│ ├── index.md
│ └── reference
│ │ ├── bundler.md
│ │ ├── id-gateway.md
│ │ ├── id-registry.md
│ │ ├── key-gateway.md
│ │ ├── key-registry.md
│ │ ├── signed-key-request-validator.md
│ │ ├── storage-registry.md
│ │ └── tier-registry.md
│ ├── fname
│ └── api.md
│ ├── frames-redirect.md
│ ├── index.md
│ ├── replicator
│ └── schema.md
│ ├── third-party
│ └── neynar
│ │ └── index.md
│ └── warpcast
│ ├── api.md
│ ├── cast-composer-intents.md
│ ├── direct-casts.md
│ ├── embeds.md
│ ├── signer-requests.md
│ ├── signers.md
│ └── videos.md
├── package.json
├── vercel.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # node-waf configuration
29 | .lock-wscript
30 |
31 | # Compiled binary addons (https://nodejs.org/api/addons.html)
32 | build/Release
33 |
34 | # Dependency directories
35 | node_modules/
36 | jspm_packages/
37 |
38 | # TypeScript v1 declaration files
39 | typings/
40 |
41 | # TypeScript cache
42 | *.tsbuildinfo
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # Yarn Integrity file
57 | .yarn-integrity
58 |
59 | # dotenv environment variables file
60 | .env
61 | .env.test
62 |
63 | # parcel-bundler cache (https://parceljs.org/)
64 | .cache
65 |
66 |
67 | # Vitepress configuration files
68 | docs/.vitepress/dist
69 | docs/.vitepress/cache
70 |
71 | .DS_Store
72 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | yarn lint-staged
5 |
--------------------------------------------------------------------------------
/.prettierrc.yml:
--------------------------------------------------------------------------------
1 | semi: true
2 | trailingComma: 'es5'
3 | singleQuote: true
4 | printWidth: 80
5 | tabWidth: 2
6 | useTabs: false
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # docs.farcaster.xyz
2 |
3 | Documentation for the Farcaster Protocol
4 |
5 | ### Getting Started
6 |
7 | 1. Run `yarn`
8 | 2. Run `yarn docs:dev`
9 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/custom.css:
--------------------------------------------------------------------------------
1 | /* .vitepress/theme/custom.css */
2 |
3 |
4 | /**
5 | * Colors: Palette
6 | *
7 | * The primitive colors used for accent colors. These colors are referenced
8 | * by functional colors such as "Text", "Background", or "Brand".
9 | *
10 | * Each color have exact same color scale system with 3 levels of solid
11 | * colors with different brightness, and 1 soft color.
12 | *
13 | * - `XXX-1`: The most solid color used mainly for colored text. It must
14 | * satisfy the contrast ratio against when used on top of `XXX-soft`.
15 | *
16 | * - `XXX-2`: The color used mainly for hover state of the button.
17 | *
18 | * - `XXX-3`: The color for solid background, such as bg color of the button.
19 | * It must satisfy the contrast ratio with pure white (#ffffff) text on
20 | * top of it.
21 | *
22 | * - `XXX-soft`: The color used for subtle background such as custom container
23 | * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
24 | * on top of it.
25 | *
26 | * The soft color must be semi transparent alpha channel. This is crucial
27 | * because it allows adding multiple "soft" colors on top of each other
28 | * to create a accent, such as when having inline code block inside
29 | * custom containers.
30 | * -------------------------------------------------------------------------- */
31 |
32 | :root {
33 | --vp-c-purple-1: #8a63d2;
34 | --vp-c-purple-2: #6944BA;
35 | --vp-c-purple-3: #7C65C1;
36 | --vp-c-purple-soft: rgba(138, 99, 210, 0.2);
37 | }
38 |
39 |
40 | /**
41 | * Colors: Function
42 | *
43 | * - `default`: The color used purely for subtle indication without any
44 | * special meanings attached to it such as bg color for menu hover state.
45 | *
46 | * - `brand`: Used for primary brand colors, such as link text, button with
47 | * brand theme, etc.
48 | *
49 | * - `tip`: Used to indicate useful information. The default theme uses the
50 | * brand color for this by default.
51 | *
52 | * - `warning`: Used to indicate warning to the users. Used in custom
53 | * container, badges, etc.
54 | *
55 | * - `danger`: Used to show error, or dangerous message to the users. Used
56 | * in custom container, badges, etc.
57 | *
58 | * To understand the scaling system, refer to "Colors: Palette" section.
59 | * -------------------------------------------------------------------------- */
60 |
61 | :root {
62 | --vp-c-brand-1: var(--vp-c-purple-1);
63 | --vp-c-brand-2: var(--vp-c-purple-2);
64 | --vp-c-brand-3: var(--vp-c-purple-3);
65 | --vp-c-brand-soft: var(--vp-c-purple-soft);
66 |
67 | }
68 |
69 | :root {
70 | --vp-c-green: #8a63d2;
71 | --vp-c-green-light: #9c83d5;
72 | --vp-c-green-lighter: #c2b2e5;
73 | --vp-c-green-dark: #6950a3;
74 | --vp-c-green-darker: #5d468e;
75 | --vp-c-green-dimm-1: rgba(138, 99, 210, 0.05);
76 | --vp-c-green-dimm-2: rgba(138, 99, 210, 0.2);
77 | --vp-c-green-dimm-3: rgba(138, 99, 210, 0.5);
78 | }
79 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | // .vitepress/theme/index.js
2 | import DefaultTheme from 'vitepress/theme'
3 | import './custom.css'
4 |
5 | export default DefaultTheme
--------------------------------------------------------------------------------
/docs/assets/actions/frame_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/actions/frame_type.png
--------------------------------------------------------------------------------
/docs/assets/actions/message_type.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/actions/message_type.png
--------------------------------------------------------------------------------
/docs/assets/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/architecture.png
--------------------------------------------------------------------------------
/docs/assets/contracts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/contracts.png
--------------------------------------------------------------------------------
/docs/assets/frame_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/frame_app.png
--------------------------------------------------------------------------------
/docs/assets/frame_og.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/frame_og.png
--------------------------------------------------------------------------------
/docs/assets/frame_poll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/frame_poll.png
--------------------------------------------------------------------------------
/docs/assets/gcp_compute_engine_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/gcp_compute_engine_api.png
--------------------------------------------------------------------------------
/docs/assets/gcp_hubble_running.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/gcp_hubble_running.png
--------------------------------------------------------------------------------
/docs/assets/gcp_project_id.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/gcp_project_id.png
--------------------------------------------------------------------------------
/docs/assets/gcp_terraform_apply.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/gcp_terraform_apply.png
--------------------------------------------------------------------------------
/docs/assets/gcp_terraform_plan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/gcp_terraform_plan.png
--------------------------------------------------------------------------------
/docs/assets/gcp_vm_overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/gcp_vm_overview.png
--------------------------------------------------------------------------------
/docs/assets/google_cloud_shell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/google_cloud_shell.png
--------------------------------------------------------------------------------
/docs/assets/high-level.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/high-level.png
--------------------------------------------------------------------------------
/docs/assets/hub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/hub.png
--------------------------------------------------------------------------------
/docs/assets/registry-contracts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/registry-contracts.png
--------------------------------------------------------------------------------
/docs/assets/usernames.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/assets/usernames.png
--------------------------------------------------------------------------------
/docs/auth-kit/auth-kit-provider.md:
--------------------------------------------------------------------------------
1 | # `AuthKitProvider`
2 |
3 | Wrap your application in an `AuthKitProvider` to use Farcaster Auth. This provider component stores configuration information about your app and makes it available to auth-kit components and hooks.
4 |
5 | **Note:** You must create an `AuthKitProvider` to use Farcaster Connect. Don't forget to create one at the top level of your application.
6 |
7 | ```tsx
8 | const config = {
9 | domain: 'example.com',
10 | siweUri: 'https://example.com/login',
11 | rpcUrl: process.env.OP_MAINNET_RPC_URL,
12 | relay: 'https://relay.farcaster.xyz',
13 | };
14 |
15 | const App = () => {
16 | return (
17 | {/* Your App */}
18 | );
19 | };
20 | ```
21 |
22 | # Props
23 |
24 | | Prop | Type | Required | Description |
25 | | -------- | --------------- | -------- | --------------------------------------------------------- |
26 | | `config` | `AuthKitConfig` | No | Configuration object. See the options in the table below. |
27 |
28 | `config` object options:
29 |
30 | | Parameter | Type | Required | Description | Default |
31 | | --------- | -------- | -------- | ---------------------------------- | ----------------------------- |
32 | | `domain` | `string` | No | The domain of your application. | `window.location.host` |
33 | | `siweUri` | `string` | No | The login URL of your application. | `window.location.href` |
34 | | `relay` | `string` | No | Farcaster Auth relay server URL | `https://relay.farcaster.xyz` |
35 | | `rpcUrl` | `string` | No | Optimism RPC server URL | `https://mainnet.optimism.io` |
36 | | `version` | `string` | No | Farcaster Auth version | `v1` |
37 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/app/client.md:
--------------------------------------------------------------------------------
1 | # App Client
2 |
3 | If you're building a [connected app](https://docs.farcaster.xyz/learn/what-is-farcaster/apps#connected-apps) and want users to sign in with Farcaster, use an `AppClient`.
4 |
5 | You can use an `AppClient` to create a Farcaster Auth relay channel, generate a deep link to request a signature from the user's Farcaster wallet app, and verify the returned signature.
6 |
7 | ```ts
8 | import { createAppClient, viemConnector } from '@farcaster/auth-client';
9 |
10 | const appClient = createAppClient({
11 | relay: 'https://relay.farcaster.xyz',
12 | ethereum: viemConnector(),
13 | });
14 | ```
15 |
16 | ## Parameters
17 |
18 | | Parameter | Type | Description | Required |
19 | | ---------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
20 | | `ethereum` | `EthereumConnector` |
An Ethereum connector, used to query the Farcaster contracts and verify smart contract wallet signatures. `@farcaster/auth-client` currently provides only the `viem` connector type.
To use a custom RPC, pass an RPC URL to the viem connector.
| Yes |
21 | | `relay` | `string` | Relay server URL. Defaults to the public relay at `https://relay.farcaster.xyz` | No |
22 | | `version` | `string` | Farcaster Auth version. Defaults to `"v1"` | No |
23 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/app/create-channel.md:
--------------------------------------------------------------------------------
1 | # `createChannel`
2 |
3 | Create a Farcaster Auth relay channel.
4 |
5 | Returns a secret token identifying the channel, and a URI to display to the end user as a link or QR code.
6 |
7 | ```ts
8 | const channel = await appClient.createChannel({
9 | siweUri: 'https://example.com/login',
10 | domain: 'example.com',
11 | });
12 | ```
13 |
14 | ## Parameters
15 |
16 | | Parameter | Type | Description | Required | Example |
17 | | ------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------- |
18 | | `siweUri` | `string` | Login URL for your application. | Yes | `https://example.com/login` |
19 | | `domain` | `string` | Domain of your application. | Yes | `example.com` |
20 | | `nonce` | `string` | A custom nonce. Must be at least 8 alphanumeric characters. | No | `ESsxs6MaFio7OvqWb` |
21 | | `notBefore` | `string` | Start time at which the signature becomes valid. ISO 8601 datetime. | No | `2023-12-20T23:21:24.917Z` |
22 | | `expirationTime` | `string` | Expiration time at which the signature is no longer valid. ISO 8601 datetime. | No | `2023-12-20T23:21:24.917Z` |
23 | | `requestId` | `string` | A system specific ID your app can use to refer to the sign in request. | No | `8d0494d9-e0cf-402b-ab0a-394ac7fe07a0` |
24 | | `acceptAuthAddress` | `boolean` | Whether your application accepts signatures from an [auth address](https://github.com/farcasterxyz/protocol/discussions/225). | No | `true` |
25 |
26 | ## Returns
27 |
28 | ```ts
29 | {
30 | response: Response;
31 | data: {
32 | channelToken: string;
33 | url: string;
34 | nonce: string;
35 | }
36 | isError: boolean;
37 | error: Error;
38 | }
39 | ```
40 |
41 | | Parameter | Description |
42 | | ------------------- | --------------------------------------------------------------------------------------- |
43 | | `response` | HTTP response from the Connect relay server. |
44 | | `data.channelToken` | Connect relay channel token. |
45 | | `data.url` | Sign in With Farcaster URL to present to the user. Links to the Farcaster client in v1. |
46 | | `data.nonce` | Random nonce included in the Sign in With Farcaster message. |
47 | | `isError` | True when an error has occurred. |
48 | | `error` | `Error` instance. |
49 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/app/status.md:
--------------------------------------------------------------------------------
1 | # `status`
2 |
3 | Get the current status of a Farcaster Auth request.
4 |
5 | Returns the current state of the request, either `'pending'` if the user's Farcaster wallet app has not yet sent back a signature, or `'completed'` once the wallet app has returned a response.
6 |
7 | In `'completed'` state, the response includes the generated Sign in With Farcaster message, a signature from the user's custody address, the user's verified fid, and user profile information.
8 |
9 | ```ts
10 | const status = await appClient.status({
11 | channelToken: '23W59BKK',
12 | });
13 | ```
14 |
15 | ## Parameters
16 |
17 | | Parameter | Type | Description | Required | Example |
18 | | -------------- | -------- | ----------------------------- | -------- | -------------------------------------- |
19 | | `channelToken` | `string` | Farcaster Auth channel token. | Yes | `8d0494d9-e0cf-402b-ab0a-394ac7fe07a0` |
20 |
21 | ## Returns
22 |
23 | ```ts
24 | {
25 | response: Response
26 | data: {
27 | state: "pending";
28 | nonce: string;
29 | metadata: {
30 | ip: string;
31 | userAgent: string;
32 | };
33 | acceptAuthAddress: boolean;
34 | } | {
35 | state: "completed";
36 | nonce: string;
37 | url: string;
38 | message?: string;
39 | signature?: `0x${string}`;
40 | authMethod?: "custody" | "authAddress";
41 | fid?: number;
42 | username?: string;
43 | bio?: string;
44 | displayName?: string;
45 | pfpUrl?: string;
46 | verifications?: string[];
47 | custody?: Hex;
48 | signatureParams: {
49 | siweUri: string;
50 | domain: string;
51 | nonce?: string;
52 | notBefore?: string;
53 | expirationTime?: string;
54 | requestId?: string;
55 | redirectUrl?: string;
56 | };
57 | metadata: {
58 | ip: string;
59 | userAgent: string;
60 | };
61 | acceptAuthAddress: boolean;
62 | }
63 | isError: boolean
64 | error: Error
65 | }
66 | ```
67 |
68 | | Parameter | Description |
69 | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
70 | | `response` | HTTP response from the Connect relay server. |
71 | | `data.state` | Status of the sign in request, either `"pending"` or `"completed"` |
72 | | `data.nonce` | Random nonce used in the SIWE message. If you don't provide a custom nonce as an argument to the hook, you should read this value. |
73 | | `data.url` | URL of the application. |
74 | | `data.message` | The generated SIWE message. |
75 | | `data.signature` | Hex signature produced by the user's Farcaster client app wallet. |
76 | | `data.authMethod` | Auth method used to sign the message. Either `"custody"` or `"authAddress"`. |
77 | | `data.fid` | User's Farcaster ID. |
78 | | `data.username` | User's Farcaster username. |
79 | | `data.bio` | User's Farcaster bio. |
80 | | `data.displayName` | User's Farcaster display name. |
81 | | `data.pfpUrl` | User's Farcaster profile picture URL. |
82 | | `data.custody` | User's FID custody address. |
83 | | `data.verifications` | List of user's verified addresses. |
84 | | `data.signatureParams` | SIWF message parameters. |
85 | | `data.metadata.ip` | IP address of client request. |
86 | | `data.metadata.userAgent` | User agent of client request. |
87 | | `data.acceptAuthAddress` | `true` if requesting application accepts auth address signatures. |
88 | | `isError` | True when an error has occurred. |
89 | | `error` | `Error` instance. |
90 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/app/verify-sign-in-message.md:
--------------------------------------------------------------------------------
1 | # `verifySignInMessage`
2 |
3 | Verify a Sign In With Farcaster message. Your app should call this function and check that it succeeds after reading the message and signature provided by the user's Farcaster wallet over the Connect channel.
4 |
5 | Returns the parsed Sign in With Farcaster message, the user's fid, and whether the verification succeeded.
6 |
7 | ```ts
8 | const { data, success, fid } = await appClient.verifySignInMessage({
9 | nonce: 'abcd1234',
10 | domain: 'example.com',
11 | message: 'example.com wants you to sign in with your Ethereum account…',
12 | signature: '0x9335c3055d47780411a3fdabad293c68c84ea350a11794cd11fd51b…',
13 | acceptAuthAddress: true,
14 | });
15 | ```
16 |
17 | ## Parameters
18 |
19 | | Parameter | Type | Description | Required |
20 | | ------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
21 | | `domain` | `string` | Domain of your application. Must match the domain in the provided SIWF message. | Yes |
22 | | `nonce` | `string` | A custom nonce. Must match the nonce in the provided SIWF message. | Yes |
23 | | `message` | `string` or `SiweMessage` | The Sign in With Farcaster message to verify. This may be either a string or a parsed `SiweMessage`. Your app should read this value from the Connect channel once the request is completed. | Yes |
24 | | `signature` | `Hex` | Signature provided by the user's Farcaster wallet. Your app should read this from the Connect channel once the request is completed. | Yes |
25 | | `acceptAuthAddress` | `boolean` | Pass `true` to accept an [auth address](https://github.com/farcasterxyz/protocol/discussions/225) signature in addition to a custody address signature. | No |
26 |
27 | ## Returns
28 |
29 | ```ts
30 | {
31 | data: SiweMessage,
32 | success: boolean,
33 | fid: number
34 | isError: boolean
35 | error: Error
36 | }
37 | ```
38 |
39 | | Parameter | Description |
40 | | --------- | ----------------------------------------------- |
41 | | `data` | Parsed SIWF message, as a `SiweMessage` object. |
42 | | `success` | True if the provided signature is valid. |
43 | | `fid` | FID of the user. |
44 | | `isError` | True when an error has occurred. |
45 | | `error` | `Error` instance. |
46 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/app/watch-status.md:
--------------------------------------------------------------------------------
1 | # `watchStatus`
2 |
3 | Poll for the current status of a Farcaster Auth request.
4 |
5 | When the status changes to `'complete'` this action resolves with the final channel value, including the Sign In With Farcaster message, signature, and user profile information.
6 |
7 | ```ts
8 | const status = await appClient.watchStatus({
9 | channelToken: '210f1718-427e-46a4-99e3-2207f21f83ec',
10 | timeout: 60_000,
11 | interval: 1_000,
12 | onResponse: ({ response, data }) => {
13 | console.log('Response code:', response.status);
14 | console.log('Status data:', data);
15 | },
16 | });
17 | ```
18 |
19 | ## Parameters
20 |
21 | | Parameter | Type | Description | Required | Example |
22 | | -------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------- |
23 | | `channelToken` | `string` | Farcaster Auth channel token. | Yes | `8d0494d9-e0cf-402b-ab0a-394ac7fe07a0` |
24 | | `timeout` | `number` | Polling timeout, in milliseconds. If the connect request is not completed before the timeout, `watchStatus` returns an error. | No | `300_000` |
25 | | `interval` | `number` | Polling interval, in milliseconds. The client will check for updates at this frequency. | No | `1_000` |
26 | | `onResponse` | `function` | Callback function invoked each time the client polls for an update and receives a response from the relay server. Receives the return value of the latest `status` request. | No | `({ data }) => console.log(data.fid)` |
27 |
28 | ## Returns
29 |
30 | ```ts
31 | {
32 | response: Response
33 | data: {
34 | state: "pending";
35 | nonce: string;
36 | metadata: {
37 | ip: string;
38 | userAgent: string;
39 | };
40 | acceptAuthAddress: boolean;
41 | } | {
42 | state: "completed";
43 | nonce: string;
44 | url: string;
45 | message?: string;
46 | signature?: `0x${string}`;
47 | authMethod?: "custody" | "authAddress";
48 | fid?: number;
49 | username?: string;
50 | bio?: string;
51 | displayName?: string;
52 | pfpUrl?: string;
53 | verifications?: string[];
54 | custody?: Hex;
55 | signatureParams: {
56 | siweUri: string;
57 | domain: string;
58 | nonce?: string;
59 | notBefore?: string;
60 | expirationTime?: string;
61 | requestId?: string;
62 | redirectUrl?: string;
63 | };
64 | metadata: {
65 | ip: string;
66 | userAgent: string;
67 | };
68 | acceptAuthAddress: boolean;
69 | }
70 | isError: boolean
71 | error: Error
72 | }
73 | ```
74 |
75 | | Parameter | Description |
76 | | ------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
77 | | `response` | HTTP response from the Connect relay server. |
78 | | `data.state` | Status of the sign in request, either `"pending"` or `"completed"` |
79 | | `data.nonce` | Random nonce used in the SIWE message. If you don't provide a custom nonce as an argument, you should read this value. |
80 | | `data.url` | URL of the application. |
81 | | `data.message` | The generated SIWE message. |
82 | | `data.signature` | Hex signature produced by the user's Warpcast wallet. |
83 | | `data.authMethod` | Auth method used to sign the message. Either `"custody"` or `"authAddress"`. |
84 | | `data.fid` | User's Farcaster ID. |
85 | | `data.username` | User's Farcaster username. |
86 | | `data.bio` | User's Farcaster bio. |
87 | | `data.displayName` | User's Farcaster display name. |
88 | | `data.pfpUrl` | User's Farcaster profile picture URL. |
89 | | `data.custody` | User's FID custody address. |
90 | | `data.verifications` | List of user's verified addresses. |
91 | | `data.signatureParams` | SIWF message parameters. |
92 | | `data.metadata.ip` | IP address of client request. |
93 | | `data.metadata.userAgent` | User agent of client request. |
94 | | `data.acceptAuthAddress` | `true` if requesting application accepts auth address signatures. |
95 | | `isError` | True when an error has occurred. |
96 | | `error` | `Error` instance. |
97 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/introduction.md:
--------------------------------------------------------------------------------
1 | # Auth client
2 |
3 | [](https://www.npmjs.com/package/@farcaster/auth-client)
4 |
5 | The `@farcaster/auth-client` library provides a framework agnostic client for Farcaster Auth. If you're not using React, want greater customizability, or want to interact with the Farcaster Auth relay directly, you can use the Auth client library to build your own Sign in With Farcaster flow.
6 |
7 | ## Getting Started
8 |
9 | ### Installation
10 |
11 | Install the Auth client and its peer dependency [viem](https://viem.sh/).
12 |
13 | ```sh
14 | npm install @farcaster/auth-client viem
15 | ```
16 |
17 | **Note:** This is a low level client library. If you're using React, take a look at [auth-kit](../) instead.
18 |
19 | ### Create a client
20 |
21 | Set up a client with a relay server URL and Ethereum connector.
22 |
23 | ```tsx
24 | import { createAppClient, viemConnector } from '@farcaster/auth-client';
25 |
26 | const appClient = createAppClient({
27 | relay: 'https://relay.farcaster.xyz',
28 | ethereum: viemConnector(),
29 | });
30 | ```
31 |
32 | Depending on the type of app you're building, you may use an `AppClient` or a `WalletClient`. If you're building a connected app and logging in users, use an _app client_. If you're building a Farcaster wallet app, use a _wallet client_.
33 |
34 | ### Consume actions
35 |
36 | Now that your client is set up, you can use it to interact with Farcaster Auth actions.
37 |
38 | ```tsx
39 | const { data: { channelToken } } = await appClient.createChannel({
40 | siweUri: "https://example.com/login",
41 | domain: "example.com";
42 | });
43 |
44 | const status = await appClient.watchStatus({
45 | channelToken,
46 | });
47 | ```
48 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/wallet/authenticate.md:
--------------------------------------------------------------------------------
1 | # `authenticate`
2 |
3 | Submit a Sign In With Farcaster message, user signature, and profile data to the Connect relay server.
4 |
5 | ```ts
6 | const params = await walletClient.authenticate({
7 | message: 'example.com wants you to sign in with your Ethereum account…',
8 | signature: '0x9335c3055d47780411a3fdabad293c68c84ea350a11794cdc811fd5…',
9 | authMethod: 'authAddress',
10 | fid: 1,
11 | username: 'alice',
12 | bio: "I'm a little teapot who didn't fill out my bio",
13 | displayName: 'Alice Teapot',
14 | pfpUrl: 'https://images.example.com/profile.png',
15 | });
16 | ```
17 |
18 | ## Parameters
19 |
20 | | Parameter | Type | Description | Required |
21 | | -------------- | -------- | -------------------------------------------------------------------------------------------------------------- | -------- |
22 | | `authKey` | `string` | Farcaster Auth API key. Farcaster Auth v1 restricts calls to `/authenticate` to the official Farcaster client. | Yes |
23 | | `channelToken` | `string` | Farcaster Auth channel token. | Yes |
24 | | `message` | `string` | The Sign in With Farcaster message produced by your wallet app and signed by the user. | Yes |
25 | | `signature` | `Hex` | SIWE signature created by the wallet user's account. | Yes |
26 | | `authMethod` | `string` | Method used to sign the SIWF message. Either `"custody"` or `"authAddress"`. | Yes |
27 | | `fid` | `number` | Wallet user's fid. | Yes |
28 | | `username` | `string` | Wallet user's Farcaster username. | Yes |
29 | | `bio` | `string` | Wallet user's bio. | Yes |
30 | | `displayName` | `string` | Wallet user's display name. | Yes |
31 | | `pfpUrl` | `string` | Wallet user's profile photo URL. | Yes |
32 |
33 | ## Returns
34 |
35 | ```ts
36 | {
37 | response: Response
38 | data: {
39 | state: 'completed'
40 | nonce: string
41 | message?: string
42 | signature?: `Hex`
43 | fid?: number
44 | username?: string
45 | bio?: string
46 | displayName?: string
47 | pfpUrl?: string
48 | }
49 | isError: boolean
50 | error: Error
51 | }
52 | ```
53 |
54 | | Parameter | Description |
55 | | ------------------ | ----------------------------------------------------------------- |
56 | | `response` | HTTP response from the Connect relay server. |
57 | | `data.state` | Status of the sign in request, either `"pending"` or `"complete"` |
58 | | `data.nonce` | Random nonce used in the SIWE message. |
59 | | `data.message` | The generated SIWE message. |
60 | | `data.signature` | Hex signature produced by the user's Farcaster client app wallet. |
61 | | `data.fid` | User's Farcaster ID. |
62 | | `data.username` | User's Farcaster username. |
63 | | `data.bio` | User's Farcaster bio. |
64 | | `data.displayName` | User's Farcaster display name. |
65 | | `data.pfpUrl` | User's Farcaster profile picture URL. |
66 | | `isError` | True when an error has occurred. |
67 | | `error` | `Error` instance. |
68 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/wallet/build-sign-in-message.md:
--------------------------------------------------------------------------------
1 | # `buildSignInMessage`
2 |
3 | Build a Sign In With Farcaster message to present to the end user for signing.
4 |
5 | Adds required Sign In With Farcaster message attributes to any provided parameters. You should parse most of these parameters from a provided protocol URI. Your wallet app must provide the user's custody address and fid.
6 |
7 | Returns a `SiweMessage` object and the message as a string.
8 |
9 | ```ts
10 | const { siweMessage, message } = walletClient.buildSignInMessage({
11 | address: '0x63C378DDC446DFf1d831B9B96F7d338FE6bd4231',
12 | fid: 1,
13 | uri: 'https://example.com/login',
14 | domain: 'example.com',
15 | nonce: 'ESsxs6MaFio7OvqWb',
16 | });
17 | ```
18 |
19 | ## Parameters
20 |
21 | | Parameter | Type | Description | Required |
22 | | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
23 | | `address` | `Hex` | Wallet user's custody address. This address must be the same account that signs the generated Sign In With Farcaster message. Your wallet app should provide the custody address of the authenticated user. | Yes |
24 | | `fid` | `string` | Wallet user's fid. Your wallet app should provide the fid of the authenticated user. | Yes |
25 | | `uri` | `string` | Login URL of the relying connected app. Parse this from the provided Sign In With Farcaster URI. | Yes |
26 | | `domain` | `string` | Domain of the relying connected app. Parse this from the provided Sign In With Farcaster URI. | Yes |
27 | | `nonce` | `string` | Random nonce to include in the Sign In With Farcaster message. Must be at least 8 alphanumeric characters. Parse this from the provided Sign In With Farcaster URI. | Yes |
28 | | `notBefore` | `string` | Start time at which the SIWE signature becomes valid. ISO 8601 datetime. Parse this from the provided Sign In With Farcaster URI. | No |
29 | | `expirationTime` | `string` | Expiration time after which the SIWE signature becomes valid. ISO 8601 datetime. Parse this from the provided Sign In With Farcaster URI. | No |
30 | | `requestId` | `string` | A system specific ID provided by the relying app. Parse this from the provided Sign In With Farcaster URI. | No |
31 |
32 | ## Returns
33 |
34 | ```ts
35 | {
36 | siweMessage: SiweMessage;
37 | message: string;
38 | isError: boolean;
39 | error: Error;
40 | }
41 | ```
42 |
43 | | Parameter | Description |
44 | | ------------- | ------------------------------------------------- |
45 | | `siweMessage` | Constructed Sign In With Ethereum message object. |
46 | | `message` | SIWE message serialized as a string. |
47 | | `isError` | True when an error has occurred. |
48 | | `error` | `Error` instance. |
49 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/wallet/client.md:
--------------------------------------------------------------------------------
1 | # Wallet Client
2 |
3 | If you're building a [wallet app](https://docs.farcaster.xyz/learn/what-is-farcaster/apps#wallet-apps) and receiving signature requests, use a `WalletClient`.
4 |
5 | You can use a `WalletClient` to parse an incoming Sign In With Farcaster request URL, build a Sign In With Farcaster message to present to the user, and submit the signed message to a Farcaster Auth relay channel.
6 |
7 | ```ts
8 | import { createWalletClient, viemConnector } from '@farcaster/auth-client';
9 |
10 | const walletClient = createWalletClient({
11 | relay: 'https://relay.farcaster.xyz',
12 | ethereum: viemConnector(),
13 | });
14 | ```
15 |
16 | ## Parameters
17 |
18 | | Parameter | Type | Description | Required |
19 | | ---------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
20 | | `ethereum` | `EthereumConnector` |
An Ethereum connector, used to query the Farcaster contracts and verify smart contract wallet signatures. `@farcaster/auth-client` currently provides only the `viem` connector type.
To use a custom RPC, pass an RPC URL to the viem connector.
| Yes |
21 | | `relay` | `string` | Relay server URL. Defaults to the public relay at `https://relay.farcaster.xyz` | No |
22 | | `version` | `string` | Farcaster Auth version. Defaults to `"v1"` | No |
23 |
--------------------------------------------------------------------------------
/docs/auth-kit/client/wallet/parse-sign-in-uri.md:
--------------------------------------------------------------------------------
1 | # `parseSignInURI`
2 |
3 | Parse the Sign In With Farcaster URI provided by a connected app user.
4 |
5 | Returns the parsed parameters. Your app should use these to construct a Sign In With Farcaster message.
6 |
7 | Returns an error if URI is invalid.
8 |
9 | ```ts
10 | const params = walletClient.parseSignInURI({
11 | uri: 'farcaster://connect?channelToken=23W59BKK&nonce=ESsxs6MaFio7OvqWb&siweUri=https%3A%2F%2Fexample.com%2Flogin&domain=example.com',
12 | });
13 | ```
14 |
15 | ## Parameters
16 |
17 | | Parameter | Type | Description | Required |
18 | | --------- | -------- | --------------------------- | -------- |
19 | | `uri` | `string` | Sign In With Farcaster URI. | Yes |
20 |
21 | ## Returns
22 |
23 | ```ts
24 | {
25 | channelToken: string
26 | params: {
27 | domain: string
28 | uri: string
29 | nonce: string
30 | notBefore?: string
31 | expirationTime?: string
32 | requestId?: string
33 | }
34 | isError: boolean
35 | error: Error
36 | }
37 | ```
38 |
39 | | Parameter | Description |
40 | | ----------------------- | ----------------------------------------------------------------- |
41 | | `channelToken` | Connect relay channel token. |
42 | | `params.uri` | Login URI of the relying connected app. |
43 | | `params.domain` | Domain of the relying app. |
44 | | `params.nonce` | Random nonce provided by the relying app. |
45 | | `params.notBefore` | Time at which this message becomes valid. |
46 | | `params.expirationTime` | Time at which this message expires. |
47 | | `params.requestId` | A system specific identifier provided by the relying application. |
48 | | `isError` | True when an error has occurred. |
49 | | `error` | `Error` instance. |
50 |
--------------------------------------------------------------------------------
/docs/auth-kit/examples.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | ## Client Side
4 |
5 | A frontend-only app that lets users Sign in with Farcaster and shows them their profile picture and username.
6 |
7 |
8 |
9 | [Try Demo](https://farcaster-auth-kit-vite-demo.replit.app/) | [View Source](https://github.com/farcasterxyz/connect-monorepo/tree/main/examples/frontend-only)
10 |
11 | ## Server Side
12 |
13 | A Next.js app that lets users Sign in with Farcaster and handles sessions server-side.
14 |
15 |
16 |
17 | [Try Demo](https://farcaster-auth-kit-next-auth-demo.replit.app/) | [View Source](https://github.com/farcasterxyz/connect-monorepo/tree/main/examples/with-next-auth)
18 |
--------------------------------------------------------------------------------
/docs/auth-kit/hooks/use-profile.md:
--------------------------------------------------------------------------------
1 | # `useProfile`
2 |
3 | Hook for reading information about the authenticated user.
4 |
5 | You can use this hook to read the authenticated user's profile information from other components inside your app.
6 |
7 | ```tsx
8 | import { useProfile } from '@farcaster/auth-kit';
9 |
10 | function App() {
11 | const {
12 | isAuthenticated,
13 | profile: { username, fid, bio, displayName, pfpUrl },
14 | } = useProfile();
15 |
16 | return (
17 |
18 | {isAuthenticated ? (
19 |
20 | Hello, {username}! Your fid is: {fid}
21 |
22 | ) : (
23 |
You're not signed in.
24 | )}
25 |
26 | );
27 | }
28 | ```
29 |
30 | ## Returns
31 |
32 | ```ts
33 | {
34 | isAuthenticated: boolean;
35 | profile?: {
36 | fid?: number;
37 | username?: string;
38 | bio?: string;
39 | displayName?: string;
40 | pfpUrl?: string;
41 | custody?: Hex;
42 | verifications?: Hex[];
43 | },
44 | };
45 | ```
46 |
47 | | Parameter | Description |
48 | | ----------------------- | ---------------------------------- |
49 | | `isAuthenticated` | True when the user is logged in. |
50 | | `profile.fid` | User's Farcaster ID. |
51 | | `profile.username` | User's username. |
52 | | `profile.bio` | User's bio text. |
53 | | `profile.displayName` | User's display name. |
54 | | `profile.pfpUrl` | User's profile picture URL. |
55 | | `profile.custody` | User's FID custody address. |
56 | | `profile.verifications` | List of user's verified addresses. |
57 |
--------------------------------------------------------------------------------
/docs/auth-kit/hooks/use-sign-in-message.md:
--------------------------------------------------------------------------------
1 | # `useSignInMessage`
2 |
3 | Hook for reading the Sign in With Farcaster message and signature used to authenticate the user.
4 |
5 | If you're providing the message and signature to a backend API, you may want to use this hook.
6 |
7 | ```tsx
8 | import { useSignInMessage } from '@farcaster/auth-kit';
9 |
10 | function App() {
11 | const { message, signature } = useSignInMessage();
12 |
13 | return (
14 |
15 |
You signed: {message}
16 |
Your signature: {signature}
17 |
18 | );
19 | }
20 | ```
21 |
22 | ## Returns
23 |
24 | ```ts
25 | {
26 | message: string;
27 | signature: Hex;
28 | }
29 | ```
30 |
31 | | Parameter | Description |
32 | | ----------- | -------------------------------------------------- |
33 | | `message` | SIWE message signed by the user. |
34 | | `signature` | Signature produced by the user's Farcaster wallet. |
35 |
--------------------------------------------------------------------------------
/docs/auth-kit/hooks/use-sign-in.md:
--------------------------------------------------------------------------------
1 | # `useSignIn`
2 |
3 | Hook for signing in a user. Connects to the relay server, generates a sign in link to present to the user, and polls the relay server for the user's Farcaster wallet signature.
4 |
5 | If you want to build your own sign in component with a custom UI, use the `useSignIn` hook.
6 |
7 | ```tsx
8 | import { useSignIn, QRCode } from '@farcaster/auth-kit';
9 |
10 | function App() {
11 | const {
12 | signIn,
13 | url,
14 | data: { username },
15 | } = useSignIn({
16 | onSuccess: ({ fid }) => console.log('Your fid:', fid),
17 | });
18 |
19 | return (
20 |
29 | );
30 | }
31 | ```
32 |
33 | ## Parameters
34 |
35 | | Parameter | Type | Description | Default |
36 | | ------------------ | ---------- | ----------------------------------------------------------------------------------- | --------------------- |
37 | | `timeout` | `number` | Return an error after polling for this long. | `300_000` (5 minutes) |
38 | | `interval` | `number` | Poll the relay server for updates at this interval. | `1500` (1.5 seconds) |
39 | | `nonce` | `string` | A random nonce to include in the Sign In With Farcaster message. | None |
40 | | `notBefore` | `string` | Time when the SIWF message becomes valid. ISO 8601 datetime string. | None |
41 | | `expirationTime` | `string` | Time when the SIWF message expires. ISO 8601 datetime string. | None |
42 | | `requestId` | `string` | An optional system-specific ID to include in the SIWF message. | None |
43 | | `onSuccess` | `function` | Callback invoked when sign in is complete and the user is authenticated. | None |
44 | | `onStatusResponse` | `function` | Callback invoked when the component receives a status update from the relay server. | None |
45 | | `onError` | `function` | Error callback function. | None |
46 |
47 | ## Returns
48 |
49 | ```ts
50 | {
51 | signIn: () => void;
52 | signOut: () => void;
53 | connect: () => void;
54 | reconnect: () => void;
55 | isConnected: boolean;
56 | isSuccess: boolean;
57 | isPolling: boolean;
58 | isError: boolean;
59 | error: AuthClientError;
60 | channelToken: string;
61 | url: string;
62 | appClient: AppClient;
63 | data: {
64 | state: "pending" | "complete";
65 | nonce: string;
66 | message: string;
67 | signature: Hex;
68 | fid: number;
69 | username: string;
70 | bio: string;
71 | displayName: string;
72 | pfpUrl: string;
73 | custody?: Hex;
74 | verifications?: Hex[];
75 | },
76 | validSignature: boolean;
77 | };
78 | ```
79 |
80 | | Parameter | Description |
81 | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
82 | | `signIn` | Call this function following `connect` to begin polling for a signature. |
83 | | `signOut` | Call this function to clear the AuthKit state and sign out the user. |
84 | | `connect` | Connect to the auth relay and create a channel. |
85 | | `reconnect` | Reconnect to the relay and try again. Call this in the event of an error. |
86 | | `isConnected` | True if AuthKit is connected to the relay server and has an active channel. |
87 | | `isSuccess` | True when the relay server returns a valid signature. |
88 | | `isPolling` | True when the relay state is `"pending"` and the app is polling the relay server for a response. |
89 | | `isError` | True when an error has occurred. |
90 | | `error` | `AuthClientError` instance. |
91 | | `channelToken` | Connect relay channel token. |
92 | | `url` | Sign in With Farcaster URL to present to the user. Links to the Farcaster client in v1. |
93 | | `appClient` | Underlying `AppClient` instance. |
94 | | `data.state` | Status of the sign in request, either `"pending"` or `"complete"` |
95 | | `data.nonce` | Random nonce used in the SIWE message. If you don't provide a custom nonce as an argument to the hook, you should read this value. |
96 | | `data.message` | The generated SIWE message. |
97 | | `data.signature` | Hex signature produced by the user's Farcaster client app wallet. |
98 | | `data.fid` | User's Farcaster ID. |
99 | | `data.username` | User's Farcaster username. |
100 | | `data.bio` | User's Farcaster bio. |
101 | | `data.displayName` | User's Farcaster display name. |
102 | | `data.pfpUrl` | User's Farcaster profile picture URL. |
103 | | `data.custody` | User's FID custody address. |
104 | | `data.verifications` | List of user's verified addresses. |
105 | | `validSignature` | True when the signature returned by the relay server is valid. |
106 |
--------------------------------------------------------------------------------
/docs/auth-kit/index.md:
--------------------------------------------------------------------------------
1 | # AuthKit
2 |
3 | [](https://www.npmjs.com/package/@farcaster/auth-kit)
4 |
5 | AuthKit is a React library that lets users log in to your app with a Farcaster account.
6 |
7 |
8 |
9 | Click "Sign in With Farcaster" above to try it out on web or click [here](https://sign-in-with-farcaster-demo.replit.app/) for mobile.
10 |
11 | ### How does it work?
12 |
13 | It uses the [Sign In With Farcaster](#sign-in-with-farcaster-siwf) standard under the hood, which is conceptually like "Sign in with Google". When integrated, AuthKit will:
14 |
15 | 1. Show a "Sign in with Farcaster" button to the user.
16 | 2. Wait for the user to click, scan a QR code and approve the request in Warpcast.
17 | 3. Receive and verify a signature from Warpcast.
18 | 4. Show the logged in user's profile picture and username.
19 |
--------------------------------------------------------------------------------
/docs/auth-kit/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | Install auth-kit and its peer dependency [viem](https://viem.sh/).
4 |
5 | ```sh
6 | npm install @farcaster/auth-kit viem
7 | ```
8 |
9 | **Note:** auth-kit is a [React](https://react.dev/) library. If you're using a different framework, take a look at the [client library](./client/introduction.md) instead.
10 |
11 | ### 1. Import the libraries
12 |
13 | Import auth-kit and CSS styles.
14 |
15 | ```tsx
16 | import '@farcaster/auth-kit/styles.css';
17 | import { AuthKitProvider } from '@farcaster/auth-kit';
18 | import { SignInButton } from '@farcaster/auth-kit';
19 | ```
20 |
21 | ### 2. Configure your provider
22 |
23 | Configure a provider with an Optimism RPC URL, your app's domain and login URL, and wrap your application in it.
24 |
25 | ```tsx
26 | const config = {
27 | rpcUrl: 'https://mainnet.optimism.io',
28 | domain: 'example.com',
29 | siweUri: 'https://example.com/login',
30 | };
31 |
32 | const App = () => {
33 | return (
34 | {/* Your App */}
35 | );
36 | };
37 | ```
38 |
39 | ### 3. Add a connect button
40 |
41 | Render the `SignInButton` component. When the user clicks this button, they will be prompted to complete sign in using their Farcaster wallet application.
42 |
43 | ```tsx
44 | export const Login = () => {
45 | return ;
46 | };
47 | ```
48 |
49 | ### 4. Read user profile
50 |
51 | Optionally, fetch details about the logged in user anywhere in your app with `useProfile`.
52 |
53 | ```tsx
54 | import { useProfile } from '@farcaster/auth-kit';
55 |
56 | export const UserProfile = () => {
57 | const {
58 | isAuthenticated,
59 | profile: { username, fid },
60 | } = useProfile();
61 | return (
62 |
63 | {isAuthenticated ? (
64 |
65 | Hello, {username}! Your fid is: {fid}
66 |
67 | ) : (
68 |
You're not signed in.
69 | )}
70 |
71 | );
72 | };
73 | ```
74 |
--------------------------------------------------------------------------------
/docs/auth-kit/service-providers.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | In addition to the core AuthKit implementation, "Sign in With Farcaster" can be implemented through multiple service providers and combined with additional functionality and login methods.
4 |
5 | # Providers
6 |
7 | Below is a list of providers that currently support "Sign in With Farcaster" functionality as part of their product suite.
8 |
9 | - [Dynamic](https://docs.dynamic.xyz/guides/integrations/sign-in-with-farcaster)
10 | - [Neynar](https://docs.neynar.com/docs/how-to-let-users-connect-farcaster-accounts-with-write-access-for-free-using-sign-in-with-neynar-siwn)
11 | - [Privy](https://docs.privy.io/guide/react/recipes/misc/farcaster)
12 | - [Web3auth](https://web3auth.io/docs/guides/farcaster-sfa-web)
13 | - [ThirdWeb](https://github.com/thirdweb-example/thirdweb-siwf)
14 |
--------------------------------------------------------------------------------
/docs/auth-kit/sign-in-button.md:
--------------------------------------------------------------------------------
1 | # `SignInButton`
2 |
3 | The main component. Renders a "Sign in With Farcaster" button that prompts the user to scan a QR code with their phone in a web browser or redirects to a mobile device. You can use the `onSuccess` callback prop or the `useProfile` hook to access the user's authentication status and profile information.
4 |
5 | **Note:** Make sure you've wrapped your application in an [`AuthKitProvider`](./auth-kit-provider.md) to use the `SignInButton` component.
6 |
7 | ```tsx
8 | import { SignInButton } from '@farcaster/auth-kit';
9 |
10 | export const Login = () => {
11 | return (
12 |
14 | console.log(`Hello, ${username}! Your fid is ${fid}.`)
15 | }
16 | />
17 | );
18 | };
19 | ```
20 |
21 | ## Props
22 |
23 | | Prop | Type | Description | Default |
24 | | ------------------ | ---------- | ----------------------------------------------------------------------------------- | --------------------- |
25 | | `timeout` | `number` | Return an error after polling for this long. | `300_000` (5 minutes) |
26 | | `interval` | `number` | Poll the relay server for updates at this interval. | `1500` (1.5 seconds) |
27 | | `nonce` | `string` | A random nonce to include in the Sign In With Farcaster message. | None |
28 | | `notBefore` | `string` | Time when the message becomes valid. ISO 8601 datetime string. | None |
29 | | `expirationTime` | `string` | Time when the message expires. ISO 8601 datetime string. | None |
30 | | `requestId` | `string` | An optional system-specific ID to include in the message. | None |
31 | | `onSuccess` | `function` | Callback invoked when sign in is complete and the user is authenticated. | None |
32 | | `onStatusResponse` | `function` | Callback invoked when the component receives a status update from the relay server. | None |
33 | | `onError` | `function` | Error callback function. | None |
34 | | `onSignOut` | `function` | Callback invoked when the user signs out. | None |
35 | | `hideSignOut` | `function` | Hide the Sign out button. | `false` |
36 | | `debug` | `boolean` | Render a debug panel displaying internal auth-kit state. | `false` |
37 |
38 | ## Examples
39 |
40 | ### Custom nonce
41 |
42 | ```tsx
43 | import { SignInButton } from '@farcaster/auth-kit';
44 |
45 | export const Login = ({ nonce }: { nonce: string }) => {
46 | return (
47 |
50 | console.log(`Hello, ${username}! Your fid is ${fid}.`)
51 | }
52 | />
53 | );
54 | };
55 | ```
56 |
--------------------------------------------------------------------------------
/docs/developers/frames/advanced.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Frames Advanced Topics
3 | ---
4 |
5 | # Advanced Topics
6 |
7 | Advanced topics for building sophisticated Farcaster Frames.
8 |
9 | #### Making the initial Frame image dynamic
10 |
11 | When a Frame is shared in a cast the metadata for it will generally be scraped
12 | and cached so that it can be rendered into users feeds without additional
13 | loading. This means whatever URL is set on the initial frame will always be
14 | rendered.
15 |
16 | In order to make the initial image dynamic you'll need to:
17 |
18 | - serve a dynamic image at a static URL
19 | - set an appropriate cache header
20 |
21 | An example, imagine you want to build a frame where the initial frame shows the
22 | current price of ETH. For the initial frame you'd set a static image url
23 | like `https://example.xyz/eth-price.png`. When a GET request is made to this endpoint:
24 |
25 | - the server fetches the latest ETH price from a cache
26 | - renders an image using a tool like [Vercel OG](https://vercel.com/docs/functions/og-image-generation) and returns it
27 | - sets the following header: `Cache-Control: public, immutable, no-transform, max-age=60`
28 |
29 | We recommend setting a non-zero `max-age` so that the image can get cached and
30 | served from CDNs, otherwise users will see a gray image in their feed while the
31 | dynamic image is generated and loads. The exact time depends on your
32 | application but opt for the longest time that still keeps the image reasonably
33 | fresh.
34 |
35 | #### Avoid caching error images when generating dynamic images at static URLs
36 |
37 | If you have a static URL that generates a dynamic image and you use a fallback
38 | image for cases when you're unable to generate the image, you should set
39 | `max-age=0` in the `Cache-Control` header so it does not get cached.
40 |
41 | As an example, let's say you generate a dynamic image at `/img/eth-price` that
42 | shows a 24hr chart for the price of ETH. Normally you want this image to be
43 | cached for 5 minutes. However, if the ETH price data is unavailable and you
44 | render a fallback image you don't want the request cached so that you can try
45 | again in subsequent requests.
46 |
47 | #### Data persistence
48 |
49 | [Vercel KV](https://vercel.com/docs/storage/vercel-kv) and [Cloudflare Workers
50 | KV](https://developers.cloudflare.com/kv/) are convenient options for adding a
51 | simple persistence layer to your Frame server.
52 |
--------------------------------------------------------------------------------
/docs/developers/frames/best-practices.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Frame Best Practices
3 | ---
4 |
5 | # Frame Best Practices
6 |
7 | Learn best practices for building great Frame experiences.
8 |
9 | ::: info
10 | These best practices assume a prior knowledge of Frames. If you're looking for
11 | general information about building Frames check out these resources:
12 |
13 | - [Getting Started](./getting-started)
14 | - [Frames Specification](./spec)
15 | - guides from [frames.js](https://framesjs.org/guides/create-frame) or [frog](https://frog.fm/concepts/overview)
16 | :::
17 |
18 | ## UI / UX
19 |
20 | #### Follow the Frame Interface Guidelines (FIG)
21 |
22 | The [FIG](https://github.com/paradigmxyz/Fig) provides comprehensive guidance that can help you design a great
23 | experience for frames. It covers everything from [foundational
24 | topics](https://github.com/paradigmxyz/Fig?tab=readme-ov-file#foundations) like
25 | layout and typography to [best practices when working with
26 | transactions.](https://github.com/paradigmxyz/Fig?tab=readme-ov-file#patterns)
27 |
28 | #### Optimize performance
29 |
30 | Make your frame respond to the user as fast as possible. Review and implement
31 | the [performance best practices](#performance).
32 |
33 | #### Use reusable styles and components
34 |
35 | Building a set of reusable styles and components can help you move fast and build
36 | consistent interfaces.
37 |
38 | [FrogUI](https://frog.fm/ui) is an extension of the Frog Framework that provides a theme-able
39 | set of primitive components.
40 |
41 | ## Performance Best Practices
42 |
43 | ::: tip
44 | Don't worry about these recommendations if you're just getting started or working on a prototype.
45 |
46 | Remember, premature optimization is the root of all evil!
47 | :::
48 |
49 | #### Use cached images
50 |
51 | Where possible, serve images at stable URLs with appropriate cache headers as
52 | this can drastically reduce render time.
53 |
54 | #### Respond to requests as quickly as possible
55 |
56 | Don't perform long-running computations like interacting with an LLM while the
57 | user is waiting for the next Frame to load. See [perform long-running computations in the background](#long-running).
58 |
59 | #### Perform long-running computations in the background {#long-running}
60 |
61 | If your Frame needs to perform a long-running computation like interacting with
62 | an LLM or sending an onchain transaction, it should be done in the "background"
63 | by immediately respond with a frame that tells the user an action is being
64 | taken and let's the user refresh to check the status.
65 |
66 | #### Use a local copy of Farcaster data {#local-farcaster-data}
67 |
68 | If your frame needs to access Farcaster data, consider [using Shuttle to
69 | replicate it to Postgres](https://snapchain.farcaster.xyz/guides/syncing-to-db) so it can be fetched
70 | locally.
71 |
72 | ::: warning Advanced
73 | Maintaining a replicated database is a non-trivial amount of work. Consider
74 | fetching data from a provider like Neynar, Pinata, or Airstack unless you're
75 | willing to pay this cost.
76 | :::
77 |
78 | #### Skip Frame message signature verification when appropriate {#skip-verification}
79 |
80 | You may not need to verify the frame message if the data in the message does
81 | result in any sensitive data being updated or exposed.
82 |
83 | For example, if your frame returns public analytics data about a user's cast
84 | history, relying on the untrusted data is likely sufficient.
85 |
86 | ::: info Note
87 | For multi-step frames it might be the case that some interactions require
88 | verification while others don't.
89 | :::
90 |
91 | ::: warning Exercise caution
92 | If your frame relies on the message to allow the user to take a privileged
93 | action or expose sensitive data you must verify the message.
94 | :::
95 |
96 | #### Minimize latency from external dependencies like Snapchain
97 |
98 | This is a generalization of tactics like [skipping
99 | verification](#skip-verification) and [using a local copy of the Farcaster
100 | data](#local-farcaster-data).
101 |
102 | Find all the external dependencies for your frame server. For each of these
103 | external dependencies ask the following:
104 |
105 | - Can it be removed?
106 | - Can the data be cached?
107 | - Can it be co-located with my frame server?
108 |
--------------------------------------------------------------------------------
/docs/developers/frames/frog_frame_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/developers/frames/frog_frame_preview.png
--------------------------------------------------------------------------------
/docs/developers/frames/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting Started with Frames
3 | ---
4 |
5 | # Getting Started
6 |
7 | ::: info Not ready to build?
8 | If you'd prefer to learn more about Frames before building one, jump ahead to the [Frames Specification](./spec).
9 | :::
10 |
11 | Let's use Frog to go from 0 to 1 in less than a minute. At the end of this we'll have:
12 |
13 | - a type-safe frame server with a basic frame
14 | - a tool for interacting with and debugging our Frame locally
15 | - our server deployed on the public internet
16 |
17 | ### Bootstrap via CLI
18 |
19 | To get started, scaffold a new project:
20 |
21 | ::: code-group
22 |
23 | ```ts [npm]
24 | npm init frog -t vercel
25 | ```
26 |
27 | ```ts [yarn]
28 | yarn create frog -t vercel
29 | ```
30 |
31 | ```ts [bun]
32 | bunx create-frog -t vercel
33 | ```
34 |
35 | ```ts [pnpm]
36 | pnpm create frog -t vercel
37 | ```
38 |
39 | Complete the prompts and follow the instructions:
40 |
41 | ```
42 | bun install // install dependencies
43 | bun run dev // start dev server
44 | ```
45 |
46 | ::: info
47 | This guide uses Frog + Vercel but frames can be built and deployed in any
48 | number of ways. You can check out popular alternatives like [frame.js](https://framesjs.org/)
49 | on the [Frame Developer Resources](./resources) page.
50 | :::
51 |
52 | ### Open the preview
53 |
54 | Now that you have a frame server running, navigate to
55 | `http://localhost:5174/api/dev` to interact with your frame in the
56 | [Devtools](https://frog.fm/concepts/devtools) preview.
57 |
58 | You should see a frame that says "Welcome!" and has three buttons: apples,
59 | oranges, and bananas. Click on any of the buttons and the frame will update
60 | with a message echoing your choice.
61 |
62 | 
63 |
64 | ### Deploy the frame
65 |
66 | ::: info
67 | This project was scaffolded for deployment with Vercel since it's a popular and
68 | easy option. If you'd like to deploy your Frame another way check out the [Frog
69 | Platforms documentation](https://frog.fm/platforms/bun).
70 | :::
71 |
72 | To distribute your frame your server will need to be hosted somewhere on the
73 | internet. Feel free to skip this step and come back later.
74 |
75 | ::: code-group
76 |
77 | ```ts [npm]
78 | npm run deploy
79 | ```
80 |
81 | ```ts [yarn]
82 | yarn run deploy
83 | ```
84 |
85 | .
86 |
87 | ```ts [bun]
88 | bunx run deploy
89 | ```
90 |
91 | ```ts [pnpm]
92 | pnpm run deploy
93 | ```
94 |
95 | Complete the prompts. Once your frame is deployed you can test it end-to-end
96 | using the [Farcaster Client Frame Validator](https://farcaster.xyz/~/developers/frames-legacy).
97 |
98 | ::: info
99 | Make sure to plug the full frame URL in. For Vercel projects this default frame
100 | url is located at `https:///api`.
101 | :::
102 |
103 | ## Next steps
104 |
105 | Here are some next steps now that you have your first Frames project scaffolded
106 | and deployed:
107 |
108 | - Read through the [Frog Concepts
109 | documentation](https://frog.fm/concepts/overview) to learn how to build a
110 | sophisticated, [multi-step frame](https://frog.fm/concepts/routing).
111 | - Try [scaffolding a project with
112 | frames.js](https://framesjs.org/guides/create-frame) and check out their
113 | extensive [guides](https://framesjs.org/guides/create-frame) and
114 | [examples](https://framesjs.org/examples/basic).
115 | - Discover more resources for [building and learning about frames](./resources).
116 | - Read over our [best practices](./best-practices) for building a great Frame experience.
117 |
--------------------------------------------------------------------------------
/docs/developers/frames/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Frames Introduction
3 | ---
4 |
5 | # Frames Introduction
6 |
7 | ::: info Mini Apps are evolving!
8 |
9 |
10 | We recently released a new [Mini Apps standard](https://miniapps.farcaster.xyz/){target="_self"} to enable even better in-feed experiences. **Frames v1 have been deprecated and will be supported only until end of March 2025.** We strongly recommend using Mini Apps for all new projects.
11 | :::
12 |
13 | Frames are a way to build interactive apps that run directly in a Farcaster social feed.
14 |
15 | They can be used to create rich in-feed experiences for web applications:
16 |
17 | - NFTS shared from [Zora](https://zora.co/) and [Highlight](https://highlight.xyz/) can be minted in-feed
18 | - Newsletters shared from [Paragraph](https://paragraph.xyz/) can be read inline and subscribed to in-feed
19 | - Markets shared from [Polymarket](https://polymarket.com/) let users place bets in-feed
20 |
21 | Or standalone experiences like polls and games:
22 |
23 | - Spot and mint wild animals on a live-feed of a watering hole in the Namib Desert with [Safaricaster](https://warpcast.com/mattkim/0x3d165bb8)
24 | - Make an onchain payment to another user with [Paybot](https://app.paycaster.co)
25 | - RSVP to an [Eventcaster](https://warpcast.com/toadyhawk.eth/0xcb4aefe8) event
26 | - [Yoink](https://warpcast.com/horsefacts.eth/0x70019199) the flag in this simple yet viral social game
27 | - Generate a [Waifu NFT](https://warpcast.com/horsefacts.eth/0xbc7d33ca) based on your Farcaster profile
28 |
29 | ### Farcaster 101
30 |
31 | A 5 minute non-technical primer on Frames:
32 |
33 |
34 |
35 | ## Next Steps
36 |
37 | 1. [Build your first mini app](https://miniapps.farcaster.xyz/docs/getting-started){target="\_self"}
38 | 2. Read through the [formal Mini Apps Specification](https://miniapps.farcaster.xyz/docs/specification){target="\_self"}
39 | 3. Join the Farcaster developer community in the [/fc-devs](https://warpcast.com/~/channel/fc-devs) channel on Farcaster.
40 |
--------------------------------------------------------------------------------
/docs/developers/frames/resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Frame Resources
3 | ---
4 |
5 | # Frame Resources
6 |
7 | An opinionated collection of popular resources for building Frames.
8 |
9 | #### Learning
10 |
11 | - [/fc-devs](https://farcaster.xyz/~/channel/fc-devs) - Farcaster developer channel
12 | - [Frames Specification](./spec) - official Frames specification
13 | - [dTech Zero to Hero Getting Started Guides](https://dtech.vision/farcaster/frames/)
14 | - [Frames.js Guide](https://framesjs.org/guides/create-frame) - guides from Frames.js
15 | - [Frog Guides](https://frog.fm/getting-started) - guides from Frog
16 | - [Frame Interface Guidelines (FIG)](https://github.com/paradigmxyz/Fig) - guidance and best practices for building frames
17 | - [Pinata Tutorials](https://docs.pinata.cloud/farcaster/frames#frame-tutorials) - tutorials for building frames that leverage IPFS
18 | - [Frames.js Examples](https://framesjs.org/examples/basic) - a collection of 20+ examples that cover basic and advanced topics
19 |
20 | #### Frameworks
21 |
22 | - [frog](https://frog.fm) - minimal & lightweight framework Farcaster Frames
23 | - [FrogUI](https://frog.fm/ui) - type-safe layout and styling primitives
24 | - [frames.js](https://framesjs.org/) - build, debug, and render Frames
25 | - [onchainkit](https://github.com/coinbase/onchainkit) - A React toolkit to create frames
26 | - [simplest frame](https://github.com/depatchedmode/simplest-frame) - zero-cost, zero-framework Frame template
27 | - [framebuilder](https://framebuilder.xyz) - No-Code Farcaster Frames Builder
28 |
29 | #### Developer tools
30 |
31 | - [Farcaster Client Frame Validator](https://farcaster.xyz/~/developers/frames-legacy) - a debugger for testing frames in the Farcaster client
32 | - [Neynar](https://docs.neynar.com/docs/how-to-build-farcaster-frames-with-neynar) - infrastructure and tools for frame servers
33 | - [Neynar Frame Studio](https://neynar.com/nfs) - build no-code Frames
34 | - [Pinata](https://docs.pinata.cloud/farcaster/frames) - Frame analytics, hub APIs, and more
35 | - [Airstack Frames SDK](https://github.com/Airstack-xyz/airstack-frames-sdk) - integrate onchain data into Frames
36 | - [Vercel OG](https://vercel.com/docs/functions/og-image-generation) - use satori and resvg-js to generate PNG images from HTML and CSS
37 |
38 |
39 |
40 | A more extensive list of resources can be found at [awesome-frames](https://github.com/davidfurlong/awesome-frames).
41 |
--------------------------------------------------------------------------------
/docs/developers/frames/safari_frame.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/developers/frames/safari_frame.gif
--------------------------------------------------------------------------------
/docs/developers/guides/accounts/change-custody.md:
--------------------------------------------------------------------------------
1 | # Change custody address
2 |
3 | Accounts are owned by custody address which is an Ethereum address on OP Mainnet.
4 |
5 | A user may want to change this address for security reasons or to transfer ownership of the entire account.
6 |
7 | ### Requirements
8 |
9 | - An ETH wallet that owns the account on OP Mainnet, with some ETH.
10 | - An Ethereum provider URL for OP Mainnet (e.g. via [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/) or [QuickNode](https://www.quicknode.com/)).
11 |
12 | ### Change Custody Address
13 |
14 | Call the `transfer` function on the Id Registry contract. The receiving address must provide an EIP-712 signature accepting the transfer.
15 |
16 | ::: code-group
17 |
18 | ```ts [@farcaster/hub-web]
19 | import { ViemWalletEip712Signer } from '@farcaster/hub-web';
20 | import { walletClient, account } from './clients.ts';
21 | import { readNonce, getDeadline } from './helpers.ts';
22 |
23 | const nonce = await readNonce();
24 | const deadline = getDeadline();
25 |
26 | const eip712Signer = new ViemWalletEip712Signer(walletClient);
27 | const signature = await eip712signer.signTransfer({
28 | fid: 1n,
29 | to: account,
30 | nonce,
31 | deadline,
32 | });
33 |
34 | const { request: transferRequest } = await publicClient.simulateContract({
35 | ...IdContract,
36 | functionName: 'transfer',
37 | args: [account, deadline, signature], // to, deadline, signature
38 | });
39 |
40 | await walletClient.writeContract(transferRequest);
41 | ```
42 |
43 | ```ts [Viem]
44 | import {
45 | ID_REGISTRY_EIP_712_TYPES,
46 | idRegistryABI,
47 | ID_GATEWAY_ADDRESS,
48 | } from '@farcaster/hub-web';
49 | import { walletClient, account } from './clients.ts';
50 | import { readNonce, getDeadline } from './helpers.ts';
51 |
52 | const nonce = await readNonce();
53 | const deadline = getDeadline();
54 | const IdContract = {
55 | abi: idRegistryABI,
56 | address: ID_GATEWAY_ADDRESS,
57 | chain: optimism,
58 | };
59 |
60 | const signature = await walletClient.signTypedData({
61 | account,
62 | ...ID_REGISTRY_EIP_712_TYPES,
63 | primaryType: 'Transfer',
64 | message: {
65 | fid: 1n,
66 | to: account,
67 | nonce,
68 | deadline,
69 | },
70 | });
71 | ```
72 |
73 | ```ts [helpers.ts]
74 | import { ID_REGISTRY_ADDRESS, idRegistryABI } from '@farcaster/hub-web';
75 | import { publicClient, account } from './clients.ts';
76 |
77 | export const getDeadline = () => {
78 | const now = Math.floor(Date.now() / 1000);
79 | const oneHour = 60 * 60;
80 | return now + oneHour;
81 | };
82 |
83 | export const readNonce = async () => {
84 | return await publicClient.readContract({
85 | address: ID_REGISTRY_ADDRESS,
86 | abi: idRegistryABI,
87 | functionName: 'nonces',
88 | args: [account],
89 | });
90 | };
91 | ```
92 |
93 | <<< @/examples/contracts/clients.ts
94 |
95 | :::
96 |
97 | ::: warning
98 | Transferring a FID does not reset its recovery address. To transfer a FID and update its recovery address,
99 | call [`transferAndChangeRecovery`](/reference/contracts/reference/id-registry#transferandchangerecovery).
100 | :::
101 |
102 | See the [Id Registry](/reference/contracts/reference/id-registry#transfer) section for more
103 | details.
104 |
--------------------------------------------------------------------------------
/docs/developers/guides/accounts/change-fname.md:
--------------------------------------------------------------------------------
1 | # Change Farcaster name
2 |
3 | A user can change their offchain ENS name or Fname without affecting their account's history. This can be done at most once in 28 days.
4 |
5 | ::: warning
6 |
7 | - Fnames may be revoked if you violate the [usage policy](/learn/architecture/ens-names#offchain-ens-names-fnames).
8 | - Apps may lower your reputation if you change Fnames often.
9 | :::
10 |
11 | ### Requirements
12 |
13 | - An ETH wallet that owns the account on OP Mainnet. No ETH is required.
14 |
15 | ### Change username
16 |
17 | To transfer an Fname, e.g. `farcaster`, make a POST request to `/transfers` with the following body:
18 |
19 | ```yaml
20 | {
21 | "name": "farcaster", // Name to transfer
22 | "from": 123, // FID to transfer from
23 | "to": 321, // FID to transfer to
24 | "fid": 123, // FID making the request (must match from)
25 | "owner": "0x...", // Custody address of FID making the request
26 | "timestamp": 1641234567, // Current timestamp in seconds
27 | "signature": "0x..." // EIP-712 signature signed by the custody address of the FID
28 | }
29 | ```
30 |
31 | To generate the EIP-712 signature, use the following code:
32 |
33 | ```js
34 | import { makeUserNameProofClaim, EIP712Signer } from '@farcaster/hub-nodejs';
35 |
36 | const accountKey: EIP712Signer = undefined; // Account Key for the custody address (use appropriate subclass from hub-nodejs for ethers or viem)
37 |
38 | const claim = makeUserNameProofClaim({
39 | name: 'farcaster',
40 | owner: '0x...',
41 | timestamp: Math.floor(Date.now() / 1000),
42 | });
43 | const signature = (
44 | await accountKey.signUserNameProofClaim(claim)
45 | )._unsafeUnwrap();
46 | ```
47 |
48 | Example request via curl:
49 |
50 | ```bash
51 | curl -X POST https://fnames.farcaster.xyz/transfers \
52 | -H "Content-Type: application/json" \
53 | -d \
54 | '{"name": "farcaster", "owner": "0x...", "signature": "0x...", "from": 123, "to": 321, "timestamp": 1641234567, fid: 123}'
55 | ```
56 |
57 | See [here](/reference/fname/api.md) for more details on the Fname registry API.
58 |
--------------------------------------------------------------------------------
/docs/developers/guides/accounts/change-recovery.md:
--------------------------------------------------------------------------------
1 | # Change recovery address
2 |
3 | Accounts can configure a recovery address to protect against the loss of the custody address. The recovery address will change the custody address of the account.
4 |
5 | ### Requirements
6 |
7 | - An ETH wallet that has an FID on OP Mainnet, with some ETH for gas costs.
8 | - An ETH RPC URL for OP Mainnet (e.g. via [Alchemy](https://www.alchemy.com/), [Infura](https://www.infura.io/) or [QuickNode](https://www.quicknode.com/)).
9 |
10 | ### Change Address
11 |
12 | Call the `changeRecovery` function on the Id Registry contract.
13 |
14 | ::: code-group
15 |
16 | ```ts [@farcaster/hub-web]
17 | import { walletClient, account, IdContract } from './clients.ts';
18 |
19 | const newRecoveryAddress = '0x...';
20 |
21 | const { request: transferRequest } = await walletClient.simulateContract({
22 | ...IdContract,
23 | functionName: 'changeRecovery',
24 | args: [newRecoveryAddress], // New recovery address
25 | });
26 |
27 | await walletClient.writeContract(transferRequest);
28 | ```
29 |
30 | ```ts [clients.ts]
31 | import {
32 | ID_REGISTRY_EIP_712_TYPES,
33 | idRegistryABI,
34 | ID_GATEWAY_ADDRESS,
35 | } from '@farcaster/hub-web';
36 | import { walletClient, account } from './clients.ts';
37 |
38 | const IdContract = {
39 | abi: idRegistryABI,
40 | address: ID_GATEWAY_ADDRESS,
41 | chain: optimism,
42 | };
43 |
44 | import { createWalletClient, createPublicClient, custom, http } from 'viem';
45 | import { privateKeyToAccount } from 'viem/accounts';
46 | import { optimism } from 'viem/chains';
47 |
48 | export const publicClient = createPublicClient({
49 | chain: optimism,
50 | transport: http(),
51 | });
52 |
53 | export const walletClient = createWalletClient({
54 | chain: optimism,
55 | transport: custom(window.ethereum),
56 | });
57 |
58 | // JSON-RPC Account
59 | export const [account] = await walletClient.getAddresses();
60 |
61 | // Local Account
62 | export const account = privateKeyToAccount('0x...');
63 | ```
64 |
65 | :::
66 |
67 | See the [Id Registry](/reference/contracts/reference/id-registry#transfer) section for more
68 | details.
69 |
--------------------------------------------------------------------------------
/docs/developers/guides/accounts/find-by-name.md:
--------------------------------------------------------------------------------
1 | # Find account by username
2 |
3 | If you have a user's name and want to find their account, you'll need to use one of these methods depending on what type of username they have.
4 |
5 | ## Offchain ENS Names (Fnames)
6 |
7 | If the user has an offchain ENS name like `@alice`, you'll need to call the [Fname Registry](/reference/fname/api#get-current-fname-or-fid).
8 |
9 | ```bash
10 | curl https://fnames.farcaster.xyz/transfers/current?name=farcaster | jq
11 | {
12 | "transfers": [
13 | {
14 | "id": 1,
15 | "timestamp": 1628882891,
16 | "username": "farcaster",
17 | "owner": "0x8773442740c17c9d0f0b87022c722f9a136206ed",
18 | "from": 0,
19 | "to": 1,
20 | "user_signature": "0xa6fdd2a69deab5633636f32a30a54b21b27dff123e6481532746eadca18cd84048488a98ca4aaf90f4d29b7e181c4540b360ba0721b928e50ffcd495734ef8471b",
21 | "server_signature": "0xb7181760f14eda0028e0b647ff15f45235526ced3b4ae07fcce06141b73d32960d3253776e62f761363fb8137087192047763f4af838950a96f3885f3c2289c41b"
22 | }
23 | ]
24 | }
25 | ```
26 |
27 | This returns the most recent transfer associated with the name if it is registered. Note that the creation of an Fname is a transfer from the zero address to the custody address. The `to` field indicates the current FID that owns the name.
28 |
29 | ## Onchain ENS Names
30 |
31 | If the user has an onchain ENS name like `@alice.eth`, the easiest way to do it is with the Postgres [replicator](https://snapchain.farcaster.xyz/guides/syncing-to-db). It indexes onchain and offchain data and lets you easily find what you're looking for.
32 |
33 | Once you have it set up, query the `fnames` table in the replicator database for the account's FID:
34 |
35 | ```sql
36 | SELECT username, fid
37 | FROM fnames
38 | WHERE username = 'farcaster.eth'
39 | order by updated_at desc
40 | limit 1;
41 | ```
42 |
43 | See [here](/reference/replicator/schema#fnames) for more details on the replicator table schema.
44 |
--------------------------------------------------------------------------------
/docs/developers/guides/accounts/register-ens.md:
--------------------------------------------------------------------------------
1 | # Register ENS Name
2 |
3 | A user can set their farcaster username to an ENS name they own.
4 |
5 | ### Requirements
6 |
7 | - An ETH wallet that owns the account on OP Mainnet. No ETH is required.
8 | - A valid ENS name that resolves to the custody address of the Farcaster account, or a verified eth address in the
9 | Farcaster account.
10 |
11 | ### Register ENS Name
12 |
13 | First, ensure the ENS name resolves to the custody address of the farcaster account. Or the resolved address is a
14 | verified eth address in the Farcaster account. See [here](/developers/guides/writing/verify-address.md) for how to
15 | verify an ETH address.
16 |
17 | Then, generate an EIP-712 signature for the ENS name proof claim and submit the message. For more details on how to
18 | create messages, see [this guide](/developers/guides/writing/messages.md).
19 |
20 | ```js
21 | import {
22 | makeUserNameProofClaim,
23 | EIP712Signer,
24 | makeUsernameProof,
25 | FarcasterNetwork,
26 | makeUserDataAdd,
27 | UserNameType,
28 | UserDataType,
29 | } from '@farcaster/hub-nodejs';
30 |
31 | const accountKey: EIP712Signer = undefined; // Account Key for the custody/verified address (use appropriate subclass from hub-nodejs for ethers or viem)
32 | const accountEd25519Key = undefined; // Private key for the farcaster account signer
33 |
34 | const claim = makeUserNameProofClaim({
35 | name: 'farcaster.eth', // ENS name to register
36 | owner: '0x...', // Must be the public key of accountKey, and name must resolve to this address
37 | timestamp: Math.floor(Date.now() / 1000),
38 | });
39 | const signature = (
40 | await accountKey.signUserNameProofClaim(claim)
41 | )._unsafeUnwrap();
42 |
43 | const dataOptions = {
44 | fid: 123, // FID make the request
45 | network: FarcasterNetwork.MAINNET,
46 | };
47 | const signer = new NobleEd25519Signer(accountEd25519Key);
48 | const usernameProofMessage = makeUsernameProof(
49 | {
50 | name: claim.name,
51 | owner: claim.owner,
52 | timestamp: claim.timestamp,
53 | fid: dataOptions.fid,
54 | signature: signature,
55 | type: UserNameType.USERNAME_TYPE_ENS_L1,
56 | },
57 | dataOptions,
58 | signer
59 | );
60 |
61 | // Submit the message to the node. Note that this only registers the name proof to the account, it does not change the username yet.
62 | // await client.submitMessage(usernameProofMessage);
63 |
64 | // Once it's accepted, you can set the username to the ENS name
65 |
66 | const usernameMessage = makeUserData(
67 | {
68 | type: UserDataType.USERNAME,
69 | value: claim.name,
70 | },
71 | dataOptions,
72 | signer
73 | );
74 |
75 | // Submit the username message to the node
76 | // await client.submitMessage(usernameMessage);
77 | ```
78 |
--------------------------------------------------------------------------------
/docs/developers/guides/advanced/decode-key-metadata.md:
--------------------------------------------------------------------------------
1 | # Decode key metadata
2 |
3 | When users add a new key to the Key Registry, the contract emits [encoded metadata](/reference/contracts/reference/signed-key-request-validator#signedkeyrequestmetadata-struct) in an event. You can use this metadata to determine who requested the key.
4 |
5 | To decode key metadata, you can use Viem's `decodeAbiParameters` function:
6 |
7 | ::: code-group
8 |
9 | ```ts [Viem]
10 | import { decodeAbiParameters } from 'viem';
11 |
12 | const encodedMetadata =
13 | '0x' +
14 | '0000000000000000000000000000000000000000000000000000000000000020' +
15 | '00000000000000000000000000000000000000000000000000000000000023C0' +
16 | '00000000000000000000000002EF790DD7993A35FD847C053EDDAE940D055596' +
17 | '0000000000000000000000000000000000000000000000000000000000000080' +
18 | '00000000000000000000000000000000000000000000000000000000657C8AF5' +
19 | '0000000000000000000000000000000000000000000000000000000000000041' +
20 | 'F18569F4364BB2455DB27A4E8464A83AD8555416B1AAB21FF26E8501168F471F' +
21 | '7EC17BB096EA4438E5BF82CE01224B2F67EF9042737B7B101C41A1A05CB469DC' +
22 | '1B00000000000000000000000000000000000000000000000000000000000000';
23 |
24 | const decoded = decodeAbiParameters(
25 | [
26 | {
27 | components: [
28 | {
29 | name: 'requestFid',
30 | type: 'uint256',
31 | },
32 | {
33 | name: 'requestSigner',
34 | type: 'address',
35 | },
36 | {
37 | name: 'signature',
38 | type: 'bytes',
39 | },
40 | {
41 | name: 'deadline',
42 | type: 'uint256',
43 | },
44 | ],
45 | type: 'tuple',
46 | },
47 | ],
48 | encodedMetadata
49 | );
50 |
51 | console.log(decoded);
52 | /*
53 | [
54 | {
55 | requestFid: 9152n,
56 | requestSigner: '0x02ef790Dd7993A35fD847C053EDdAE940D055596',
57 | signature: '0xF185...69F4',
58 | deadline: 1702660853n
59 | }
60 | ]
61 | */
62 | ```
63 |
64 | :::
65 |
66 | See the [Signed Key Request Validator](/reference/contracts/reference/signed-key-request-validator#signedkeyrequestmetadata-struct) reference for more
67 | details.
68 |
--------------------------------------------------------------------------------
/docs/developers/guides/advanced/query-signups.md:
--------------------------------------------------------------------------------
1 | # Counting signups by day
2 |
3 | ::: info Pre-requisites
4 |
5 | - Read access to a replicator database
6 |
7 | :::
8 |
9 | To count the number of signups by day, we can use the `chain_events` table to query the number
10 | of [`ID_REGISTER`](https://snapchain.farcaster.xyz/reference/datatypes/events#onchaineventtype) events
11 | and group by day.
12 |
13 | ```sql
14 | SELECT DATE_TRUNC('day', created_at) AS day, COUNT(*) AS count
15 | FROM chain_events
16 | WHERE type = 3 -- ID_REGISTER (see event types reference page)
17 | GROUP BY day
18 | ORDER BY day desc;
19 | ```
20 |
21 | For more information on the schema, see the [replicator schema](/reference/replicator/schema).
22 |
--------------------------------------------------------------------------------
/docs/developers/guides/apps/feed.md:
--------------------------------------------------------------------------------
1 | # Generate a chronological feed for a user
2 |
3 | This example will showcase how to read data from the Farcaster network using the
4 | official [hub-nodejs](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/hub-nodejs) in typescript.
5 |
6 | We will create a simple feed of casts from a list of FIDs and display them in reverse chronological order.
7 |
8 | ## Installation
9 |
10 | Create an empty typescript project and install the hub-nodejs package
11 |
12 | ```bash
13 | yarn add @farcaster/hub-nodejs
14 | ```
15 |
16 | ## 1. Create a client
17 |
18 | First, let's set up some constants and create a client to connect to the hub.
19 |
20 | ```typescript
21 | import { getSSLHubRpcClient } from '@farcaster/hub-nodejs';
22 |
23 | /**
24 | * Populate the following constants with your own values
25 | */
26 |
27 | const HUB_URL = 'hoyt.farcaster.xyz:3383'; // URL of the Hub
28 | const FIDS = [2, 3]; // User IDs to fetch casts for
29 |
30 | // const client = getInsecureHubRpcClient(HUB_URL); // Use this if you're not using SSL
31 | const client = getSSLHubRpcClient(HUB_URL);
32 | ```
33 |
34 | ## 2. Cache the fnames for the FIDs
35 |
36 | Query the UserData for the provided FIDs, so we can show friendly usernames. Cache them for later.
37 |
38 | ```typescript
39 | // Create a mapping of fids to fnames, which we'll need later to display messages
40 | const fidToFname = new Map();
41 |
42 | const fnameResultPromises = FIDS.map((fid) =>
43 | client.getUserData({ fid, userDataType: UserDataType.USERNAME })
44 | );
45 | const fnameResults = await Promise.all(fnameResultPromises);
46 |
47 | fnameResults.map((result) =>
48 | result.map((uData) => {
49 | if (isUserDataAddMessage(uData)) {
50 | const fid = uData.data.fid;
51 | const fname = uData.data.userDataBody.value;
52 | fidToFname.set(fid, fname);
53 | }
54 | })
55 | );
56 | ```
57 |
58 | ## 3. Fetch top level casts
59 |
60 | Query the hub for all casts for each FID, sorted in reverse chronological order and then filter to only the top level
61 | casts.
62 |
63 | ```typescript
64 | /**
65 | * Returns a user's casts which are not replies to any other casts in reverse chronological order.
66 | */
67 | const getPrimaryCastsByFid = async (
68 | fid: number,
69 | client: HubRpcClient
70 | ): HubAsyncResult => {
71 | const result = await client.getCastsByFid({
72 | fid: fid,
73 | pageSize: 10,
74 | reverse: true,
75 | });
76 | if (result.isErr()) {
77 | return err(result.error);
78 | }
79 | // Coerce Messages into Casts, should not actually filter out any messages
80 | const casts = result.value.messages.filter(isCastAddMessage);
81 | return ok(casts.filter((message) => !message.data.castAddBody.parentCastId));
82 | };
83 |
84 | // Fetch primary casts for each fid
85 | const castResultPromises = FIDS.map((fid) => getPrimaryCastsByFid(fid, client));
86 | const castsResult = Result.combine(await Promise.all(castResultPromises));
87 |
88 | if (castsResult.isErr()) {
89 | console.error('Fetching casts failed');
90 | console.error(castsResult.error);
91 | return;
92 | }
93 | ```
94 |
95 | ## 4. Function to pretty print a cast
96 |
97 | The raw cast data is not very readable. We'll write a function to convert the timestamp to a human readable format, and
98 | also resolve any mentions (only stored as fids and their location within the cast) to their fnames.
99 |
100 | ```typescript
101 | const castToString = async (
102 | cast: CastAddMessage,
103 | nameMapping: Map,
104 | client: HubRpcClient
105 | ) => {
106 | const fname = nameMapping.get(cast.data.fid) ?? `${cast.data.fid}!`; // if the user doesn't have a username set, use their FID
107 |
108 | // Convert the timestamp to a human readable string
109 | const unixTime = fromFarcasterTime(cast.data.timestamp)._unsafeUnwrap();
110 | const dateString = timeAgo.format(new Date(unixTime));
111 |
112 | const { text, mentions, mentionsPositions } = cast.data.castAddBody;
113 | const bytes = new TextEncoder().encode(text);
114 |
115 | const decoder = new TextDecoder();
116 | let textWithMentions = '';
117 | let indexBytes = 0;
118 | for (let i = 0; i < mentions.length; i++) {
119 | textWithMentions += decoder.decode(
120 | bytes.slice(indexBytes, mentionsPositions[i])
121 | );
122 | const result = await getFnameFromFid(mentions[i], client);
123 | result.map((fname) => (textWithMentions += fname));
124 | indexBytes = mentionsPositions[i];
125 | }
126 | textWithMentions += decoder.decode(bytes.slice(indexBytes));
127 |
128 | // Remove newlines from the message text
129 | const textNoLineBreaks = textWithMentions.replace(/(\r\n|\n|\r)/gm, ' ');
130 |
131 | return `${fname}: ${textNoLineBreaks}\n${dateString}\n`;
132 | };
133 | ```
134 |
135 | ## 5. Sort and print the casts
136 |
137 | Finally, we can sort the casts by timestamp again (so they are interleaved correctly) and print them out.
138 |
139 | ```typescript
140 | /**
141 | * Compares two CastAddMessages by timestamp, in reverse chronological order.
142 | */
143 | const compareCasts = (a: CastAddMessage, b: CastAddMessage) => {
144 | if (a.data.timestamp < b.data.timestamp) {
145 | return 1;
146 | }
147 | if (a.data.timestamp > b.data.timestamp) {
148 | return -1;
149 | }
150 | return 0;
151 | };
152 |
153 | const sortedCasts = castsResult.value.flat().sort(compareCasts); // sort casts by timestamp
154 | const stringifiedCasts = await Promise.all(
155 | sortedCasts.map((c) => castToString(c, fidToFname, client))
156 | ); // convert casts to printable strings
157 |
158 | for (const outputCast of stringifiedCasts) {
159 | console.log(outputCast);
160 | }
161 | ```
162 |
163 | ## Full example
164 |
165 | See full example [here](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/hub-nodejs/examples/chron-feed)
166 |
--------------------------------------------------------------------------------
/docs/developers/guides/querying/fetch-casts.md:
--------------------------------------------------------------------------------
1 | # Get account messages
2 |
3 | ::: info Pre-requisites
4 |
5 | - Read only access to a Snapchain node
6 |
7 | :::
8 |
9 | See [Snapchain installation](https://snapchain.farcaster.xyz/getting-started#sync-a-node) for more information on how to set up a local Snapchain instance.
10 |
11 | To query all the casts for a particular FID, you can use the castsByFid HTTP endpoint:
12 |
13 | ```bash
14 | # Default http port is 3381
15 | $ curl http://localhost:3381/v1/castsByFid\?fid\=1 | jq ".messages[].data.castAddBody.text | select( . != null)"
16 | "testing"
17 | "test"
18 | "another test"
19 | "another testy test"
20 | ```
21 |
22 | This returns all the cast related messages for the fid. There are similar endpoints for reactions and follows. See
23 | the [http api reference](https://snapchain.farcaster.xyz/reference/httpapi/httpapi) for more details.
24 |
25 | If you have the [hub-monorepo](https://github.com/farcasterxyz/hub-monorepo) installed from source, you can use the built in `console`. This will use the grpc APIs
26 |
27 | ```bash
28 | # Ensure you are in the hubble sub directory
29 | $ cd apps/hubble
30 | # Remove `--insecure` if the host is using TLS
31 | $ yarn console --insecure -s localhost:3383
32 | > res = await rpcClient.getCastsByFid({fid: 1})
33 | Ok {
34 | value: {
35 | messages: [ [Object], [Object], [Object], [Object] ],
36 | nextPageToken:
37 | }
38 | }
39 | > res.value.messages.map( m => m.data.castAddBody.text)
40 | [ 'testing', 'test', 'another test', 'another testy test' ]
41 | ```
42 |
43 | For more details on the GRPC API, see the [grpc api reference](https://snapchain.farcaster.xyz/reference/grpcapi/grpcapi).
44 |
--------------------------------------------------------------------------------
/docs/developers/guides/querying/fetch-channel-casts.md:
--------------------------------------------------------------------------------
1 | # Fetch casts from a channel
2 |
3 | ::: info Pre-requisites
4 |
5 | - Read access to a Snapchain instance
6 |
7 | :::
8 |
9 | To fetch casts from a channel, Snapchain provides a `getCastsByParent` api call.
10 |
11 | For example, to query all casts to the `ethereum` channel:
12 |
13 | ```bash
14 | $ curl http://localhost:3381/v1/castsByParent\?fid\=1\&url\="https://ethereum.org" | jq " .messages | limit(10;.[]) | .data.castAddBody.text"
15 | "cue "
16 | "Commandeering this channel for the one true Ethereum, Ethereum classic."
17 | "Pretty amazing that even during a bear market, the 30 day average burn gives us deflationary ETH. \n\nSource: Ultrasound.Money"
18 | "So, Ethereum is frequently called the Base Layer or L1 when talking about scalability.\n\nBut how can you call the whole Ethereum + Ethereum L2s + L3s that commit to Ethereum L2s?\n\nWe’re building a unified multi-chain explorer for that, but we don’t know how to call it: https://ethereum.routescan.io"
19 | "This, we're already doing.\n\nBut we call it, the Full-Index Ecosystem Explorer."
20 | ". By subdomains do you mean more specific namespaces, e.g. Farcaster fnames being name.farcaster.eth?\n\nMy guess is if the root .eth namespace is available it will command higher status and value.\n\nhttps://x.com/0xfoobar/status/1687209523239604230"
21 | "what are the best examples of DAOs with independent core working groups/multisigs?"
22 | "Anyone here use Rabby?\n\nhttps://x.com/0xfoobar/status/1687474090150416385"
23 | "Who needs stablecoins when we have ETH"
24 | "782,672 active + pending validators! 🤯 \n\n(also... I haven't proposed a block for a few months)"
25 | ```
26 |
27 | Using the GRPC API:
28 |
29 | ```bash
30 | > res = await rpcClient.getCastsByParent({parentUrl: "https://ethereum.org"})
31 | > res.value.messages.slice(0, 10).map( m => m.data.castAddBody.text)
32 | [
33 | 'cue ',
34 | 'Commandeering this channel for the one true Ethereum, Ethereum classic.',
35 | 'Pretty amazing that even during a bear market, the 30 day average burn gives us deflationary ETH. \n' +
36 | '\n' +
37 | 'Source: Ultrasound.Money',
38 | 'So, Ethereum is frequently called the Base Layer or L1 when talking about scalability.\n' +
39 | '\n' +
40 | 'But how can you call the whole Ethereum + Ethereum L2s + L3s that commit to Ethereum L2s?\n' +
41 | '\n' +
42 | 'We’re building a unified multi-chain explorer for that, but we don’t know how to call it: https://ethereum.routescan.io',
43 | "This, we're already doing.\n" +
44 | '\n' +
45 | 'But we call it, the Full-Index Ecosystem Explorer.',
46 | '. By subdomains do you mean more specific namespaces, e.g. Farcaster fnames being name.farcaster.eth?\n' +
47 | '\n' +
48 | 'My guess is if the root .eth namespace is available it will command higher status and value.\n' +
49 | '\n' +
50 | 'https://x.com/0xfoobar/status/1687209523239604230',
51 | 'what are the best examples of DAOs with independent core working groups/multisigs?',
52 | 'Anyone here use Rabby?\n' +
53 | '\n' +
54 | 'https://x.com/0xfoobar/status/1687474090150416385',
55 | 'Who needs stablecoins when we have ETH',
56 | '782,672 active + pending validators! 🤯 \n' +
57 | '\n' +
58 | "(also... I haven't proposed a block for a few months)"
59 | ]
60 | ```
61 |
--------------------------------------------------------------------------------
/docs/developers/guides/querying/fetch-profile.md:
--------------------------------------------------------------------------------
1 | # Get account profile
2 |
3 | ::: info Pre-requisites
4 |
5 | - Read only access to a Snapchain instance
6 |
7 | :::
8 |
9 | To fetch profile details, use the
10 |
11 | ```bash
12 | $ curl http://localhost:3381/v1/userDataByFid\?fid\=1 | jq ".messages[].data.userDataBody"
13 | {
14 | "type": "USER_DATA_TYPE_PFP",
15 | "value": "https://i.imgur.com/I2rEbPF.png"
16 | }
17 | {
18 | "type": "USER_DATA_TYPE_BIO",
19 | "value": "A sufficiently decentralized social network. farcaster.xyz"
20 | }
21 | {
22 | "type": "USER_DATA_TYPE_DISPLAY",
23 | "value": "Farcaster"
24 | }
25 | {
26 | "type": "USER_DATA_TYPE_USERNAME",
27 | "value": "farcaster"
28 | }
29 | ```
30 |
31 | See the [http api reference](https://snapchain.farcaster.xyz/reference/httpapi/userdata) for more details.
32 |
33 | If you have the [hub-monorepo](https://github.com/farcasterxyz/hub-monorepo) installed from source, you can use the built in `console`. This will use the grpc APIs
34 |
35 | ```bash
36 | # Ensure you are in the hubble sub directory
37 | $ cd apps/hubble
38 | # Remove `--insecure` if the host is using TLS
39 | $ yarn console --insecure -s localhost:3383
40 | > res = await rpcClient.getUserDataByFid({fid: 1})
41 | Ok {
42 | value: {
43 | messages: [ [Object], [Object], [Object], [Object] ],
44 | nextPageToken:
45 | }
46 | }
47 | > res.value.messages.map(m => m.data.userDataBody)
48 | [
49 | { type: 1, value: 'https://i.imgur.com/I2rEbPF.png' },
50 | {
51 | type: 3,
52 | value: 'A sufficiently decentralized social network. farcaster.xyz'
53 | },
54 | { type: 2, value: 'Farcaster' },
55 | { type: 6, value: 'farcaster' }
56 | ]
57 | ```
58 |
59 | For more details on the GRPC API, see the [grpc api reference](https://snapchain.farcaster.xyz/reference/grpcapi/grpcapi).
60 |
--------------------------------------------------------------------------------
/docs/developers/guides/writing/casts.md:
--------------------------------------------------------------------------------
1 | # Create casts
2 |
3 | Creating simple casts is covered in the [messages](./messages.md) tutorial. This tutorial covers advanced topics like mentions, embeds, emojis, replies and channels.
4 |
5 | ## Setup
6 |
7 | - See the setup instructions in [creating messages](./messages.md)
8 |
9 | ## Mentions
10 |
11 | Users can be tagged in a cast with an @username mention (e.g. "Hello @bob!") which causes clients to send notifications.
12 |
13 | A mention is not included in the text of the cast. The target fid and the position of the mention in the text are specified in the `mentions` and `mentionPositions` array, and are populated into the cast by clients at render-time.
14 |
15 | ```typescript
16 | /**
17 | * "@dwr and @v are big fans of @farcaster"
18 | */
19 | const castWithMentions = await makeCastAdd(
20 | {
21 | text: ' and are big fans of ',
22 | embeds: [],
23 | embedsDeprecated: [],
24 | mentions: [3, 2, 1],
25 | mentionsPositions: [0, 5, 22], // The position in bytes (not characters)
26 | },
27 | dataOptions,
28 | ed25519Signer
29 | );
30 | ```
31 |
32 | ## Embeds
33 |
34 | URLs can be embedded in the cast which instructs clients to render a preview.
35 |
36 | A cast can have up to 2 embeds which can each be up to 256 bytes long. No other validation is performed on embeds.
37 |
38 | ```typescript
39 | /**
40 | * A cast with a mention and an attachment
41 | *
42 | * "Hey @dwr, check this out!"
43 | */
44 | const castWithMentionsAndAttachment = await makeCastAdd(
45 | {
46 | text: 'Hey, check this out!',
47 | embeds: [{ url: 'https://farcaster.xyz' }],
48 | embedsDeprecated: [],
49 | mentions: [3],
50 | mentionsPositions: [4],
51 | },
52 | dataOptions,
53 | ed25519Signer
54 | );
55 | ```
56 |
57 | ## Emoji
58 |
59 | Emojis can be included directly in the text of a cast and be rendered by clients.
60 |
61 | Since an emoji character often takes up multiple bytes but renders as a single character, it has an impact on how mention positions and cast length should be calculated.
62 |
63 | ```typescript
64 | /**
65 | * A cast with emojis and mentions
66 | *
67 | * "🤓@farcaster can mention immediately after emoji"
68 | */
69 | const castWithEmojiAndMentions = await makeCastAdd(
70 | {
71 | text: '🤓 can mention immediately after emoji',
72 | embeds: [],
73 | embedsDeprecated: [],
74 | mentions: [1],
75 | mentionsPositions: [4],
76 | },
77 | dataOptions,
78 | ed25519Signer
79 | );
80 | ```
81 |
82 | ## Reply
83 |
84 | A cast can be a reply to another cast, URL or NFT. A reply to another cast is treated as a thread, while a reply to a URL or NFT can be treated as a comment or a [channel](#channels).
85 |
86 | The optional parentUrl property can be set to a URL or to an fid-hash value of the cast being replied to, as shown in th example below. See [FIP-2](https://github.com/farcasterxyz/protocol/discussions/71) for more details on reply types.
87 |
88 | ```typescript
89 | /**
90 | * A cast that replies to a URL
91 | *
92 | * "I think this is a great protocol 🚀"
93 | */
94 | const castReplyingToAUrl = await makeCastAdd(
95 | {
96 | text: 'I think this is a great protocol 🚀',
97 | embeds: [],
98 | embedsDeprecated: [],
99 | mentions: [],
100 | mentionsPositions: [],
101 | parentUrl: 'https://www.farcaster.xyz/',
102 | },
103 | dataOptions,
104 | ed25519Signer
105 | );
106 | ```
107 |
108 | ## Channels
109 |
110 | A cast can be sent into a channel, which instructs clients that it is related to a specific topic. Clients may choose to use this metadata in different ways, like grouping channel casts together or recommending them to certain users.
111 |
112 | A channel is simply a `parentURL` that is either a URL or NFT, which all clients recognize as a channel by loose consensus. There is no protocol level agreement on the list of channels yet, but the `casts` table in the replicator database can be used to get a list of commonly used channels.
113 |
114 | ```sql
115 | /* Query for a list of channels */
116 | select parent_url,
117 | count(*) as count
118 | from casts
119 | where parent_url is not null
120 | group by parent_url
121 | order by count desc;
122 | ```
123 |
124 | ```typescript
125 | // Cast into the Farcaster channel
126 | const channelCast = await makeCastAdd(
127 | {
128 | text: 'I love farcaster',
129 | embeds: [],
130 | embedsDeprecated: [],
131 | mentions: [],
132 | mentionsPositions: [],
133 | parentUrl: 'https://www.farcaster.xyz/', // This is illustrative, and is not an actual channel URL
134 | },
135 | dataOptions,
136 | ed25519Signer
137 | );
138 | ```
139 |
--------------------------------------------------------------------------------
/docs/developers/guides/writing/messages.md:
--------------------------------------------------------------------------------
1 | # Create messages
2 |
3 | A message represents an action taken by a user (e.g. alice says "hello world")
4 |
5 | There are many types of messages, and this tutorial will walk you through the most common ones. Other tutorials will cover the more advanced message types.
6 |
7 | ## Setup
8 |
9 | You will need:
10 |
11 | - Write access to a Snapchain node
12 | - Private key of a signer registered to an fid
13 | - `hub-nodejs` and helper functions imported and shown below
14 |
15 | ```ts
16 | import {
17 | makeCastAdd,
18 | makeCastRemove,
19 | makeLinkAdd,
20 | makeLinkRemove,
21 | makeReactionAdd,
22 | makeReactionRemove,
23 | makeUserDataAdd,
24 | NobleEd25519Signer,
25 | FarcasterNetwork,
26 | } from '@farcaster/hub-nodejs';
27 |
28 | const ACCOUNT_PRIVATE_KEY: Hex = '0x...'; // Your account key's private key
29 | const FID = -1; // Your fid
30 | const ed25519Signer = new NobleEd25519Signer(ACCOUNT_PRIVATE_KEY);
31 | const dataOptions = {
32 | fid: FID,
33 | network: FC_NETWORK,
34 | };
35 | const FC_NETWORK = FarcasterNetwork.MAINNET;
36 | ```
37 |
38 | ## Casts
39 |
40 | Casts are public messages created by a user.
41 |
42 | A cast is created by issuing a CastAdd message with the text of the cast and optional embeds, mentions, and emoji. The example below shows the creation of a simple cast.
43 |
44 | ```typescript
45 | const cast = await makeCastAdd(
46 | {
47 | text: 'This is a cast!', // Text can be up to 320 bytes long
48 | embeds: [],
49 | embedsDeprecated: [],
50 | mentions: [],
51 | mentionsPositions: [],
52 | },
53 | dataOptions,
54 | ed25519Signer
55 | );
56 | ```
57 |
58 | A cast can be removed by issuing a CastRemove message with the hash of the CastAdd message and a later timestamp.
59 |
60 | ```typescript
61 | const castRemove = await makeCastRemove(
62 | {
63 | targetHash: castReplyingToAUrl._unsafeUnwrap().hash,
64 | },
65 | dataOptions,
66 | ed25519Signer
67 | );
68 | ```
69 |
70 | To create casts with embeds, mentions, channels emoji, see the [casts](../writing/casts.md) tutorial.
71 |
72 | ## Reactions
73 |
74 | Reactions are strongly typed relationships between a user and a cast (e.g. a like).
75 |
76 | A user "likes" a cast by producing a ReactionAdd message with type set to `like` and the target set to the hash of the cast and the fid of its author.
77 |
78 | ```typescript
79 | const reactionAdd = await makeReactionAdd(
80 | {
81 | type: ReactionType.LIKE,
82 | targetCastId: { fid: createdCast.data.fid, hash: createdCast.hash },
83 | },
84 | dataOptions,
85 | ed25519Signer
86 | );
87 | ```
88 |
89 | The like can be negated by broadcasting a ReactionRemove message with the information and a later timestamp.
90 |
91 | ```typescript
92 | const reactionRemove = await makeReactionRemove(
93 | {
94 | type: ReactionType.LIKE,
95 | targetCastId: { fid: createdCast.data.fid, hash: createdCast.hash },
96 | },
97 | dataOptions, // Timestamp provided must be higher
98 | ed25519Signer
99 | );
100 | ```
101 |
102 | A user can "recast" with a very similar process.
103 |
104 | ```typescript
105 | const recastAdd = await makeReactionAdd(
106 | {
107 | type: ReactionType.RECAST,
108 | targetCastId: { fid: createdCast.data.fid, hash: createdCast.hash },
109 | },
110 | dataOptions,
111 | ed25519Signer
112 | );
113 |
114 | const recastRemove = await makeReactionRemove(
115 | {
116 | type: ReactionType.RECAST,
117 | targetCastId: { fid: createdCast.data.fid, hash: createdCast.hash },
118 | },
119 | dataOptions,
120 | ed25519Signer
121 | );
122 | ```
123 |
124 | ## User Data
125 |
126 | UserData is a strongly typed set of messages that represent metadata about a user (e.g. bio, profile picture).
127 |
128 | A `UserData` message has a type and a string value which can be set. The example below shows a user updating their bio.
129 |
130 | ```typescript
131 | // Update user bio. Other fields are similar, just change the type. Value is always a string.
132 | const bioUpdate = await makeUserDataAdd(
133 | {
134 | type: UserDataType.BIO,
135 | value: 'new bio',
136 | },
137 | dataOptions,
138 | ed25519Signer
139 | );
140 | ```
141 |
142 | ## Links
143 |
144 | Links are loosely typed relationships between users (e.g. alice follows bob).
145 |
146 | A user creates a Link by issuing a LinkAdd message with a string type and the target user's fid. The most commonly supported link on all clients is 'follow'.
147 |
148 | ```typescript
149 | const follow = await makeLinkAdd(
150 | {
151 | type: 'follow',
152 | targetFid: 1,
153 | },
154 | dataOptions,
155 | ed25519Signer
156 | );
157 |
158 | const unfollow = await makeLinkRemove(
159 | {
160 | type: 'unfollow',
161 | targetFid: 1,
162 | },
163 | dataOptions,
164 | ed25519Signer
165 | );
166 | ```
167 |
--------------------------------------------------------------------------------
/docs/developers/guides/writing/submit-messages.md:
--------------------------------------------------------------------------------
1 | # Submit data to the hub
2 |
3 | ::: info Pre-requisites
4 |
5 | - Write access to a Snapchain node
6 | - Private key of an account key registered to an fid
7 | - Local typescript development environment
8 |
9 | :::
10 |
11 | To see a full example of how to submit different kinds of messages to the hub,
12 | see [here](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/hub-nodejs/examples/write-data)
13 |
--------------------------------------------------------------------------------
/docs/developers/guides/writing/verify-address.md:
--------------------------------------------------------------------------------
1 | # Create an address verification
2 |
3 | ::: info Pre-requisites
4 |
5 | - Write access to a Snapchain instance
6 | - Private key of an account key registered to an fid
7 | - An Ethereum provider URL for OP Mainnet (e.g. via [Alchemy](https://www.alchemy.com/),[Infura](https://www.infura.io/) or [QuickNode](https://www.quicknode.com/)).
8 |
9 | :::
10 |
11 | To create a [Verification](https://snapchain.farcaster.xyz/reference/datatypes/messages#6-verification) proving ownership of an external Ethereum address, you can use an `Eip712Signer` to sign a verification message, and the `makeVerificationAddEthAddress` function to construct a message to send to a Hub.
12 |
13 | First, set up clients and account keys:
14 |
15 | ```ts
16 | import {
17 | NobleEd25519Signer,
18 | ViemLocalEip712Signer,
19 | FarcasterNetwork,
20 | makeVerificationAddEthAddress,
21 | } from '@farcaster/hub-nodejs';
22 | import { createPublicClient, http } from 'viem';
23 | import { privateKeyToAccount } from 'viem/accounts';
24 | import { optimism } from 'viem/chains';
25 |
26 | const publicClient = createPublicClient({
27 | chain: optimism,
28 | transport: http(),
29 | });
30 |
31 | const alice = privateKeyToAccount('0xab..12');
32 | const eip712Signer = new ViemLocalEip712Signer(alice);
33 |
34 | const ed25519Signer = new NobleEd25519Signer('0xcd..34');
35 | ```
36 |
37 | Then create a verification signature using an `Eip712Signer`. You'll need to query the latest blockhash on OP mainnet and include it in the signed message.
38 |
39 | ```ts
40 | const latestBlock = await publicClient.getBlock();
41 |
42 | const fid = 1n;
43 | const network = FarcasterNetwork.MAINNET;
44 | const address = alice.address;
45 | const blockHash = latestBlock.blockhash;
46 |
47 | const ethSignature = eip712Signer.signVerificationEthAddressClaim({
48 | fid,
49 | address,
50 | network,
51 | blockHash,
52 | });
53 | ```
54 |
55 | Finally, use `makeVerificationAddEthAddress` to construct a [`Verification`](https://snapchain.farcaster.xyz/reference/datatypes/messages#6-verification) message you can send to a Hub.
56 |
57 | ```ts
58 | if (ethSignature.isOk()) {
59 | const message = await makeVerificationAddEthAddress(
60 | {
61 | address,
62 | blockHash,
63 | ethSignature,
64 | },
65 | { fid, network },
66 | ed25519Signer
67 | );
68 | }
69 | ```
70 |
71 | ### Full code example
72 |
73 | ::: code-group
74 |
75 | ```ts [@farcaster/hub-nodejs]
76 | import {
77 | NobleEd25519Signer,
78 | ViemLocalEip712Signer,
79 | FarcasterNetwork,
80 | makeVerificationAddEthAddress,
81 | } from '@farcaster/hub-nodejs';
82 | import { createPublicClient, http } from 'viem';
83 | import { privateKeyToAccount } from 'viem/accounts';
84 | import { optimism } from 'viem/chains';
85 |
86 | const publicClient = createPublicClient({
87 | chain: optimism,
88 | transport: http(),
89 | });
90 |
91 | const alice = privateKeyToAccount('0xab..12');
92 | const eip712Signer = new ViemLocalEip712Signer(alice);
93 |
94 | const ed25519Signer = new NobleEd25519Signer('0xcd..34');
95 |
96 | const latestBlock = await publicClient.getBlock();
97 |
98 | const fid = 1n;
99 | const network = FarcasterNetwork.MAINNET;
100 | const address = alice.address;
101 | const blockHash = latestBlock.blockhash;
102 |
103 | const ethSignature = eip712Signer.signVerificationEthAddressClaim({
104 | fid,
105 | address,
106 | network,
107 | blockHash,
108 | });
109 |
110 | if (ethSignature.isOk()) {
111 | const message = await makeVerificationAddEthAddress(
112 | {
113 | address,
114 | blockHash,
115 | ethSignature,
116 | },
117 | { fid, network },
118 | ed25519Signer
119 | );
120 | }
121 | ```
122 |
123 | :::
124 |
--------------------------------------------------------------------------------
/docs/developers/index.md:
--------------------------------------------------------------------------------
1 | :::tip Join the conversation
2 | Ask questions and hang out with other Farcaster developers in the [/fc-devs](https://warpcast.com/~/channel/fc-devs) channel on Farcaster.
3 | :::
4 |
5 | ## Create mini apps
6 |
7 | Learn how to build mini apps (previously called Frames) that run inside a Farcaster feed.
8 |
9 |
10 | - [Introduction](https://miniapps.farcaster.xyz/){target="_self"}- understand what a mini app is and how it works
11 |
12 | - [Getting Started](https://miniapps.farcaster.xyz/docs/getting-started){target="_self"}- Build your first mini app
13 |
14 | ## Sign in with Farcaster
15 |
16 | Make it easy for users to sign in to your app with their Farcaster account.
17 |
18 | - [Examples](/auth-kit/examples.md) - see Sign in with Farcaster (SIWF) in action
19 | - [AuthKit](/auth-kit/installation.md) - a React toolkit to integrate SIWF
20 | - [FIP-11](https://github.com/farcasterxyz/protocol/discussions/110) - the formal standard for SIWF
21 |
22 | ## Analyze Farcaster data
23 |
24 | Sync the Farcaster network to a local machine so you can run queries on the data.
25 |
26 | - [Run a Snapchain node](https://snapchain.farcaster.xyz/getting-started#getting-started) - get realtime access to Farcaster data
27 | - [Write your first Snapchain query](https://snapchain.farcaster.xyz/getting-started#query-a-node) - get an account's casts from a Snapchain node
28 | - [Set up the replicator](https://snapchain.farcaster.xyz/guides/syncing-to-db) - sync a Snapchain node to a postgres database to run advanced queries
29 |
30 | ## Write to Farcaster
31 |
32 | - [Hello World](/developers/guides/basics/hello-world) - programmatically create an account and publish a cast
33 |
--------------------------------------------------------------------------------
/docs/developers/resources.md:
--------------------------------------------------------------------------------
1 | # Resources
2 |
3 | An opinionated list of the best libraries and tools for Farcaster developers. A more comprehensive list of resources can be found in a16z's [awesome-farcaster](https://github.com/a16z/awesome-farcaster) repo.
4 |
5 | Resources may be added via pull request. They must be purpose built for Farcaster only, actively maintained and adhere to the ethos and specification of the protocol.
6 |
7 | :::warning
8 | Resources are often from third parties and are not reviewed. Use them at your own risk.
9 | :::
10 |
11 | ## Libraries
12 |
13 | ### Mini Apps
14 |
15 |
16 | - [@farcaster/mini-app](https://miniapps.farcaster.xyz/docs/getting-started){target="_self"}- CLI tool for building mini apps.
17 | - [@neynar/create-farcaster-mini-app](https://www.npmjs.com/package/@neynar/create-farcaster-mini-app) - A Mini App quickstart npx script from Neynar.
18 |
19 | ### Legacy Frames
20 |
21 | - [@frame-js/frames](https://framesjs.org/) - next.js template for building and debugging frames.
22 | - [@coinbase/onchainkit](https://github.com/coinbase/onchainkit) - react toolkit to create frames.
23 | - [@frog](https://frog.fm) - framework for frames.
24 |
25 | ### Apps
26 |
27 | - [farcaster kit](https://www.farcasterkit.com/) - react hooks for building Farcaster apps.
28 |
29 | ### Snapchain
30 |
31 | - [@farcaster/hub-nodejs](https://www.npmjs.com/package/@farcaster/hub-nodejs) - lightweight, fast Typescript interface for Farcaster clients.
32 |
33 | ### Onchain
34 |
35 | - [farcaster-solidity](https://github.com/pavlovdog/farcaster-solidity/) - libraries for verifying and parsing Farcaster messages onchain
36 |
37 | ## Dashboards
38 |
39 | - [Farcaster Hub Map](https://farcaster.spindl.xyz/) - geographical map of Farcaster hubs
40 | - [Dune: Farcaster](https://dune.com/pixelhack/farcaster) - @pixelhack's dashboard for network stats
41 | - [Dune: Farcaster User Onchain Activities](https://dune.com/yesyes/farcaster-users-onchain-activities) - dashboard of farcaster user's onchain activity
42 |
43 | ## Learning
44 |
45 | - [dTech Farcaster Tutorials](https://dtech.vision/farcaster)
46 |
47 | ## Open Source Examples
48 |
49 | - [quikcast](https://github.com/farcasterxyz/quikcast) - an end-to-end connected app implementation for Farcaster
50 | - [fc-polls](https://github.com/farcasterxyz/fc-polls) - a simple polling app built using frames
51 |
52 | ## Services
53 |
54 | - [Neynar](https://neynar.com/) - infrastructure and services for building farcaster apps.
55 | - [dTech](https://dtech.vision) - Farcaster Development and Consulting Agency
56 |
--------------------------------------------------------------------------------
/docs/developers/siwf/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sign In with Farcaster
3 | ---
4 |
5 | # Introduction
6 |
7 | Sign In with Farcaster (SIWF) is a way for users to sign into any app using their
8 | Farcaster identity.
9 |
10 | When a user signs into your application with Farcaster you'll be able to use
11 | public social data like their social graph and profile information to provide
12 | a streamlined onboarding experience and social-powered features.
13 |
14 | ### How does it work?
15 |
16 | 1. Show a "Sign in with Farcaster" button to the user.
17 | 2. Wait for the user to click, scan a QR code and approve the request in Warpcast.
18 | 3. Receive and verify a signature from Warpcast.
19 | 4. Show the logged in user's profile picture and username.
20 |
21 | 
22 |
23 | ## Next Steps
24 |
25 | - Integrate SIWF to your app today with [AuthKit](/auth-kit/).
26 | - Read about the underlying standard in [FIP-11: Sign In With
27 | Farcaster](https://github.com/farcasterxyz/protocol/discussions/110).
28 |
--------------------------------------------------------------------------------
/docs/developers/siwf/siwf_demo.avifs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/developers/siwf/siwf_demo.avifs
--------------------------------------------------------------------------------
/docs/developers/utilities.md:
--------------------------------------------------------------------------------
1 | # Links
2 |
3 | - https://github.com/a16z/awesome-farcaster
4 |
--------------------------------------------------------------------------------
/docs/examples/contracts/clients.ts:
--------------------------------------------------------------------------------
1 | import { createWalletClient, createPublicClient, custom, http } from 'viem';
2 | import { privateKeyToAccount } from 'viem/accounts';
3 | import { optimism } from 'viem/chains';
4 |
5 | export const publicClient = createPublicClient({
6 | chain: optimism,
7 | transport: http(),
8 | });
9 |
10 | export const walletClient = createWalletClient({
11 | chain: optimism,
12 | transport: custom(window.ethereum),
13 | });
14 |
15 | // JSON-RPC Account
16 | export const [account] = await walletClient.getAddresses();
17 |
18 | // Local Account
19 | export const account = privateKeyToAccount('0x...');
20 |
--------------------------------------------------------------------------------
/docs/examples/contracts/metadata.ts:
--------------------------------------------------------------------------------
1 | import { ViemLocalEip712Signer } from '@farcaster/hub-web';
2 | import { privateKeyToAccount } from 'viem/accounts';
3 | import { getDeadline } from './helpers.ts';
4 | import { getPublicKey } from './signer.ts';
5 |
6 | // App account
7 | export const appAccount = privateKeyToAccount('0x...');
8 |
9 | const deadline = getDeadline();
10 | const publicKey = await getPublicKey();
11 |
12 | export const getMetadata = async () => {
13 | const eip712signer = new ViemLocalEip712Signer(appAccount);
14 | const metadata = await eip712signer.getSignedKeyRequestMetadata({
15 | requestFid: 9152n, // App fid
16 | key: publicKey,
17 | deadline,
18 | });
19 | if (metadata.isOk()) {
20 | return metadata.value;
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/docs/examples/contracts/signer.ts:
--------------------------------------------------------------------------------
1 | import * as ed from '@noble/ed25519';
2 | import { NobleEd25519Signer } from '@farcaster/hub-web';
3 |
4 | const privateKeyBytes = ed.utils.randomPrivateKey();
5 | export const accountKey = new NobleEd25519Signer(privateKeyBytes);
6 |
7 | export const getPublicKey = async () => {
8 | const accountKeyResult = await accountKey.getSignerKey();
9 | if (accountKeyResult.isOk()) {
10 | return accountKeyResult.value;
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: home
3 |
4 | hero:
5 | name: Farcaster Docs
6 | tagline: Permissionlessly build and distribute social apps
7 | actions:
8 | - theme: brand
9 | text: Build a mini app
10 | link: https://miniapps.farcaster.xyz/docs/getting-started
11 | target: _self
12 | - theme: alt
13 | text: Explore Sign In with Farcaster
14 | link: /developers/siwf/
15 | - theme: alt
16 | text: Learn about the protocol
17 | link: /learn/
18 | ---
19 |
20 | ### Build a Mini App
21 |
22 | Learn how to build Mini Apps (previously known as Frames v2) that run inside a Farcaster feed.
23 |
24 |
25 | - [Introduction to Mini Apps](https://miniapps.farcaster.xyz/){target="_self"}- Understand what a mini app is and how it works.
26 |
27 | - [Build your first Mini App](https://miniapps.farcaster.xyz/docs/getting-started){target="_self"}- Make mini apps that run inside Farcaster.
28 |
29 | ### Explore Sign In with Farcaster
30 |
31 | Allow users to Sign In with Farcaster and leverage social data in your app.
32 |
33 | - [Introduction](/developers/siwf/) - Learn about Sign In with Farcaster.
34 | - [Add SIWF using AuthKit](/auth-kit/installation) - a React toolkit to add SIWF to your app.
35 | - [Examples](/auth-kit/examples) - see Sign In with Farcaster in action.
36 |
37 | ### Analyze Farcaster data
38 |
39 | Sync the Farcaster network to a local machine so you can run queries on the data.
40 |
41 | - [Write your first snapchain query](https://snapchain.farcaster.xyz/getting-started#query-a-node) - get an account's casts from a snapchain node.
42 | - [Set up the replicator](https://snapchain.farcaster.xyz/guides/syncing-to-db) - sync a snapchain node to a postgres database to run advanced queries.
43 | - [Run a snapchain node](https://snapchain.farcaster.xyz/guides/running-a-node) - get realtime access to Farcaster data.
44 |
--------------------------------------------------------------------------------
/docs/learn/architecture/contracts.md:
--------------------------------------------------------------------------------
1 | # Contracts
2 |
3 | A Farcaster account is managed and secured onchain using the Farcaster contracts. This section provides a high level overview and avoids some implementation details. For the full picture, see the [contracts repository](https://github.com/farcasterxyz/contracts/).
4 |
5 |
6 |
7 | There are three main contracts deployed on OP Mainnet:
8 |
9 | - **Id Registry** - creates new accounts
10 | - **Storage Registry** - rents storage to accounts
11 | - **Key Registry** - adds and removes app keys from accounts
12 |
13 |
14 |
15 | 
16 |
17 | The contracts are deployed at the following addresses:
18 |
19 | | Contract | Address |
20 | | --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
21 | | IdRegistry | [0x00000000fc6c5f01fc30151999387bb99a9f489b](https://optimistic.etherscan.io/address/0x00000000fc6c5f01fc30151999387bb99a9f489b) |
22 | | StorageRegistry | [0x00000000fcce7f938e7ae6d3c335bd6a1a7c593d](https://optimistic.etherscan.io/address/0x00000000fcce7f938e7ae6d3c335bd6a1a7c593d) |
23 | | KeyRegistry | [0x00000000fc1237824fb747abde0ff18990e59b7e](https://optimistic.etherscan.io/address/0x00000000fc1237824fb747abde0ff18990e59b7e) |
24 |
25 | ### Id Registry
26 |
27 | The IdRegistry lets users register, transfer and recover Farcaster accounts. An account is identified by a unique number (the fid) which is assigned to an Ethereum address on registration. An Ethereum address may only own one account at a time, though it may transfer it freely to other accounts. It may also specify a recovery address which can transfer the account at any time.
28 |
29 | ### Storage Registry
30 |
31 | The Storage Registry lets accounts rent [storage](../what-is-farcaster/messages.md#storage) by making a payment in ETH. The storage prices are set by admins in USD and converted to ETH using a Chainlink oracle. The price increases or decreases based on supply and demand.
32 |
33 | ### Key Registry
34 |
35 | The Key Registry lets accounts issue keys to apps, so that they can publish messages on their behalf. Keys can be added or removed at any time. To add a key, an account must submit the public key of an EdDSA key pair along with a requestor signature. The requestor can be the account itself or an app that wants to operate on its behalf.
36 |
--------------------------------------------------------------------------------
/docs/learn/architecture/ens-names.md:
--------------------------------------------------------------------------------
1 | # ENS Names
2 |
3 | Farcaster uses ENS names as human readable identifiers for accounts. Two kinds of ENS names are supported:
4 |
5 | - **Offchain ENS names**: free and controlled by farcaster. (e.g. @alice)
6 | - **Onchain ENS names**: costs money and is controlled by your wallet. (e.g. @alice.eth)
7 |
8 | ENS names can only be used on Farcaster if they are <= 16 characters and contain only lowercase letters, numbers, and hyphens.
9 |
10 | 
11 |
12 | ## Onchain ENS Names
13 |
14 | Users can use onchain ENS names like `@alice.eth` on Farcaster.
15 |
16 | Onchain ENS names are issued by ENS, end in .eth and must be registered on the Ethereum L1 blockchain. Anyone can register an ENS name by using the [ENS app](https://app.ens.domains/).
17 |
18 | Users must pay a fee to register an onchain ENS name, but once registered, it is controlled by the user and cannot be revoked.
19 |
20 | ## Offchain ENS Names (Fnames)
21 |
22 | Users can use offchain ENS names like `@alice` on Farcaster.
23 |
24 | Offchain ENS names, also called Farcaster Names or Fnames, are compliant with ENS but registered offchain. Fnames are free but are subject to a usage policy to prevent squatting and impersonation. They are also subject to the following requirements:
25 |
26 | 1. An account can only have one Fname at a time.
27 | 2. An account can change its Fname once every 28 days.
28 |
29 | ### Usage Policy
30 |
31 | Registering an Fname is free but subject to the following policy:
32 |
33 | 1. Names connected to public figures or entities may be reclaimed (e.g. @google).
34 | 2. Names that haven't been used for 60+ days may be reclaimed.
35 | 3. Names that are registered for the sole purpose of resale may be reclaimed.
36 |
37 | Decisions are made by the Farcaster team and often require human judgment. Users who want a name that is fully under their control should use an onchain ENS name.
38 |
39 | ### Registry
40 |
41 | Fnames are issued as offchain names under the subdomain `fcast.id`.
42 |
43 | Bob can register the offchain ENS name `bob.fcast.id` and use it on any Farcaster app with the shorthand `@bob`. The name can be registered by making a signed request to the Fname Registry server. See the [FName API reference](/reference/fname/api) for more details on how to query and create Fnames.
44 |
45 | To learn more about how Fnames work, see [ENSIP-16](https://docs.ens.domains/ens-improvement-proposals/ensip-16-offchain-metadata)
46 | and [ERC-3668](https://eips.ethereum.org/EIPS/eip-3668).
47 |
--------------------------------------------------------------------------------
/docs/learn/architecture/overview.md:
--------------------------------------------------------------------------------
1 | # Architecture
2 |
3 | Farcaster has a hybrid architecture that stores identity onchain and data offchain.
4 |
5 | 
6 |
7 | ## Onchain
8 |
9 | Farcaster's onchain systems are implemented as [contracts on OP Mainnet](./contracts.md). Actions are performed onchain only when security and consistency are critical. Use of onchain actions is kept at a minimum to reduce costs and improve performance.
10 |
11 | Only a handful of actions are performed onchain, including:
12 |
13 | - Creating an [account](../what-is-farcaster/accounts.md).
14 | - Paying rent to [store data](../what-is-farcaster/messages.md#storage).
15 | - Adding account keys for [connected apps](../what-is-farcaster/apps.md#connected-apps).
16 |
17 | ## Offchain
18 |
19 | Farcaster's offchain system is a peer-to-peer network of servers called [Snapchain](https://snapchain.farcaster.xyz/) which store user data. The majority of user actions are performed offchain. These include:
20 |
21 | - Posting a new public message.
22 | - Following another user.
23 | - Reacting to a post.
24 | - Updating your profile picture.
25 |
26 | Actions are performed offchain when performance and cost are critical. Use of offchain actions is typically preferred when consistency isn't a strict requirement. Offchain systems achieve security by relying on signatures from onchain systems.
27 |
--------------------------------------------------------------------------------
/docs/learn/contributing/fips.md:
--------------------------------------------------------------------------------
1 | # FIPs
2 |
3 | An FIP, or Farcaster Improvement Proposal, is a process for building consensus around protocol changes. FIP's are
4 | inspired by [Ethereum's EIPs](https://eips.ethereum.org/EIPS/eip-1)
5 | and [Python's PEPs](https://peps.python.org/pep-0001/). Anyone can write an FIP to propose a change to:
6 |
7 | 1. A process, like the protocol's release schedule
8 | 2. A standard, like URIs for onchain assets
9 | 3. An implementation, like adding a new protocol feature
10 |
11 | Read more about FIP's
12 | in [FIP-0: A proposal for making proposals](https://github.com/farcasterxyz/protocol/discussions/82). A list of
13 | finalized proposals can be found below. Proposals are made and ratified on
14 | the [discussions board](https://github.com/farcasterxyz/protocol/discussions/categories/fip-stage-4-finalized).
15 |
16 | | FIP | Title | Authors |
17 | | --- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------- |
18 | | 0 | [A proposal for making proposals](https://github.com/farcasterxyz/protocol/discussions/82) | @v |
19 | | 1 | [Canonical URIs](https://github.com/farcasterxyz/protocol/discussions/72) | @pfh, @v |
20 | | 2 | [Flexible targets for messages](https://github.com/farcasterxyz/protocol/discussions/71) | @pfh |
21 | | 3 | [Links](https://github.com/farcasterxyz/protocol/discussions/85) | @cassie, @v |
22 | | 4 | [ENS Usernames](https://github.com/farcasterxyz/protocol/discussions/90) | @horsefacts, @sanjay, @sds, @v |
23 | | 5 | [Instant Recovery](https://github.com/farcasterxyz/protocol/discussions/100) | @v |
24 | | 6 | [Flexible Storage](https://github.com/farcasterxyz/protocol/discussions/98) | @cassie, @horsefacts, @v |
25 | | 7 | [Onchain Signers](https://github.com/farcasterxyz/protocol/discussions/103) | @horsefacts, @sanjay, @v |
26 | | 8 | [Verifications for Contract Wallets](https://github.com/farcasterxyz/protocol/discussions/109) | @horsefacts, @sanjay, @eulerlagrange.eth |
27 | | 9 | [Globally Unique Verifications](https://github.com/farcasterxyz/protocol/discussions/114) | @sanjay, @v |
28 | | 10 | [Gateways](https://github.com/farcasterxyz/protocol/discussions/133) | @horsefacts, @sanjay, @v |
29 | | 11 | [Sign in with Farcaster](https://github.com/farcasterxyz/protocol/discussions/110) | @deodad, @horsefacts, @sanjay, @v |
30 | | 12 | [Pricing schedule for flexible storage](https://github.com/farcasterxyz/protocol/discussions/126) | @v |
31 | | 13 | [Canonical serialization for hashing messages](https://github.com/farcasterxyz/protocol/discussions/87) | @sanjay, @adityapk |
32 |
--------------------------------------------------------------------------------
/docs/learn/contributing/governance.md:
--------------------------------------------------------------------------------
1 | # Governance
2 |
3 | Farcaster embraces [rough consensus and running code](https://en.wikipedia.org/wiki/Rough_consensus) as its governance model. Changes happen when someone makes a proposal, gets buy-in and ships running code. Depending on the change, different groups need to be convinced:
4 |
5 | 1. **Protocol devs**, who choose to merge changes into hubs and contracts.
6 | 2. **Hub runners**, who choose to deploy those changes to their hubs.
7 | 3. **App devs**, who choose the hubs they read from.
8 | 4. **Users**, who choose the apps they want to use.
9 |
10 | Consensus emerges from people accepting new code or rejecting it. Farcaster will not have a binding voting process,
11 | official roles or veto power for anyone. Having too much structure ossifies systems, encourages politicking and slows
12 | progress. Rough consensus biases to action, encourages diversity of viewpoints, and maximizes decentralization, which is
13 | essential for a long-lived protocol. Most changes happen through the [FIP](./fips.md) process.
14 |
--------------------------------------------------------------------------------
/docs/learn/contributing/overview.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Farcaster welcomes contributions of all sizes from the community. The protocol owes thanks to over 100 contributors who
4 | have helped us so far.
5 |
6 | To get involved, try looking up open issues in one of the repos below or join a dev call.
7 |
8 | ## Repositories
9 |
10 | | Repository | Description |
11 | | ---------------------------------------------------------------- | ------------------------------------------- |
12 | | [Protocol](https://github.com/farcasterxyz/protocol) | Specification of the protocol |
13 | | [Contracts](https://github.com/farcasterxyz/contracts) | The canonical Farcaster contracts |
14 | | [Snapchain](https://github.com/farcasterxyz/snapchain) | A Farcaster node written in Rust |
15 | | [FName Registry](https://github.com/farcasterxyz/fname-registry) | The canonical server to register fnames |
16 | | [Docs](https://github.com/farcasterxyz/docs) | Documentation for all the above (this site) |
17 |
18 | ## Documentation
19 |
20 | This site serves as the central hub for documentation on the protocol. If you have feedback, please open an issue or
21 | create a pull request at [farcasterxyz/docs](https://github.com/farcasterxyz/docs)
22 |
23 | ## Dev Calls
24 |
25 | We host a bi-weekly developer call to discuss upcoming changes to the protocol. The call is open to anyone and is a
26 | great way to get involved.
27 |
28 | - [Calendar Invite](https://calendar.google.com/calendar/u/0?cid=NjA5ZWM4Y2IwMmZiMWM2ZDYyMTkzNWM1YWNkZTRlNWExN2YxOWQ2NDU3NTA3MjQwMTk3YmJlZGFjYTQ3MjZlOEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t) -
29 | Calendar invite to join upcoming calls.
30 | - [Recordings](https://www.youtube.com/watch?v=lmGXWP5m1_Y&list=PL0eq1PLf6eUeZnPtyKMS6uN9I5iRIlnvq) - watch recordings
31 | of previous calls.
32 |
--------------------------------------------------------------------------------
/docs/learn/index.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | Farcaster is a [sufficiently decentralized](https://www.varunsrinivasan.com/2022/01/11/sufficient-decentralization-for-social-networks) social network built on Ethereum.
4 |
5 | It is a public social network similar to X and Reddit. Users can create profiles, post "casts" and follow others. They own their accounts and relationships with other users and are free to move between different apps.
6 |
7 | :::tip Join Farcaster
8 | If you're not on Farcaster, get started by [creating your account](https://www.farcaster.xyz/) with the official Farcaster client.
9 | :::
10 |
11 | ## Learn
12 |
13 | If you want to learn more, get started by diving into these concepts:
14 |
15 | - [Farcaster 101](https://www.youtube.com/playlist?list=PL0eq1PLf6eUdm35v_840EGLXkVJDhxhcF) - a walkthrough of the Farcaster protocol in short, 5 minute videos.
16 | - [Core Concepts](/learn/what-is-farcaster/accounts) - learn about the building blocks of Farcaster, starting with accounts.
17 | - [Architecture](/learn/architecture/overview) - a breakdown of Farcaster's onchain and offchain systems.
18 |
19 | ## Tutorials
20 |
21 | - [Build your first mini app](/developers/frames/getting-started) - Make mini-apps that run inside Farcaster.
22 | - [Sign in with Farcaster](/auth-kit/installation) - Let users login to your app with their Farcaster account.
23 | - [Write your first app](/developers/index) - Publish a "Hello World" message to Farcaster.
24 |
25 | Find more how-tos, guide and tutorials like this in the [developers](/developers/) section.
26 |
27 | ## Documentation
28 |
29 | - [Farcaster Spec](https://github.com/farcasterxyz/protocol) - Specifications for Farcaster, including its contracts and nodes.
30 | - [Mini Apps Spec](/developers/frames/spec) - Specifications for writing and rendering mini apps in Farcaster apps.
31 | - [APIs](/reference/) - Docs for API's and ABI's for onchain and offchain systems.
32 |
33 | ## Contributing
34 |
35 | To learn about how to contribute to the protocol, including this documentation site, check out
36 | the [Contributing](/learn/contributing/overview) section.
37 |
--------------------------------------------------------------------------------
/docs/learn/what-is-farcaster/accounts.md:
--------------------------------------------------------------------------------
1 | # Accounts
2 |
3 | A Farcaster account lets you set up a username, profile picture and publish short text messages known as casts. Any Ethereum address can register a Farcaster account by making an onchain transaction.
4 |
5 | ## Creating an account
6 |
7 | A Farcaster account is created by calling the IdGateway contract. It will assign a new Farcaster ID or fid to your Ethereum address.
8 |
9 | You'll need to get a username, rent storage and add a key before you can use your account. These steps require many signatures and onchain transactions and can be tedious with a regular Ethereum wallet.
10 |
11 | We recommend starting with the [official client](https://www.farcaster.xyz/), developed by the Farcaster team which will handle the entire flow for you. It also uses a separate Ethereum account to sign transactions, so you can keep your main Ethereum account secure.
12 |
13 | ## Adding account keys
14 |
15 | Accounts can issue keys which let apps write messages on their behalf. Users will typically issue a key to each Farcaster app they use.
16 |
17 | Keys are managed by the KeyRegistry contract. To add a key, you'll need to submit the public key of an EdDSA key pair along with a requestor signature. The requestor can be the account itself or an app that wants to operate on its behalf.
18 |
19 | ## Recovering an account
20 |
21 | Users often set up separate wallets for their social apps and it's easy to lose access. Farcaster lets any account specify a recovery address which can be used to recover the account. It can be configured when creating the account or anytime after.
22 |
23 | Users can set the recovery address to trusted services like the official Farcaster client or they can manage it themselves using a regular Ethereum wallet.
24 |
25 | ## Resources
26 |
27 | ### Specifications
28 |
29 | - [Contract Specifications](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#1-smart-contracts) - The onchain contracts that manage Farcaster accounts, account keys and recovery addresses.
30 |
31 | ### APIs
32 |
33 | - [IdRegistry](../../reference/contracts/reference/id-registry) - Lookup account data onchain.
34 | - [IdGateway](../../reference/contracts/reference/id-gateway) - Create accounts onchain.
35 | - [KeyRegistry](../../reference/contracts/reference/key-registry) - Lookup account key data onchain.
36 | - [KeyGateway](../../reference/contracts/reference/key-gateway) - Create account keys onchain.
37 | - [Get Farcaster Ids](https://snapchain.farcaster.xyz/reference/httpapi/fids) - Fetch a list of all registered account fids from a Snapchain node.
38 | - [Get account keys](https://snapchain.farcaster.xyz/reference/httpapi/onchain#onchainsignersbyfid) - Fetch the account keys (signers) for an account from a Snapchain node.
39 |
40 | ### Tutorials
41 |
42 | - [Create an account](../../developers/guides/accounts/create-account.md) - Create a new account on Farcaster.
43 | - [Create an account key](../../developers/guides/accounts/create-account-key.md) - Create a new account key for your account.
44 | - [Find account by username](../../developers/guides/accounts/find-by-name.md) - Find an account by its username.
45 | - [Change custody address](../../developers/guides/accounts/change-custody.md) - Change the address that owns your account.
46 | - [Change recovery address](../../developers/guides/accounts/change-recovery.md) - Change the address that recovers your account.
47 | - [Find account key requestor](../../developers/guides/advanced/decode-key-metadata.md) - Find the app that the user granted an account key to.
48 | - [Query signups from replicator](../../developers/guides/advanced/query-signups.md) - Query the number of signups from the replicator.
49 |
--------------------------------------------------------------------------------
/docs/learn/what-is-farcaster/apps.md:
--------------------------------------------------------------------------------
1 | # Apps
2 |
3 | Using Farcaster requires an Ethereum wallet to register your account and UI to browse the network. If you are new, we recommend starting with the official Farcaster client on [iOS](https://apps.apple.com/us/app/warpcast/id1600555445) or [Android](https://play.google.com/store/apps/details?id=com.farcaster.mobile&hl=en_US&gl=US)
4 |
5 | There are two kinds of apps:
6 |
7 | 1. **Wallet App** - allows signing up, adding connected apps, posting and browsing messages.
8 | 2. **Connected App** - allows posting and browsing messages only.
9 |
10 | ## Wallet Apps
11 |
12 | Users must install a wallet app to get started with Farcaster. They can take onchain and offchain actions like signing up, adding connected apps, posting messages and users.
13 |
14 | A wallet app controls the Ethereum address that owns the account. It has control over the account and can take any action on your behalf, so only use a wallet app that you trust.
15 |
16 | ### Farcaster client
17 |
18 | The Farcaster client is a wallet app developed by the Farcaster team. It has a web and mobile app, though signing up is only available on mobile.
19 |
20 | - Download: [iOS](https://apps.apple.com/us/app/warpcast/id1600555445), [Android](https://play.google.com/store/apps/details?id=com.farcaster.mobile&hl=en_US&gl=US)
21 |
22 | ## Connected Apps
23 |
24 | Connected apps can only be added once a user signs up with a wallet app. They can take offchain actions on Farcaster like writing casts, following accounts and browsing.
25 |
26 | A connected app controls an app key granted by the wallet app. Users can add many connected apps to their account and remove them at any time. A malicious connected app cannot take control of your account and any actions it takes can be reversed by your wallet app.
27 |
28 | Some popular connected apps include:
29 |
30 | - [Supercast](https://supercast.xyz/)
31 | - [Yup](https://yup.io/)
32 | - [Farcord](https://farcord.com/)
33 |
34 | **Connected apps are not reviewed by Farcaster, use them at your own risk**
35 |
36 | ## Resources
37 |
38 | ### Tools
39 |
40 | - [Snapchain](https://snapchain.farcaster.xyz/) - a node for reading and writing messages.
41 | - [Replicator](https://github.com/farcasterxyz/hub-monorepo/tree/main/apps/replicator) - a tool to sync a hub to a postgres database.
42 |
43 | ### Tutorials
44 |
45 | - [Set up snapchain](https://snapchain.farcaster.xyz/guides/running-a-node) - run a snapchain node.
46 | - [Set up replicator](https://snapchain.farcaster.xyz/guides/syncing-to-db) - sync a hub to postgres for easy querying.
47 | - [Schema for replication](../../reference/replicator/schema) - schema for a replicator's postgres tables.
48 |
49 | ### Services
50 |
51 | - [Neynar](https://neynar.com/) - infrastructure and services for building farcaster apps.
52 |
--------------------------------------------------------------------------------
/docs/learn/what-is-farcaster/channels.md:
--------------------------------------------------------------------------------
1 | # Channels
2 |
3 | A channel is a public space for your community to have conversations around a topic.
4 |
5 | Creating a channel starts a new feed for your community. People can join, cast and find other interesting people. It sparks conversations that wouldn’t otherwise happen on the home feed.
6 |
7 | :::warning Experimental Feature
8 | Channels are being prototyped in the Farcaster client and not fully supported by the Farcaster protocol. They may be ported to the protocol in the future if the feature is deemed successful or they may be removed entirely.
9 | :::
10 |
11 | ## Hosting Channels
12 |
13 | Anyone can create a channel host by paying a fee in the Farcaster client and choosing a channel name. The name must be under 16 characters and can only contain lowercase alphabets and numbers. A channel's creator is called a host and may invite other co-hosts to operate the channel. Hosts have special privileges like:
14 |
15 | 1. Defining “channel norms" which everyone must agree to when joining.
16 | 2. Pinning or hiding casts in a channel.
17 | 3. Blocking other users from casting in their channel.
18 | 4. Setting a channel picture, description and other metadata.
19 |
20 | Channel metadata is not part of the protocol and stored in the Farcaster client while channels are in the experimental stage.
21 |
22 | ## Casting in Channels
23 |
24 | Anyone can post into a channel by using the Farcaster client and selecting the channel when creating the cast. The client automatically sets the cast's `parentUrl` to `https://farcaster.xyz/~/channel/`. A cast is considered "in a channel" if it's parentUrl is the channel URI or another cast which is "in a channel".
25 |
26 | Channel casts are part of the protocol and stored on hubs. Using a replicator, you can fetch all casts in a channel by filtering the `parentUrl` field for the channel's FIP-2 URL.
27 |
28 | ## Following Channels
29 |
30 | Anyone can follow a channel just like a user. A user will see casts from a followed channel in their home feed when using the Farcaster client.
31 |
32 | Channel follows are not part of the protocol and are stored in the Farcaster client while channels are in the experimental stage.
33 |
34 | ## Cast Visibility
35 |
36 | If a user casts in a channel, Farcaster will:
37 |
38 | 1. Always send the casts to the home feeds of any user who follows the channel.
39 | 2. Usually send the casts to the home feeds of any user who follows the author.
40 |
41 | The determination for (2) is made based on the user's preferences, channel contents and other social graph data. This algorithm is still being fine tuned and will be documented once it is stable.
42 |
43 | ## Usage Policy
44 |
45 | The Farcaster client may remove your channel and will NOT refund your warps if:
46 |
47 | 1. Your profile or channel impersonates someone.
48 | 2. You squat a channel without using it.
49 | 3. You violate the Farcaster client's terms and conditions or app store rules.
50 |
51 | ## FAQ
52 |
53 | **Why are channel hosts allowed to hide and ban? Isn’t this censorship?**
54 |
55 | Channels are not free-for-all public spaces, they are owned and moderated by their creators. You are always free to start your own channel at any time with its own rules.
56 |
57 | **Why is there a fee for creating channels?**
58 |
59 | The fee discourages people from squatting short names and not using the channels.
60 |
61 | **What's the benefit of creating a channel?**
62 |
63 | Starting a channel also helps grow your audience:
64 |
65 | 1. The Farcaster client will send your followers a notification about your channel.
66 | 2. Your channel will be promoted to users who follow similar channels.
67 | 3. Users who follow your channel will see channel casts in their home feed.
68 |
69 | ## Resources
70 |
71 | ### APIs
72 |
73 | - [Farcaster Client Channel APIs](../../reference/warpcast/api.md) - fetch a list of all known channels
74 |
--------------------------------------------------------------------------------
/docs/learn/what-is-farcaster/messages.md:
--------------------------------------------------------------------------------
1 | # Messages
2 |
3 | Farcaster accounts interact by signing and publishing messages. Alice can create a message that says "_Hello @bob_" and sign it with her key.
4 |
5 | Messages are stored on a peer-to-peer network of nodes. A node in the Farcaster network is called a Hub, and each Hub stores a copy of the entire network. A user can publish a message to one Hub and it will propagate to the entire network in a few seconds. Farcaster's compact message format and eventually consistent model lets this architecture scale to millions of users.
6 |
7 | An account can generate a [key](./accounts.md#adding-account-keys) and give it to an app which can use it to sign messages. Users can use multiple apps with the same account, and each application can have its own key. Separating the signing keys from the ownership keys helps keep the account secure.
8 |
9 | ## Types
10 |
11 | Accounts can publish five different kinds of messages to the network:
12 |
13 | | Type | Description | Example |
14 | | ------------- | --------------------------------------------- | ------------------------------ |
15 | | Casts | Public messages that can be seen by anyone. | "Hello world!" |
16 | | Reactions | A relationship between an account and a cast. | Alice liked Bob's cast. |
17 | | Links | A relationship between two accounts. | Alice follows Bob. |
18 | | Profile Data | Metadata about the account. | Profile picture, display name. |
19 | | Verifications | A proof of ownership of something. | An Ethereum address. |
20 |
21 | ## Storage
22 |
23 | An account must pay rent to keep their messages on the Farcaster network. Charging rent prevents users from spamming the network.
24 |
25 | An account can rent a unit of storage by making an onchain transaction to the Storage Registry. A unit of storage costs $7 today, lasts for one year and lets each account store a certain number of messages of each type. The limits for each type today are:
26 |
27 | - 5000 Casts
28 | - 2500 Reactions
29 | - 2500 Links
30 | - 50 Profile Data
31 | - 50 Verifications
32 |
33 | If an account exceeds its limit for a message type, the oldest message is pruned to make space for the new one. The user can keep using the network without paying for more storage and Hubs can keep the storage load under control. An account can always purchase more storage to increase its limits.
34 |
35 | An account that lets its storage expire may lose all its messages. There is a 30-day grace period after a storage unit expires during which an account must renew or lose its messages.
36 |
37 | The price and size of each storage unit is re-calculated periodically to balance growth and quality of the network. See [FIP-6](https://github.com/farcasterxyz/protocol/discussions/98)
38 | for more details.
39 |
40 | ## Deletion
41 |
42 | An account can delete messages at any time by publishing a corresponding delete message. The delete message will remove the contents of the original message, leaving a tombstone in its place. A deleted message will still count towards the account's storage limit until it expires by being pushed out by a newer message.
43 |
44 | ## Timestamps
45 |
46 | Messages have timestamps which count seconds from the Farcaster Epoch, which began on `Jan 1, 2021 00:00:00 UTC`. Using a recent epoch makes timestamps and messages much smaller, which is important for the network.
47 |
48 | Timestamps are unverified and can be backdated by users, similar to a blog post. They cannot be more than 15 minutes into the future, as the network will reject such messages.
49 |
50 | ## Resources
51 |
52 | ### Specifications
53 |
54 | - [Messages](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#2-message-specifications) - the atomic unit of change on Farcaster
55 | - [CRDTs](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#31-crdts) - rules for keeping messages in sync on the network
56 | - [Storage Registry](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#13-storage-registry) - contract to acquire storage units
57 |
58 | ### APIs
59 |
60 | - [Get Casts](https://snapchain.farcaster.xyz/reference/httpapi/casts) - fetch an account's casts from a Snapchain node
61 | - [Get Reactions](https://snapchain.farcaster.xyz/reference/httpapi/reactions) - fetch an account's reactions from a Snapchain node
62 | - [Get Links](https://snapchain.farcaster.xyz/reference/httpapi/links) - fetch an account's links or follows from a Snapchain node
63 | - [Get UserData](https://snapchain.farcaster.xyz/reference/httpapi/userdata) - fetch an account's profile data from a Snapchain node
64 | - [Submit Message](https://snapchain.farcaster.xyz/reference/httpapi/message#submitmessage) - broadcast a message to the Snapchain network
65 | - [Validate Message](https://snapchain.farcaster.xyz/reference/httpapi/message#validatemessage) - verify a message's authenticity with a Snapchain node
66 | - [Storage Registry](../../reference/contracts/reference/storage-registry) - Acquire or check storage units for an account
67 |
68 | ### Tutorials
69 |
70 | - [Get casts](../../developers/guides/querying/fetch-casts) - Get an account's casts from a Snapchain node.
71 | - [Get profile](../../developers/guides/querying/fetch-profile) - Get an account's profile from a Snapchain node.
72 | - [Create common message types](../../developers/guides/writing/messages) - Create casts, links, reactions and userdata.
73 | - [Create casts with advanced features](../../developers/guides/writing/casts) - Create casts with embeds, emojis and mentions.
74 |
--------------------------------------------------------------------------------
/docs/learn/what-is-farcaster/usernames.md:
--------------------------------------------------------------------------------
1 | # Usernames
2 |
3 | A Farcaster account needs a username so it can be found and mentioned by other users. Farcaster uses the [Ethereum Name Service](https://ens.domains/) to manage usernames.
4 |
5 | ENS usernames are owned by Ethereum addresses, just like Farcaster accounts. The difference is that an address can own multiple ENS names, so the Farcaster account must specify the name it wishes to use. ENS names can only be used on Farcaster if they are <= 16 characters and contain only lowercase letters, numbers and hyphens.
6 |
7 | ## Changing usernames
8 |
9 | A Farcaster account can change between different usernames at any time. Changing names does not affect your history or your followers.
10 |
11 | It's safe to change your name a few times a year. But changing your name more often may cause users or apps to lose trust in your account. If you want to change a public indicator, consider changing your display name instead.
12 |
13 | ## Offchain vs Onchain Names
14 |
15 | An account can choose between two kinds of usernames:
16 |
17 | - **Offchain ENS Names**: free and controlled by farcaster. (e.g. @alice)
18 | - **Onchain ENS Names**: costs money and controlled by your wallet. (e.g. @alice.eth)
19 |
20 | Choose an offchain ENS name if you want to get started quickly and don't have an onchain ENS name. An account can always upgrade to an onchain name later. It's recommended to use an app like the official Farcaster client to set this up for you.
21 |
22 | 
23 |
24 | ### Offchain ENS Names
25 |
26 | - Offchain ENS names, also called fnames, are free and issued by Farcaster.
27 | - Any Ethereum account can get one unique fname by calling the [Fname Registry](/learn/architecture/ens-names).
28 | - Fnames are free but they can be revoked by Farcaster at any time.
29 |
30 | ### Onchain ENS fnames
31 |
32 | - Onchain ENS names, also called .eth names, are onchain and issued by ENS.
33 | - Any Ethereum account can get an ENS by calling the [ENS Registry](https://docs.ens.domains/dapp-developer-guide/the-ens-registry).
34 | - Names are not free but they cannot be revoked by Farcaster.
35 |
36 | ## Resources
37 |
38 | ### Specifications
39 |
40 | - [Farcaster Name](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#5-fname-specifications) - An ENSIP-10 offchain ENS name usable within Farcaster.
41 | - [UserData: Username](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#23-user-data) - Sets a valid Username Proof as the current username.
42 | - [Username Proof](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#17-username-proof) - Proves ownership of an onchain or offchain username.
43 | - [Verifications](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#25-verifications) - Proves ownership of an address, required for onchain Username Proofs.
44 |
45 | ### APIs
46 |
47 | - [UserData API](https://snapchain.farcaster.xyz/reference/httpapi/userdata) - Fetch the UserData for a user's current username.
48 | - [Username Proofs API](https://snapchain.farcaster.xyz/reference/httpapi/usernameproof) - Fetch a user's Username Proofs from a Snapchain node.
49 | - [Verification Proofs API](https://snapchain.farcaster.xyz/reference/httpapi/verification) - Fetch a user's Verifications from a Snapchain node.
50 | - [Fname Registry API](../../reference/fname/api.md) - Register and track fname ownership programmatically.
51 |
52 | ### Tutorials
53 |
54 | - [Get UserData](../../developers/guides/querying/fetch-profile.md) - Get UserData messages from an account.
55 | - [Create UserData](../../developers/guides/writing/messages#user-data) - Create a UserData message to select a valid username.
56 | - [Verify an Address](../../developers/guides/writing/verify-address.md) - Verify ownership of an Ethereum account.
57 | - [Find account by username](../../developers/guides/accounts/find-by-name.md) - Find an account by its username.
58 | - [Change farcaster name](../../developers/guides/accounts/change-fname.md) - Change a farcaster username.
59 |
--------------------------------------------------------------------------------
/docs/public/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/public/icon.png
--------------------------------------------------------------------------------
/docs/public/og-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/farcasterxyz/docs/fb73a480dea944e59a72bae2951881aea9b8b1cb/docs/public/og-image.png
--------------------------------------------------------------------------------
/docs/reference/contracts/deployments.md:
--------------------------------------------------------------------------------
1 | # Deployments
2 |
3 | ## Addresses
4 |
5 | The Farcaster contracts are deployed on Optimism and Base mainnet. There are no testnet deployments.
6 |
7 | Optimism:
8 |
9 | | Contract | Optimism Address | Etherscan Link |
10 | | ---------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ |
11 | | Id Registry | `0x00000000fc6c5f01fc30151999387bb99a9f489b` | [link](https://optimistic.etherscan.io/address/0x00000000fc6c5f01fc30151999387bb99a9f489b) |
12 | | Key Registry | `0x00000000Fc1237824fb747aBDE0FF18990E59b7e` | [link](https://optimistic.etherscan.io/address/0x00000000Fc1237824fb747aBDE0FF18990E59b7e) |
13 | | Storage Registry | `0x00000000fcCe7f938e7aE6D3c335bD6a1a7c593D` | [link](https://optimistic.etherscan.io/address/0x00000000fcCe7f938e7aE6D3c335bD6a1a7c593D) |
14 | | IdGateway | `0x00000000fc25870c6ed6b6c7e41fb078b7656f69` | [link](https://optimistic.etherscan.io/address/0x00000000fc25870c6ed6b6c7e41fb078b7656f69) |
15 | | KeyGateway | `0x00000000fc56947c7e7183f8ca4b62398caadf0b` | [link](https://optimistic.etherscan.io/address/0x00000000fc56947c7e7183f8ca4b62398caadf0b) |
16 | | Bundler | `0x00000000fc04c910a0b5fea33b03e0447ad0b0aa` | [link](https://optimistic.etherscan.io/address/0x00000000fc04c910a0b5fea33b03e0447ad0b0aa) |
17 |
18 | Base:
19 |
20 | | Contract | Base Address | Etherscan Link |
21 | | ------------- | -------------------------------------------- | ------------------------------------------------------------------------------- |
22 | | Tier Registry | `0x00000000fc84484d585C3cF48d213424DFDE43FD` | [link](https://basescan.org/address/0x00000000fc84484d585c3cf48d213424dfde43fd) |
23 |
24 | ## ABIs
25 |
26 | The ABIs for the contracts are available via etherscan links above, or from the [`@farcaster/core`](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/core/src/eth/contracts/abis) package.
27 |
--------------------------------------------------------------------------------
/docs/reference/contracts/faq.md:
--------------------------------------------------------------------------------
1 | # FAQ
2 |
3 | ## Signatures
4 |
5 | ### How do I generate an EIP-712 signature?
6 |
7 | See the contract reference docs for documentation on each EIP-712 signature, including Typescript [code examples](/reference/contracts/reference/id-gateway#register-signature).
8 |
9 | If you're using Typescript/JS, the [`@farcaster/hub-web`](https://www.npmjs.com/package/@farcaster/hub-web) package includes tools for generating and working with EIP-712 signatures. To ensure you're using the correct addresses and typehashes, we recommend importing the ABIs and EIP-712 types from the [contracts module](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/core/src/eth/contracts) or using the provided [`Eip712Signer`](https://github.com/farcasterxyz/hub-monorepo/blob/main/packages/core/src/signers/eip712Signer.ts) helper.
10 |
11 | See the "Working with EIP-712 signatures" [example app](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/hub-nodejs/examples/contract-signatures) in the hub monorepo for a reference that demonstrates each signature and contract call.
12 |
13 | ### How can I debug an invalid EIP-712 signature?
14 |
15 | To help debug EIP-712 signing, every contract that uses EIP-712 signatures exposes its [domain separator](https://optimistic.etherscan.io/address/0x00000000fc25870c6ed6b6c7e41fb078b7656f69#readContract#F3) and typehashes as [constants](https://optimistic.etherscan.io/address/0x00000000fc25870c6ed6b6c7e41fb078b7656f69#readContract#F1) along with a [hashTypedDataV4](https://optimistic.etherscan.io/address/0x00000000fc25870c6ed6b6c7e41fb078b7656f69#readContract#F6) helper view. If you're constructing signatures in Solidity or another low level language, you can use these to help debug.
16 |
17 | ## Reference
18 |
19 | ### Where is the full contract source code?
20 |
21 | The contracts repo is on Github [here](https://github.com/farcasterxyz/contracts).
22 |
23 | ### Where do I get contract ABIs?
24 |
25 | Find contract ABIs and deployment addresses [here](/reference/contracts/deployments#abis).
26 |
27 | ### Where can I find audit reports?
28 |
29 | Past audit reports are linked from the [contracts repo](https://github.com/farcasterxyz/contracts/blob/1aceebe916de446f69b98ba1745a42f071785730/README.md#audits).
30 |
31 | ### Are the Farcaster contracts deployed to a testnet?
32 |
33 | No. Consider using [network forking](https://book.getfoundry.sh/tutorials/forking-mainnet-with-cast-anvil) to test or develop against the OP mainnet contracts.
34 |
35 | ## Data
36 |
37 | ### How do I find a user’s custody address?
38 |
39 | Call the [`custodyOf`](https://optimistic.etherscan.io/address/0x00000000fc6c5f01fc30151999387bb99a9f489b#readContract#F5) function on the [IdRegistry](/reference/contracts/reference/id-registry.md).
40 |
41 | ### How do I find a user’s recovery address?
42 |
43 | Call the [`recoveryOf`](https://optimistic.etherscan.io/address/0x00000000fc6c5f01fc30151999387bb99a9f489b#readContract#F23) function on the [IdRegistry](/reference/contracts/reference/id-registry.md).
44 |
45 | ### How do I find an account’s fid?
46 |
47 | Call the [`idOf`](https://optimistic.etherscan.io/address/0x00000000fc6c5f01fc30151999387bb99a9f489b#readContract#F14) function on the [IdRegistry](/reference/contracts/reference/id-registry.md).
48 |
49 | ### How do I look up the account keys for my fid?
50 |
51 | Call the [`keysOf`](https://optimistic.etherscan.io/address/0x00000000fc1237824fb747abde0ff18990e59b7e#readContract#F16) function on the [KeyRegistry](/reference/contracts/reference/key-registry.md).
52 |
53 | ## Other
54 |
55 | ### What is an app fid? How do I get one?
56 |
57 | **What is an FID?**
58 |
59 | An FID (Farcaster ID) is a unique identifier used to distinguish applications and users. With an FID, apps and users can be identified and differentiated.
60 |
61 | **Why is an FID necessary?**
62 |
63 | To create or post anything on the Farcaster platform, an FID is essential for identifying your app or user.
64 |
65 | **How do I get one?**
66 |
67 | You can register an app fid directly through the [Bundler](/reference/contracts/reference/bundler.md) or [IdGateway](/reference/contracts/reference/id-gateway.md), or use a Farcaster client to register an account for your app. Since you'll need to sign [key request metadata](/reference/contracts/reference/signed-key-request-validator.md) from the wallet that owns your app fid, keep the private key secure.
68 |
--------------------------------------------------------------------------------
/docs/reference/contracts/index.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | The core Farcaster contracts are deployed on Optimism, an Ethereum layer 2 network. There are three core contracts:
4 | Id Registry, Key Registry, and Storage Registry. Write access to the ID and Key registry is gated through the Gateway
5 | contracts. There is also a Bundler helper contract to make it easy to register an fid, add a key and rent storage in one
6 | transaction.
7 |
8 | The Tier Registry contract supporting Farcaster Pro subscriptions is deployed on Base, an Ethereum layer 2 network.
9 |
10 | 
11 |
12 | ## Id Registry
13 |
14 | The Id Registry contract is used to keep track of Farcaster IDs. It maps an fid to an owning Ethereum
15 | address. The owner can also designate a "recovery address" which can be used to recover the fid if the owner loses
16 | access to the registering address. Registering an fid for the first time must be done through
17 | the [ID Gateway](#idgateway).
18 |
19 | ## Key Registry
20 |
21 | The Key Registry associates a Farcaster id to zero or more ed2559 public keys. Only messages signed by a key registered
22 | here are considered valid by the hubs. Registered keys can be revoked by the owner of the fid, but revoked keys can not
23 | be added to that fid again. The same key may be registered to multiple fids. Adding a key must be done through the
24 | [Key Gateway](#keygateway).
25 |
26 | ## Storage Registry
27 |
28 | The Storage Registry allows an fid to rent one or more "units" of storage on the farcaster network. The current cost of
29 | storage is 7$ USD per unit, for one year. This fee must be paid in ETH. The storage registry uses an ETH price oracle to
30 | determine the current cost in ETH and exposes functions to query this price. Overpayments are refunded to the caller.
31 |
32 | ## Id Gateway
33 |
34 | The ID Gateway handles additional logic required for first time registration of an fid. To prevent spam, the
35 | gateway also requires renting 1 unit of storage.
36 |
37 | ## Key Gateway
38 |
39 | Similarly, the Key Gateway exists for the Key Registry. Adding a key to a fid must be done via the gateway.
40 |
41 | ## Bundler
42 |
43 | The Bundler makes first time sign up easier by allowing a user to register an fid, add a key and rent storage in one
44 | function call.
45 |
46 | ## Tier Registry
47 |
48 | The Tier Registry collects subscription payments for Farcaster Pro, paid in USDC. Unlike other core protocol contracts,
49 | it is deployed on Base mainnet.
50 |
51 | ## Source code
52 |
53 | The contracts source repo can be found [here](https://github.com/farcasterxyz/contracts), including more low level
54 | documentation [here](https://github.com/farcasterxyz/contracts/blob/main/docs/docs.md).
55 |
--------------------------------------------------------------------------------
/docs/reference/contracts/reference/bundler.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: [2, 3]
3 | ---
4 |
5 | # Bundler
6 |
7 | The Bundler makes first time sign up easier by allowing a user to register an fid, add a key and rent storage in one transaction.
8 |
9 | If you want to create a new Farcaster account in a single transaction, use the Bundler.
10 |
11 | ## Read
12 |
13 | ### price
14 |
15 | Get the price in wei to register an fid, including 1 storage unit. To add additional storage units to the calculation, use the `extraStorage` parameter.
16 |
17 | | Parameter | type | Description |
18 | | ------------ | --------- | --------------------------------------------- |
19 | | extraStorage | `uint256` | Number of extra units to include in the price |
20 |
21 | ## Write
22 |
23 | ### register
24 |
25 | Register an fid, add one or more keys, and rent storage in a single step. For a detailed usage example, see the [signup demo app](https://farcaster-signup-demo.vercel.app/bundler).
26 |
27 | | Parameter | type | Description |
28 | | -------------- | -------------------- | --------------------------------------------- |
29 | | `msg.value` | `wei` | Payment amount for registration |
30 | | registerParams | `RegistrationParams` | Registration related parameters and signature |
31 | | signerParams | `SignerParams[]` | Key related parameters and signature |
32 | | extraStorage | `uint256` | Additional storage units to rent |
33 |
34 | **RegistrationParams struct**
35 |
36 | The `RegistrationParams` struct includes registration parameters and an IdGateway [`Register`](/reference/contracts/reference/id-gateway#register-signature) signature from the fid recipient.
37 |
38 | | Parameter | type | Description |
39 | | --------- | --------- | -------------------------------------------------------------------------------------------------------------- |
40 | | to | `address` | Address to register the fid to |
41 | | recovery | `address` | Recovery address for the new fid |
42 | | deadline | `uint256` | Signature expiration timestamp signature |
43 | | sig | `bytes` | EIP-712 [`Register`](/reference/contracts/reference/key-gateway#add-signature) signature from the `to` address |
44 |
45 | **SignerParams struct**
46 |
47 | The `SignerParams` struct includes signer key parameters and a KeyGateway [`Add`](/reference/contracts/reference/key-gateway#add-signature) signature from the fid recipient. Callers may provide multiple `SignerParams` structs to add multiple keys at registration time.
48 |
49 | | Parameter | type | Description |
50 | | ------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------- |
51 | | keyType | `uint32` | Must be set to `1`. This is currently the only supported `keyType`. |
52 | | key | `bytes` | Public key to add |
53 | | metadataType | `uint8` | Must be set to `1`. This is currently the only supported `metadataType`. |
54 | | metadata | `bytes` | Encoded [`SignedKeyRequestMetadata`](/reference/contracts/reference/signed-key-request-validator#signedkeyrequestmetadata-struct) |
55 | | deadline | `uint256` | Signature expiration timestamp |
56 | | sig | `bytes` | EIP-712 [`Add`](/reference/contracts/reference/key-gateway#add-signature) signature from `registrationParams.to` address |
57 |
58 | ## Errors
59 |
60 | | Error | Selector | Description |
61 | | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
62 | | InvalidPayment | `3c6b4b28` | The caller provided insufficient payment. |
63 | | InvalidMetadata | `bcecb64a` | The signed metadata provided with the key is invalid. |
64 | | InvalidSignature | `8baa579f` | The provided signature is invalid. It may be incorrectly formatted, or signed by the wrong address. |
65 | | SignatureExpired | `0819bdcd` | The provided signature has expired. Collect a new signature from the signer with a later deadline timestamp. |
66 |
67 | ## Source
68 |
69 | [`Bundler.sol`](https://github.com/farcasterxyz/contracts/blob/1aceebe916de446f69b98ba1745a42f071785730/src/Bundler.sol)
70 |
--------------------------------------------------------------------------------
/docs/reference/contracts/reference/id-gateway.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: [2, 3]
3 | ---
4 |
5 | # ID Gateway
6 |
7 | The ID Gateway registers new Farcaster IDs and adds them to the [Id Registry](/reference/contracts/reference/id-registry.md).
8 |
9 | If you want to create a new Farcaster ID, use the ID Gateway.
10 |
11 | ## Read
12 |
13 | ### price
14 |
15 | Get the price in wei to register an fid. This includes the price of 1 storage unit. Use the `extraStorage` parameter to include extra storage units in the total price.
16 |
17 | | Parameter | type | Description |
18 | | ------------ | -------------------- | -------------------------------------- |
19 | | extraStorage | `uint256` (optional) | The number of additional storage units |
20 |
21 | ### nonces
22 |
23 | Get the next unused nonce for an address. Used for generating an EIP-712 [`Register`](#register-signature) signature for [registerFor](#registerfor).
24 |
25 | | Parameter | type | Description |
26 | | --------- | --------- | ---------------------------- |
27 | | owner | `address` | Address to get the nonce for |
28 |
29 | ## Write
30 |
31 | ### register
32 |
33 | Register a new fid to the caller and pay for storage. The caller must not already own an fid.
34 |
35 | | Parameter | type | Description |
36 | | ------------ | -------------------- | ------------------------------------------ |
37 | | `msg.value` | `wei` | Amount to pay for registration |
38 | | recovery | `address` | Recovery address for the new fid |
39 | | extraStorage | `uint256` (optional) | Number of additional storage units to rent |
40 |
41 | ### registerFor
42 |
43 | Register a new fid to a specific address and pay for storage. The receiving
44 | address must sign an EIP-712 [`Register`](#register-signature) message approving the registration. The receiver must not already own an fid.
45 |
46 | | Parameter | type | Description |
47 | | ------------ | -------------------- | -------------------------------------------------- |
48 | | `msg.value` | `wei` | Amount to pay for registration |
49 | | to | `address` | The address to register the fid to |
50 | | recovery | `address` | Recovery address for the new fid |
51 | | deadline | `uint256` | Signature expiration timestamp |
52 | | sig | `bytes` | EIP-712 `Register` signature from the `to` address |
53 | | extraStorage | `uint256` (optional) | Additional storage units |
54 |
55 | #### Register signature
56 |
57 | To register an fid on behalf of another account, you must provide an EIP-712 typed signature from the receiving address in the following format:
58 |
59 | `Register(address to,address recovery,uint256 nonce,uint256 deadline)`
60 |
61 | | Parameter | type | Description |
62 | | --------- | --------- | --------------------------------------------------------------------------------- |
63 | | to | `address` | Address to register the fid to. The typed message must be signed by this address. |
64 | | recovery | `address` | Recovery address for the new fid |
65 | | nonce | `uint256` | Current nonce of the `to` address |
66 | | deadline | `uint256` | Signature expiration timestamp |
67 |
68 | ::: code-group
69 |
70 | ```ts [@farcaster/hub-web]
71 | import { ViemWalletEip712Signer } from '@farcaster/hub-web';
72 | import { walletClient, account } from './clients.ts';
73 | import { readNonce, getDeadline } from './helpers.ts';
74 |
75 | const nonce = await readNonce();
76 | const deadline = getDeadline();
77 |
78 | const eip712Signer = new ViemWalletEip712Signer(walletClient);
79 | const signature = await eip712signer.signRegister({
80 | to: account,
81 | recovery: '0x00000000FcB080a4D6c39a9354dA9EB9bC104cd7',
82 | nonce,
83 | deadline,
84 | });
85 | ```
86 |
87 | ```ts [Viem]
88 | import { ID_GATEWAY_EIP_712_TYPES } from '@farcaster/hub-web';
89 | import { walletClient, account } from './clients.ts';
90 | import { readNonce, getDeadline } from './helpers.ts';
91 |
92 | const nonce = await readNonce();
93 | const deadline = getDeadline();
94 |
95 | const signature = await walletClient.signTypedData({
96 | account,
97 | ...ID_GATEWAY_EIP_712_TYPES,
98 | primaryType: 'Register',
99 | message: {
100 | to: account,
101 | recovery: '0x00000000FcB080a4D6c39a9354dA9EB9bC104cd7',
102 | nonce,
103 | deadline,
104 | },
105 | });
106 | ```
107 |
108 | ```ts [helpers.ts]
109 | import { ID_GATEWAY_ADDRESS, idGatewayABI } from '@farcaster/hub-web';
110 | import { publicClient, account } from './clients.ts';
111 |
112 | export const getDeadline = () => {
113 | const now = Math.floor(Date.now() / 1000);
114 | const oneHour = 60 * 60;
115 | return now + oneHour;
116 | };
117 |
118 | export const readNonce = async () => {
119 | return await publicClient.readContract({
120 | address: ID_GATEWAY_ADDRESS,
121 | abi: idGatewayABI,
122 | functionName: 'nonces',
123 | args: [account],
124 | });
125 | };
126 | ```
127 |
128 | <<< @/examples/contracts/clients.ts
129 |
130 | :::
131 |
132 | ## Errors
133 |
134 | | Error | Selector | Description |
135 | | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
136 | | InvalidSignature | `8baa579f` | The provided signature is invalid. It may be incorrectly formatted, or signed by the wrong address. |
137 | | SignatureExpired | `0819bdcd` | The provided signature has expired. Collect a new signature from the signer with a later deadline timestamp. |
138 |
139 | ## Source
140 |
141 | [`IdGateway.sol`](https://github.com/farcasterxyz/contracts/blob/1aceebe916de446f69b98ba1745a42f071785730/src/IdGateway.sol)
142 |
--------------------------------------------------------------------------------
/docs/reference/contracts/reference/key-registry.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: [2, 3]
3 | ---
4 |
5 | # Key Registry
6 |
7 | The Key Registry stores the public keys associated with each Farcaster account.
8 |
9 | If you want to read information about a Farcaster account's keys or remove an existing key, use the Key Registry.
10 |
11 | If you want to add a new key, use the [Key Gateway](/reference/contracts/reference/key-gateway.md) instead.
12 |
13 | ## Read
14 |
15 | ### totalKeys
16 |
17 | Get the number of active keys (`uint256`) for an fid.
18 |
19 | | Parameter | type | Description |
20 | | --------- | ------------------------------------ | ----------------------------------- |
21 | | fid | `uint256` | fid to look up |
22 | | state | `uint8` (1 for Added, 2 for Removed) | State of the key (added or removed) |
23 |
24 | ### keysOf
25 |
26 | List all public keys (`bytes[]`) for an fid.
27 |
28 | | Parameter | type | Description |
29 | | --------- | ------------------------------------ | ----------------------------------- |
30 | | fid | `uint256` | fid to look up |
31 | | state | `uint8` (1 for Added, 2 for Removed) | State of the key (added or removed) |
32 | | startIdx | `uint256` (optional) | Start index for pagination |
33 | | batchSize | `uint256` (optional) | Batch size for pagination |
34 |
35 | ::: warning
36 | Don't call this onchain! This function is very gas intensive. It's meant to be called by offchain tools, not by other contracts.
37 | :::
38 |
39 | ### keyDataOf
40 |
41 | Returns the state (`uint8`) and keyType (`uint32`) of particular key for an fid.
42 |
43 | | Parameter | type | Description |
44 | | --------- | --------- | ------------------- |
45 | | fid | `uint256` | fid to look up |
46 | | key | `bytes` | public key to check |
47 |
48 | ## Write
49 |
50 | ### add
51 |
52 | Will revert if called directly. Must be called via the [Key Gateway](/reference/contracts/reference/key-gateway.md)
53 |
54 | ### remove
55 |
56 | Removes a public key from the caller's fid and marks it as `Removed`.
57 |
58 | | Parameter | type | Description |
59 | | --------- | ------- | -------------------- |
60 | | key | `bytes` | public key to remove |
61 |
62 | ::: warning
63 | Removing a key will delete all offchain messages associated with the key from Hubs.
64 | :::
65 |
66 | ### removeFor
67 |
68 | Remove a key on behalf of another fid by providing a signature. The fid owner must sign an EIP-712 `Remove` message approving the removal. Reverts if the key does not exist or is already removed.
69 |
70 | | Parameter | type | Description |
71 | | --------- | --------- | ------------------------------------- |
72 | | fidOwner | `address` | fid owner address |
73 | | key | `bytes` | public key to remove |
74 | | deadline | `uint256` | signature deadline |
75 | | sig | `bytes` | EIP-712 signature from the `fidOwner` |
76 |
77 | ::: warning
78 | Removing a key will delete all offchain messages associated with the key from Hubs.
79 | :::
80 |
81 | #### Remove signature
82 |
83 | To remove a key on behalf of another account, you must provide an EIP-712 typed signature from the account in the following format:
84 |
85 | `Remove(address owner,bytes key,uint256 nonce,uint256 deadline)`
86 |
87 | | Parameter | type | Description |
88 | | --------- | --------- | ---------------------------------------------------------------------------- |
89 | | owner | `address` | Address that owns the fid. The typed message must be signed by this address. |
90 | | key | `bytes` | The public key to remove |
91 | | nonce | `uint256` | Current nonce of the `owner` address |
92 | | deadline | `uint256` | Signature expiration timestamp |
93 |
94 | ::: code-group
95 |
96 | ```ts [@farcaster/hub-web]
97 | import { ViemWalletEip712Signer } from '@farcaster/hub-web';
98 | import { walletClient, account } from './clients.ts';
99 | import { getPublicKey } from './signer.ts';
100 | import { readNonce, getDeadline } from './helpers.ts';
101 |
102 | const publicKey = await getPublicKey();
103 | const nonce = await readNonce();
104 | const deadline = getDeadline();
105 |
106 | const eip712Signer = new ViemWalletEip712Signer(walletClient);
107 | const signature = await eip712signer.signRemove({
108 | owner: account,
109 | key: publicKey,
110 | nonce,
111 | deadline,
112 | });
113 | ```
114 |
115 | ```ts [Viem]
116 | import { KEY_REGISTRY_EIP_712_TYPES } from '@farcaster/hub-web';
117 | import { bytesToHex } from 'viem';
118 | import { walletClient, account } from './clients.ts';
119 | import { getPublicKey } from './signer.ts';
120 | import { readNonce, getDeadline } from './helpers.ts';
121 |
122 | const publicKey = await getPublicKey();
123 | const nonce = await readNonce();
124 | const deadline = getDeadline();
125 |
126 | const signature = await walletClient.signTypedData({
127 | account,
128 | ...KEY_REGISTRY_EIP_712_TYPES,
129 | primaryType: 'Remove',
130 | message: {
131 | owner: account,
132 | key: bytesToHex(publicKey),
133 | nonce,
134 | deadline,
135 | },
136 | });
137 | ```
138 |
139 | ```ts [helpers.ts]
140 | import { KEY_REGISTRY_ADDRESS, keyRegistryABI } from '@farcaster/hub-web';
141 | import { publicClient, account } from './clients.ts';
142 |
143 | export const getDeadline = () => {
144 | const now = Math.floor(Date.now() / 1000);
145 | const oneHour = 60 * 60;
146 | return now + oneHour;
147 | };
148 |
149 | export const readNonce = async () => {
150 | return await publicClient.readContract({
151 | address: KEY_REGISTRY_ADDRESS,
152 | abi: keyRegistryABI,
153 | functionName: 'nonces',
154 | args: [account],
155 | });
156 | };
157 | ```
158 |
159 | <<< @/examples/contracts/signer.ts
160 |
161 | <<< @/examples/contracts/clients.ts
162 |
163 | :::
164 |
165 | ## Errors
166 |
167 | | Error | Selector | Description |
168 | | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
169 | | ExceedsMaximum | `29264042` | Adding the key exceeds the maximum number of keys allowed per fid (currently 1000) |
170 | | InvalidSignature | `8baa579f` | The provided signature is invalid. It may be incorrectly formatted, or signed by the wrong address. |
171 | | InvalidState | `baf3f0f7` | The action violates state transition rules. (Adding a key that already exists, removing a key that does not exist, adding a key that has been removed) |
172 | | SignatureExpired | `0819bdcd` | The provided signature has expired. Collect a new signature from the signer with a later deadline timestamp. |
173 |
174 | ## Source
175 |
176 | [`KeyRegistry.sol`](https://github.com/farcasterxyz/contracts/blob/1aceebe916de446f69b98ba1745a42f071785730/src/KeyRegistry.sol)
177 |
--------------------------------------------------------------------------------
/docs/reference/contracts/reference/storage-registry.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: [2, 3]
3 | ---
4 |
5 | # Storage Registry
6 |
7 | The Storage Registry allows Farcaster accounts to rent one or more "units" of storage on the network.
8 |
9 | If you want to rent storage for a Farcaster account, use the Storage Registry.
10 |
11 | ## Read
12 |
13 | ### unitPrice
14 |
15 | Get the price in wei (`uint256`) to register 1 unit of storage.
16 |
17 | ### price
18 |
19 | Get the price in wei (`uint256`) to register a specific number of storage units.
20 |
21 | | Param Name | type | Description |
22 | | ---------- | --------- | ----------------------------------- |
23 | | units | `uint256` | The number of storage units to rent |
24 |
25 | ## Write
26 |
27 | ### rent
28 |
29 | Rent a specific number of storage units for a given fid. Excess ether will be returned to the caller. Rented units are valid for 1 year from the time of registration.
30 |
31 | | Param Name | type | Description |
32 | | ----------- | --------- | -------------------------------------- |
33 | | `msg.value` | `wei` | Payment amount |
34 | | fid | `uint256` | The fid to credit the storage units to |
35 | | units | `uint256` | The number of units of storage to rent |
36 |
37 | ### batchRent
38 |
39 | Rent storage for multiple fids in one transaction. The caller must send enough ether to cover the total cost of all units. Like single-unit rental, extra ether is returned and units are valid for 1 year.
40 |
41 | | Param Name | type | Description |
42 | | ----------- | ----------- | ----------------------------------------------------------------------- |
43 | | `msg.value` | `wei` | Total payment amount |
44 | | fids | `uint256[]` | Array of fids |
45 | | units | `uint256[]` | Array of unit quantities, corresponding to each fid in the `fids` array |
46 |
47 | ## Errors
48 |
49 | | Error | Selector | Description |
50 | | ----------------- | ---------- | ---------------------------------------------------------------------------------------- |
51 | | InvalidPayment | `3c6b4b28` | The caller didn't provide enough ether to pay for the number of storage units requested. |
52 | | InvalidBatchInput | `0a514b99` | The caller provided mismatched arrays of `fids` and `units`. |
53 |
54 | ## Source
55 |
56 | [`StorageRegistry.sol`](https://github.com/farcasterxyz/contracts/blob/1aceebe916de446f69b98ba1745a42f071785730/src/validators/StorageRegistry.sol)
57 |
--------------------------------------------------------------------------------
/docs/reference/contracts/reference/tier-registry.md:
--------------------------------------------------------------------------------
1 | ---
2 | outline: [2, 3]
3 | ---
4 |
5 | # Tier Registry
6 |
7 | The Tier Registry allows Farcaster accounts to purchase or extend Farcaster Pro subscriptions.
8 |
9 | Unlike other protocol contracts, the Tier Registry is deployed on Base Mainnet.
10 |
11 | If you want to purchase a Pro subscription for a Farcaster account, use the Tier Registry.
12 |
13 | ## Active Tiers
14 |
15 | | Tier ID | Description | Payment Token | Min Days | Price/day |
16 | | ------- | ------------- | ------------- | -------- | ----------------- |
17 | | 1 | Farcaster Pro | USDC | 30 | `328767` wei USDC |
18 |
19 | ## Read
20 |
21 | ### price
22 |
23 | Get the total price in payment token (`uint256`) to purchase a tier subscription for a given number of days.
24 |
25 | | Param Name | type | Description |
26 | | ---------- | --------- | ----------------------------------------- |
27 | | tier | `uint256` | The tier ID to calculate price for |
28 | | forDays | `uint256` | The number of days to calculate price for |
29 |
30 | ### tierInfo
31 |
32 | Get information about a specific tier. Returns a `TierInfo` struct.
33 |
34 | | Param Name | type | Description |
35 | | ---------- | --------- | ----------- |
36 | | tier | `uint256` | The tier ID |
37 |
38 | `TierInfo` struct parameters:
39 |
40 | | Param Name | type | Description |
41 | | ---------------- | --------- | ---------------------------------------------------- |
42 | | minDays | `uint256` | Minimum number of days required to purchase |
43 | | maxDays | `uint256` | Maximum number of days per purchase |
44 | | vault | `address` | Payment destination address |
45 | | paymentToken | `IERC20` | ERC20 payment token |
46 | | tokenPricePerDay | `uint256` | Price per day in fundamental units of `paymentToken` |
47 | | isActive | `bool` | Whether tier is currently active |
48 |
49 | ## Write
50 |
51 | ### purchaseTier
52 |
53 | Purchase a subscription tier for a given fid. If the account already has an active subscription, purchasing will extend
54 | their total subscription time.
55 |
56 | | Param Name | type | Description |
57 | | ---------- | --------- | ----------------------------------------- |
58 | | fid | `uint256` | The fid to credit the subscription to |
59 | | tier | `uint256` | The tier ID to calculate price for |
60 | | forDays | `uint256` | The number of days to calculate price for |
61 |
62 | ### batchRent
63 |
64 | Rent storage for multiple fids in one transaction. The caller must send enough ether to cover the total cost of all units. Like single-unit rental, extra ether is returned and units are valid for 1 year.
65 |
66 | | Param Name | type | Description |
67 | | ----------- | ----------- | ----------------------------------------------------------------------- |
68 | | `msg.value` | `wei` | Total payment amount |
69 | | fids | `uint256[]` | Array of fids |
70 | | forDays | `uint256[]` | Array of unit quantities, corresponding to each fid in the `fids` array |
71 |
72 | ### batchPurchaseTier
73 |
74 | Purchase a subscription tier for multiple fids in a single transaction. If an account already has an active subscription, purchasing will extend
75 | their total subscription time.
76 |
77 | | Param Name | type | Description |
78 | | ---------- | ----------- | ------------------------------------------------------------ |
79 | | tier | `uint256` | The tier ID to calculate price for |
80 | | fids | `uint256[]` | Array of fids |
81 | | forDays | `uint256[]` | Array of days, corresponding to each fid in the `fids` array |
82 |
83 | ## Events
84 |
85 | ### PurchasedTier
86 |
87 | Emitted when a tier is purchased for a Farcaster account.
88 |
89 | | Param Name | type | Description |
90 | | ---------- | ----------------- | ---------------------------------------- |
91 | | fid | `uint256 indexed` | Farcaster ID the tier was purchased for |
92 | | tier | `uint256 indexed` | Tier ID that was purchased |
93 | | forDays | `uint256` | Number of days of subscription purchased |
94 | | payer | `address indexed` | Caller address that paid |
95 |
96 | ## Errors
97 |
98 | | Error | Selector | Description |
99 | | ----------------- | ---------- | -------------------------------------------------------------- |
100 | | InvalidDuration | `76166401` | The caller attempted to purchase an invalid number of days. |
101 | | InvalidTier | `e1423617` | The caller attempted to purchase an invalid or inactive tier. |
102 | | InvalidBatchInput | `0a514b99` | The caller provided mismatched arrays of `fids` and `forDays`. |
103 |
104 | ## Source
105 |
106 | [`TierRegistry.sol`](https://github.com/farcasterxyz/contracts/blob/d0af1b8148db713239f6ac19465efeadb713b58c/src/TierRegistry.sol)
107 |
--------------------------------------------------------------------------------
/docs/reference/fname/api.md:
--------------------------------------------------------------------------------
1 | # FName Registry Server API Reference
2 |
3 | The [Fname registry](https://github.com/farcasterxyz/fname-registry) server is hosted at https://fnames.farcaster.xyz
4 |
5 | It's a simple HTTP service that's responsible for issuing and tracking fnames. All Fname changes are recorded as a
6 | transfer.
7 | Registering an fname is a transfer from FID 0 to the user's fid. Transferring an fname is a transfer from the user's fid
8 | to another fid. Unregistering an fname is a transfer from the user's fid to fid 0.
9 |
10 | ::: warning Registering an fname
11 |
12 | Note, when registering a new fname, calling this api is not sufficient. This only reserves the name to your fid. You
13 | must also submit a [UserDataAdd](https://snapchain.farcaster.xyz/reference/datatypes/messages#2-userdata) message to the hub
14 | to set this name as your username.
15 |
16 | :::
17 |
18 | ### Get Transfer History
19 |
20 | To get a history of all transfers, make a GET request to `/transfers`
21 |
22 | ```bash
23 | curl https://fnames.farcaster.xyz/transfers | jq
24 | ```
25 |
26 | It also accepts the following query parameters:
27 |
28 | - `from_id` - The transfer id to start from for pagination
29 | - `name` - The fname to filter by
30 | - `fid` - The fid (either from or to) to filter by
31 | - `from_ts` - The timestamp (in seconds) to start from for pagination
32 |
33 | ### Get current fname or fid
34 |
35 | To get the most recent transfer event for an fid or fname, make a GET request to `/transfers/current`
36 |
37 | e.g. To determine the fid of `@farcaster`, make the following call and use the value from the `to` field in the return
38 | value
39 |
40 | ```bash
41 | curl https://fnames.farcaster.xyz/transfers?name=farcaster | jq
42 | ```
43 |
44 | To determine the fname of fid `1`, make the following call and use the value from the `username` field in the return
45 | value
46 |
47 | ```bash
48 | curl https://fnames.farcaster.xyz/transfers?fid=1 | jq
49 | ```
50 |
51 | Both will return the same transfers object:
52 |
53 | ```json
54 | {
55 | "transfers": [
56 | {
57 | "id": 1,
58 | "timestamp": 1628882891,
59 | "username": "farcaster",
60 | "owner": "0x8773442740c17c9d0f0b87022c722f9a136206ed",
61 | "from": 0,
62 | "to": 1,
63 | "user_signature": "0xa6fdd2a69deab5633636f32a30a54b21b27dff123e6481532746eadca18cd84048488a98ca4aaf90f4d29b7e181c4540b360ba0721b928e50ffcd495734ef8471b",
64 | "server_signature": "0xb7181760f14eda0028e0b647ff15f45235526ced3b4ae07fcce06141b73d32960d3253776e62f761363fb8137087192047763f4af838950a96f3885f3c2289c41b"
65 | }
66 | ]
67 | }
68 | ```
69 |
70 | ### Register or transfer an fname
71 |
72 | To register a new fid, e.g. `farcaster`, first make sure the fname is not already registered.
73 |
74 | Then make a POST request to `/transfers` with the following body:
75 |
76 | ```yaml
77 | {
78 | "name": "farcaster", // Name to register
79 | "from": 0, // Fid to transfer from (0 for a new registration)
80 | "to": 123, // Fid to transfer to (0 to unregister)
81 | "fid": 123, // Fid making the request (must match from or to)
82 | "owner": "0x...", // Custody address of fid making the request
83 | "timestamp": 1641234567, // Current timestamp in seconds
84 | "signature": "0x..." // EIP-712 signature signed by the custody address of the fid
85 | }
86 | ```
87 |
88 | To generate the EIP-712 signature, use the following code:
89 |
90 | ```js
91 | import { makeUserNameProofClaim, EIP712Signer } from '@farcaster/hub-nodejs';
92 |
93 | const accountKey: EIP712Signer = undefined; // Account key for the custody address (use appropriate subclass from hub-nodejs for ethers or viem)
94 |
95 | const claim = makeUserNameProofClaim({
96 | name: 'farcaster',
97 | owner: '0x...',
98 | timestamp: Math.floor(Date.now() / 1000),
99 | });
100 | const signature = (
101 | await accountKey.signUserNameProofClaim(claim)
102 | )._unsafeUnwrap();
103 | ```
104 |
105 | This is the exact same kind of signature used in the ENS UsernameProofs provided to hubs to prove ownership of an ENS
106 | name.
107 |
108 | e.g.
109 |
110 | ```bash
111 | curl -X POST https://fnames.farcaster.xyz/transfers \
112 | -H "Content-Type: application/json" \
113 | -d \
114 | '{"name": "farcaster", "owner": "0x...", "signature": "0x...", "from": 0, "to": 1000, "timestamp": 1641234567, fid: 1000}'
115 | ```
116 |
117 | Once a name is registered, it still needs a [UserData](https://snapchain.farcaster.xyz/reference/datatypes/messages#2-userdata) message
118 | to be sent to the hub in order to actually
119 | set the username for the user. See examples in
120 | the [hub-nodejs](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/hub-nodejs/examples/hello-world) repo.
121 |
--------------------------------------------------------------------------------
/docs/reference/frames-redirect.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Frames v2 have been rebranded to Mini Apps
3 | ---
4 |
5 | # Frames v2 have been rebranded to Mini Apps
6 |
7 |
8 | As of early 2025, Frames v2 have been rebranded to Mini Apps. All Frames documentation and resources have been migrated to the [Mini Apps](https://miniapps.farcaster.xyz/){target="_self"} ecosystem.
9 |
10 | Frames v2 have been deprecated and will be supported only until the end of March 2025. We strongly recommend using Mini Apps for all new projects.
11 |
12 |
13 | [Go to Mini Apps Documentation →](https://miniapps.farcaster.xyz/){target="_self"}
14 |
--------------------------------------------------------------------------------
/docs/reference/index.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | The reference sections documents API's, standards and protocols used commonly used by Farcaster developers.
4 |
5 |
6 | - [Mini Apps](https://miniapps.farcaster.xyz){target="_self"}- A specification for writing and rendering mini apps.
7 | - [Farcaster Client APIs](/reference/warpcast/api) - An overview of Farcaster Client APIs that are publicly available.
8 | - [Snapchain](https://snapchain.farcaster.xyz/) - A design overview and API reference for Farcaster Hubs.
9 | - [Replicator](/reference/replicator/schema) - An overview and schema for the replicator.
10 | - [Contracts](/reference/contracts/index) - A design overview and ABI reference for Farcaster contracts.
11 | - [FName Registry](/reference/fname/api) - An overview and API reference for the Farcaster Name Server.
12 | - [Neynar](/reference/third-party/neynar/index) - An overview of Neynar APIs that can help developers get started with Farcaster
13 |
--------------------------------------------------------------------------------
/docs/reference/third-party/neynar/index.md:
--------------------------------------------------------------------------------
1 | # Neynar
2 |
3 | [Neynar](https://neynar.com) is an independent 3rd party provider that offers the following services for Farcaster data:
4 |
5 | - [Hosted hubs](https://docs.neynar.com/docs/create-a-stream-of-casts)
6 | - [REST APIs](https://docs.neynar.com/reference/quickstart)
7 | - [Signer management](https://docs.neynar.com/docs/which-signer-should-you-use-and-why)
8 | - [New account creation](https://docs.neynar.com/docs/how-to-create-a-new-farcaster-account-with-neynar)
9 | - [Webhooks](https://docs.neynar.com/docs/how-to-create-webhooks-on-the-go-using-the-sdk)
10 | - [Data ingestion pipelines](https://docs.neynar.com/docs/how-to-choose-the-right-data-product-for-you)
11 |
12 | 🪐
13 |
--------------------------------------------------------------------------------
/docs/reference/warpcast/cast-composer-intents.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Warpcast Intents URLs
3 | ---
4 |
5 | # Intents URLs
6 |
7 | ## Cast Intent URLs
8 |
9 | Warpcast intents enable builders to direct authenticated users to a pre-filled cast composer.
10 |
11 | > [!IMPORTANT]
12 | > If you're building a Mini App and want to prompt the user to compose a cast, use the [composeCast action](https://miniapps.farcaster.xyz/docs/sdk/actions/compose-cast)
13 | > from the Mini App SDK.
14 |
15 | #### Compose with cast text
16 |
17 | ```
18 | https://warpcast.com/~/compose?text=Hello%20world!
19 | ```
20 |
21 | #### Compose with cast text and one embed
22 |
23 | ```
24 | https://warpcast.com/~/compose?text=Hello%20world!&embeds[]=https://farcaster.xyz
25 | ```
26 |
27 | #### Compose with cast text with mentions and two embeds
28 |
29 | ```
30 | https://warpcast.com/~/compose?text=Hello%20@farcaster!&embeds[]=https://farcaster.xyz&embeds[]=https://github.com/farcasterxyz/protocol
31 | ```
32 |
33 | #### Compose with cast text on a specific channel
34 |
35 | ```
36 | https://warpcast.com/~/compose?text=Hello%20world!&channelKey=farcaster
37 | ```
38 |
39 | #### Reply with cast text to a cast with hash
40 |
41 | ```
42 | https://warpcast.com/~/compose?text=Looks%20good!&parentCastHash=0x09455067393562d3296bcbc2ec1c2d6bba8ac1f1
43 | ```
44 |
45 | #### Additional details
46 |
47 | - Embeds are any valid URLs
48 | - URLs ending with `.png` `.jpg` or `.gif` will render as an image embed
49 | - Embedding the URL to a Zora mint page will render the NFT with a mint link below it.
50 | - You can check how embeds will be rendered in Warpcast at https://warpcast.com/~/developers/embeds
51 |
52 | ## Resource URLs
53 |
54 | #### View profile by FID
55 |
56 | ```
57 | https://warpcast.com/~/profiles/:fid
58 | ```
59 |
60 | #### View cast by hash
61 |
62 | ```
63 | https://warpcast.com/~/conversations/:hash
64 | ```
65 |
--------------------------------------------------------------------------------
/docs/reference/warpcast/direct-casts.md:
--------------------------------------------------------------------------------
1 | # Direct Casts
2 |
3 | This page documents public APIs provided by the official Farcaster client for direct casts. Direct casts are currently not part of the protocol. There are plans to add direct casts to the protocol later this year.
4 |
5 | #### Send / write API for direct casts
6 |
7 | - [Send direct casts via API](https://www.notion.so/warpcast/Public-Programmable-DCs-v1-50d9d99e34ac4d10add55bd26a91804f)
8 | - The above link also provides information on how to obtain direct cast API keys
9 |
10 | #### Direct cast intents
11 |
12 | Intents enable developers to direct authenticated users to a pre-filled direct cast composer via a URL.
13 |
14 | ```bash
15 | https://farcaster.xyz/~/inbox/create/[fid]?text=[message]
16 |
17 | https://farcaster.xyz/~/inbox/create/1?text=gm
18 | ```
19 |
--------------------------------------------------------------------------------
/docs/reference/warpcast/embeds.md:
--------------------------------------------------------------------------------
1 | # Farcaster Client Embeds Reference
2 |
3 | The Farcaster client follows the [Open Graph protocol](https://ogp.me) when rendering rich previews for URL embeds.
4 |
5 | Developers can reset existing embed caches on the Farcaster client at https://farcaster.xyz/~/developers/embeds.
6 |
7 | #### Additional details
8 |
9 | - Resetting an embed cache, does not reset Open Graph image caches. If you are experiencing a stale image on your Open Graph, change the image file path served as the `og:image`.
10 | - Developers have to be logged in to the Farcaster client to access this page.
11 | - To render rich previews of NFTs, follow the [Farcaster Frames spec](/developers/frames/spec).
12 |
--------------------------------------------------------------------------------
/docs/reference/warpcast/videos.md:
--------------------------------------------------------------------------------
1 | # How to have your video displayed on the Farcaster client
2 |
3 | 1. Ensure you serve your video as a streamable `.m3u8` file. This ensures clients only download what they need when viewing, and nothing more, providing a high performance experience.
4 |
5 | 2. Make sure that `.m3u8` manifest exposes the resolution(s) for your video. The Farcaster client uses this to determine the correct aspect ratio when rendering. A manifest file with resolution data looks something like:
6 |
7 | ```
8 | #EXTM3U
9 | #EXT-X-VERSION:3
10 |
11 | #EXT-X-STREAM-INF:BANDWIDTH=2444200,CODECS="avc1.64001f,mp4a.40.2",RESOLUTION=474x842
12 | 480p/video.m3u8
13 | #EXT-X-STREAM-INF:BANDWIDTH=4747600,CODECS="avc1.640020,mp4a.40.2",RESOLUTION=720x1280
14 | 720p/video.m3u8
15 | ```
16 |
17 | 3. Ensure that at cast publish time the `.m3u8` file is available. The Farcaster client checks once and if there is no valid data, the cast will show no video.
18 |
19 | 4. Have the same URL when changed from ending in `/my-video.m3u8` to `/thumbnail.jpg` with a preview/thumbnail image to render before the user has interacted with the video.
20 |
21 | 5. Reach out to the Farcaster team and ask for us to enable videos for your domain. Tell us the format of your video URLs and we’ll configure our scrapers to display them correctly in the feed. Please make sure to complete all these steps above before reaching out for allowlisting. [Ping @gt on Farcaster](https://farcaster.xyz/~/inbox/create/302?text=Completed%20video%20setup).
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "www-farcaster-xyz",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "UNLICENSED",
6 | "devDependencies": {
7 | "husky": "^8.0.3",
8 | "lint-staged": "^15.2.0",
9 | "prettier": "^2.8.7",
10 | "vitepress": "^1.3.1"
11 | },
12 | "scripts": {
13 | "docs:dev": "vitepress dev docs",
14 | "docs:build": "vitepress build docs",
15 | "docs:preview": "vitepress preview docs",
16 | "lint": "prettier --config \"./.prettierrc.yml\" --write \"**/*.{json,md}\"",
17 | "lint:check": "prettier --config \"./.prettierrc.yml\" --check \"**/*.{json,md}\"",
18 | "postinstall": "husky install"
19 | },
20 | "lint-staged": {
21 | "*.md": "prettier --config \"./.prettierrc.yml\" --write \"**/*.{json,md}\""
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "cleanUrls": true,
3 | "redirects": [
4 | {
5 | "source": "/developers/frames/v2",
6 | "destination": "https://miniapps.farcaster.xyz/",
7 | "permanent": true
8 | },
9 | {
10 | "source": "/developers/frames/v2/",
11 | "destination": "https://miniapps.farcaster.xyz/",
12 | "permanent": true
13 | },
14 | {
15 | "source": "/developers/frames/v2/getting-started",
16 | "destination": "https://miniapps.farcaster.xyz/docs/getting-started",
17 | "permanent": true
18 | },
19 | {
20 | "source": "/developers/frames/v2/spec",
21 | "destination": "https://miniapps.farcaster.xyz/docs/specification",
22 | "permanent": true
23 | },
24 | {
25 | "source": "/developers/frames/v2/index",
26 | "destination": "https://miniapps.farcaster.xyz/",
27 | "permanent": true
28 | },
29 | {
30 | "source": "/developers/frames/v2/resources",
31 | "destination": "https://miniapps.farcaster.xyz/docs/specification",
32 | "permanent": true
33 | },
34 | {
35 | "source": "/developers/frames/v2/notifications_webhooks",
36 | "destination": "https://miniapps.farcaster.xyz/docs/guides/notifications",
37 | "permanent": true
38 | },
39 | {
40 | "source": "/auth-kit/introduction",
41 | "destination": "/auth-kit/",
42 | "permanent": true
43 | },
44 | {
45 | "source": "/docs/developers/frames",
46 | "destination": "https://miniapps.farcaster.xyz",
47 | "permanent": true
48 | },
49 | {
50 | "source": "/developers/frames/v2/getting-started",
51 | "destination": "https://miniapps.farcaster.xyz/docs/getting-started",
52 | "permanent": true
53 | },
54 | {
55 | "source": "/developers/frames/v2/notifications_webhooks",
56 | "destination": "https://miniapps.farcaster.xyz/docs/guides/notifications",
57 | "permanent": true
58 | },
59 | {
60 | "source": "/developers/frames/v2/spec",
61 | "destination": "https://miniapps.farcaster.xyz/docs/specification",
62 | "permanent": true
63 | },
64 | {
65 | "source": "/auth-kit/introduction",
66 | "destination": "/auth-kit/",
67 | "permanent": true
68 | },
69 | {
70 | "source": "/docs/developers/frames",
71 | "destination": "https://miniapps.farcaster.xyz",
72 | "permanent": true
73 | },
74 | {
75 | "source": "/docs/developers/frames/",
76 | "destination": "https://miniapps.farcaster.xyz",
77 | "permanent": true
78 | },
79 | {
80 | "source": "/developers/frames/v2/getting-started",
81 | "destination": "https://miniapps.farcaster.xyz/docs/getting-started",
82 | "permanent": true
83 | },
84 | {
85 | "source": "/developers/frames/v2/notifications_webhooks",
86 | "destination": "https://miniapps.farcaster.xyz/docs/guides/notifications",
87 | "permanent": true
88 | },
89 | {
90 | "source": "/developers/frames/v2/spec",
91 | "destination": "https://miniapps.farcaster.xyz/docs/specification",
92 | "permanent": true
93 | },
94 | {
95 | "source": "/reference/frames/spec",
96 | "destination": "https://miniapps.farcaster.xyz/docs/specification",
97 | "permanent": true
98 | }
99 | ]
100 | }
101 |
--------------------------------------------------------------------------------