{"id":13767527,"url":"https://github.com/pavlovdog/farcaster-solidity","last_synced_at":"2025-06-14T13:04:25.294Z","repository":{"id":219352215,"uuid":"734285924","full_name":"pavlovdog/farcaster-solidity","owner":"pavlovdog","description":"A collection of Solidity libraries for interacting with the Farcaster messages on-chain","archived":false,"fork":false,"pushed_at":"2024-04-04T17:04:41.000Z","size":473,"stargazers_count":93,"open_issues_count":2,"forks_count":19,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-06-14T01:06:09.445Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Solidity","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pavlovdog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-21T10:03:50.000Z","updated_at":"2025-06-06T08:01:56.000Z","dependencies_parsed_at":"2024-01-26T22:23:47.116Z","dependency_job_id":"dec16507-9ee1-4848-81c7-6b83ee42d3db","html_url":"https://github.com/pavlovdog/farcaster-solidity","commit_stats":null,"previous_names":["pavlovdog/farcaster-solidity"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pavlovdog/farcaster-solidity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlovdog%2Ffarcaster-solidity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlovdog%2Ffarcaster-solidity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlovdog%2Ffarcaster-solidity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlovdog%2Ffarcaster-solidity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pavlovdog","download_url":"https://codeload.github.com/pavlovdog/farcaster-solidity/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavlovdog%2Ffarcaster-solidity/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259820794,"owners_count":22916546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T16:01:09.439Z","updated_at":"2025-06-14T13:04:25.266Z","avatar_url":"https://github.com/pavlovdog.png","language":"Solidity","funding_links":[],"categories":["Developer Resources","Uncategorized"],"sub_categories":["Repos","Uncategorized"],"readme":"# Farcaster Solidity\n\nA set of Solidity libraries for verifying and parsing Farcaster messages onchain. Made by [fastfourier.eth](https://warpcast.com/fastfourier.eth).\n\n## Introduction\n\nThe difference between a Farcaster and many other social networks is the cryptographic protocol that allows any user to verify any action, that happened on the network. Using cryptographic signatures and an onchain key registry, it is possible to verify the correctness of the cast, like, the following relation, etc.\n\nThe goal of this project is to provide a set of Solidity libraries and examples, helping to verify and parse Farcaster messages on-chain.\n\n## Overview\n\nFarcaster messages (cast, like, following, etc) are represented as Protobuf messages, signed with the user's private key. Here's an illustration of what happens when a new cast is sent to the Farcaster network:\n\n1. Alice publishes a cast. Application (eg Warpcast) forms a message from text, mentions, links, etc\n2. The message is encoded using the Protobuf scheme into a series of bytes. Then it gets hashed using the Blake3 hash function, and the first 20 bytes of the hash are signed with the user's Ed25519 private key. The corresponding public key is stored in a smart contract called `KeyRegistry` on Optimism Mainnet.\n3. The message and the signature, are being sent to the network\n4. Each network participant verifies, that the signature is correct and accepts the message as valid.\n\nAll these actions can be done inside the smart contract, verifying that Alice indeed sent the message!\n\n## Usage example\n\nThe full example can be found at [contracts/Test.sol](./contracts/Test.sol).\n\n```solidity\nfunction verifyCastAddMessage(\n  bytes32 public_key,\n  bytes32 signature_r,\n  bytes32 signature_s,\n  bytes memory message\n) external {\n  MessageData memory message_data = _verifyMessage(\n    public_key,\n    signature_r,\n    signature_s,\n    message\n  );\n\n  if (message_data.type_ != MessageType.MESSAGE_TYPE_CAST_ADD) {\n    revert InvalidMessageType();\n  }\n\n  emit MessageCastAddVerified(\n    message_data.fid,\n    message_data.cast_add_body.text,\n    message_data.cast_add_body.mentions\n  );\n}\n```\n\n## Gas usage\n\nGas usage mainly consists of three components:\n\n- Blake3 hashing (500k - 1m gas)\n- Ed25519 signature verification (≈ 1m gas)\n- Message decoding (≈ 100k gas)\n\n```\n·-----------------------------------------|----------------------------|-------------|-----------------------------·\n|          Solc version: 0.8.19           ·  Optimizer enabled: false  ·  Runs: 200  ·  Block limit: 30000000 gas  │\n··········································|····························|·············|······························\n|  Methods                                                                                                         │\n·············|····························|··············|·············|·············|···············|··············\n|  Contract  ·  Method                    ·  Min         ·  Max        ·  Avg        ·  # calls      ·  usd (avg)  │\n·············|····························|··············|·············|·············|···············|··············\n|  Test      ·  verifyCastAddMessage      ·           -  ·          -  ·    1922353  ·            2  ·          -  │\n·············|····························|··············|·············|·············|···············|··············\n|  Test      ·  verifyReactionAddMessage  ·           -  ·          -  ·    1518784  ·            2  ·          -  │\n·············|····························|··············|·············|·············|···············|··············\n```\n\n## FAQ\n\n### Is it possible to reduce gas usage per message?\n\nYes, absolutely! The main idea is to move expensive computations (Blake3 hashing and Ed25519 signature verification) offchain, using ZK proofs.\nIn this case, the Solidity contract verifies only a short proof (≈300k gas vs 2m).\nThis approach can be scaled with batching, so in the case of 10 messages, it takes 300k / 10 = 30k gas to verify a single message.\n\n### Which message types are supported?\n\nMost of them. Due to the contract size limitations, decodings for `CastRemoveBody`, `VerificationRemoveBody`, and `UserNameProof` are not included. You can include them yourself, by modifying the [message.proto](./protobufs/message.proto), check out the [Running Locally](#running-locally) section.\n\n### My contract does not fit into the 24 kb limit\n\nTry to use external libraries, as they are quite heavy to be used internally. Check the [test.ts](./test/test.ts) for deployment reference.\n\n### How can I verify the correctness of the public key?\n\nFarcaster uses onchain `KeyRegistry` contract ([spec](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#12-key-registry)), which stores the relation between the user's FID (Farcaster ID) and a public key. Here's a verification example:\n\n```solidity\naddress KEY_REGISTRY = 0x....;\n\nIKeyRegistry.KeyData memory keyData = IKeyRegistry(KEY_REGISTRY).keyDataOf(\n  messageData.fid,\n  bytes.concat(publicKey)\n);\n\nif (keyData.state != IKeyRegistry.KeyState.ADDED) revert InvalidKey();\n```\n\nKeep in mind, that KeyRegistry contact has been migrated multiple times, so make sure you use the actual address from the [Farcaster Specification](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md#12-key-registry).\n\n### Can I use this project in networks other than Optimism Mainnet?\n\nTechnically it's possible, but it's quite tricky. The best way to achieve this will be by using storage proofs for KeyRegistry storage verification.\n\n### How can I use it in frames?\n\n```javascript\nimport { NextRequest, NextResponse } from \"next/server\";\nimport {\n  Factories,\n  FarcasterNetwork,\n  FrameActionBody,\n  getSSLHubRpcClient,\n  Message,\n  MessageData,\n  MessageType,\n  toFarcasterTime,\n  UserDataType,\n} from \"@farcaster/hub-nodejs\";\n\nexport async function POST(req: NextRequest) {\n  const {\n    trustedData: { messageBytes },\n  } = await req.json();\n\n  const frameMessage = Message.decode(Buffer.from(messageBytes, \"hex\"));\n\n  const messageSignature = Buffer.from(message.signature).toString('hex');\n\n  const messageData: MessageData = {\n    type: message.data?.type as MessageType,\n    fid: message.data?.fid as number,\n    timestamp: message.data?.timestamp as number,\n    network: message.data?.network as FarcasterNetwork,\n    frameActionBody: message.data?.frameActionBody,\n  };\n\n  const messageEncoded = (MessageData.encode(messageData).finish());\n\n  const args = [\n    '0x' + Buffer.from(message.signer).toString('hex'), // public_key\n    '0x' + Buffer.from(messageSignature).slice(0, 32).toString('hex'), // signature_r\n    '0x' + Buffer.from(messageSignature).slice(32, 64).toString('hex'), // signature_s\n    '0x' + Buffer.from(messageEncoded).toString('hex') // message\n  ];\n\n  // Send your transaction here\n  // ...\n}\n```\n\n## Running locally\n\n```bash\nnode --version\nv18.17.1\nnpm --version\n9.6.7\n\nyarn\nyarn hh:compile\nyarn hh:test\n# Get contract's size in kb\nyarn hh:size\n```\n\n### Modifying proto schemes\n\nTo modify .proto schemes, install [protobuf3-solidity](https://github.com/celestiaorg/protobuf3-solidity).\n\n```\ngit clone https://github.com/celestiaorg/protobuf3-solidity\ncd protobuf3-solidity\nmake\n```\n\nExport the path to the binary and run `yarn protoc` to update Solidity libraries and TS definitions\n\n```bash\nexport PROTO_GEN_SOL=./../protobuf3-solidity/bin/protoc-gen-sol\ncd farcaster-solidity\nyarn protoc\n```\n\nKeep in mind, that not all Protobuf features are supported (`oneOf` fields, repeated strings, non-packed repeated fields). Another important thing is that message fields should be enumerated in a strict incremental order.\n\n## Links \u0026 credits\n\n- [Blake3 Solidity implementation](https://github.com/mel-project/blake3-sol)\n- [Ed25519 Solidity implementation](https://github.com/chengwenxi/Ed25519)\n- [protobuf3-solidity](https://github.com/celestiaorg/protobuf3-solidity)\n- [@farcaster/core](https://github.com/farcasterxyz/hub-monorepo/tree/main/packages/core) (contains .proto files)\n- [Farcaster specification](https://github.com/farcasterxyz/protocol/blob/main/docs/SPECIFICATION.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavlovdog%2Ffarcaster-solidity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpavlovdog%2Ffarcaster-solidity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavlovdog%2Ffarcaster-solidity/lists"}