├── .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 | [![NPM Version](https://img.shields.io/npm/v/@farcaster/auth-client)](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 | 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 | ![Sign In with Farcaste demo](./siwf_demo.avifs) 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 | ![Registry Contracts](/assets/registry-contracts.png) 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 | ![Usernames](/assets/usernames.png) 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 | ![Architecture](/assets/architecture.png) 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 | ![Usernames](/assets/usernames.png) 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 | ![contracts.png](/assets/contracts.png) 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 | --------------------------------------------------------------------------------