{"id":15427464,"url":"https://github.com/vocdoni/votecaster","last_synced_at":"2025-07-17T02:16:06.917Z","repository":{"id":221858085,"uuid":"755560476","full_name":"vocdoni/votecaster","owner":"vocdoni","description":"A farcaster frame for voting with Vocdoni a.k.a. Votecaster","archived":false,"fork":false,"pushed_at":"2024-12-02T10:30:59.000Z","size":19383,"stargazers_count":8,"open_issues_count":40,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-13T21:13:15.033Z","etag":null,"topics":["blockchain-voting","farcaster","farcaster-frames","vocdoni","vote"],"latest_commit_sha":null,"homepage":"https://votecaster.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vocdoni.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2024-02-10T15:33:24.000Z","updated_at":"2024-12-05T16:39:13.000Z","dependencies_parsed_at":"2024-04-01T10:32:31.178Z","dependency_job_id":"aeafae61-7d5d-4c86-97e3-ca2b048d9c64","html_url":"https://github.com/vocdoni/votecaster","commit_stats":null,"previous_names":["vocdoni/vote-frame","vocdoni/votecaster"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vocdoni%2Fvotecaster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vocdoni%2Fvotecaster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vocdoni%2Fvotecaster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vocdoni%2Fvotecaster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vocdoni","download_url":"https://codeload.github.com/vocdoni/votecaster/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248782260,"owners_count":21160717,"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":["blockchain-voting","farcaster","farcaster-frames","vocdoni","vote"],"created_at":"2024-10-01T18:00:25.100Z","updated_at":"2025-04-13T21:13:23.206Z","avatar_url":"https://github.com/vocdoni.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003cp align=\"center\" width=\"100%\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://developer.vocdoni.io/img/vocdoni_logotype_full_blank.svg\" /\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://developer.vocdoni.io/img/vocdoni_logotype_full_white.svg\" /\u003e\n      \u003cimg alt=\"Star History Chart\" src=\"https://developer.vocdoni.io/img/vocdoni_logotype_full_white.svg\" /\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\" width=\"100%\"\u003e\n    \u003ca href=\"https://github.com/vocdoni/vote-frame/commits/main/\"\u003e\u003cimg src=\"https://img.shields.io/github/commit-activity/m/vocdoni/vote-frame\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/vocdoni/vote-frame/issues\"\u003e\u003cimg src=\"https://img.shields.io/github/issues/vocdoni/vote-frame\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://discord.gg/xFTh8Np2ga\"\u003e\u003cimg src=\"https://img.shields.io/badge/discord-join%20chat-blue.svg\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://twitter.com/vocdoni\"\u003e\u003cimg src=\"https://img.shields.io/twitter/follow/vocdoni.svg?style=social\u0026label=Follow\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n  \u003cdiv align=\"center\"\u003e\n    Vocdoni is the first universally verifiable, censorship-resistant, anonymous, and self-sovereign governance protocol. \u003cbr /\u003e\n    Our main aim is a trustless voting system where anyone can speak their voice and where everything is auditable. \u003cbr /\u003e\n    We are engineering building blocks for a permissionless, private and censorship resistant democracy.\n    \u003cbr /\u003e\n    \u003ca href=\"https://developer.vocdoni.io/\"\u003e\u003cstrong\u003eExplore the developer portal »\u003c/strong\u003e\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003ch3\u003eMore About Us\u003c/h3\u003e\n    \u003ca href=\"https://vocdoni.io\"\u003eVocdoni Website\u003c/a\u003e\n    |\n    \u003ca href=\"https://vocdoni.app\"\u003eWeb Application\u003c/a\u003e\n    |\n    \u003ca href=\"https://explorer.vote/\"\u003eBlockchain Explorer\u003c/a\u003e\n    |\n    \u003ca href=\"https://law.mit.edu/pub/remotevotingintheageofcryptography/release/1\"\u003eMIT Law Publication\u003c/a\u003e\n    |\n    \u003ca href=\"https://chat.vocdoni.io\"\u003eContact Us\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003ch3\u003eKey Repositories\u003c/h3\u003e\n    \u003ca href=\"https://github.com/vocdoni/vocdoni-node\"\u003eVocdoni Node\u003c/a\u003e\n    |\n    \u003ca href=\"https://github.com/vocdoni/vocdoni-sdk/\"\u003eVocdoni SDK\u003c/a\u003e\n    |\n    \u003ca href=\"https://github.com/vocdoni/ui-components\"\u003eUI Components\u003c/a\u003e\n    |\n    \u003ca href=\"https://github.com/vocdoni/ui-scaffold\"\u003eApplication UI\u003c/a\u003e\n    |\n    \u003ca href=\"https://github.com/vocdoni/census3\"\u003eCensus3\u003c/a\u003e\n  \u003c/div\u003e\n\n# vote-frame\n\nThis repository contains a Farcaster frame for voting with the Vocdoni protocol. It is designed to enable integrated polling on Farcaster, leveraging Vocdoni's decentralized, verifiable, and censorship-resistant infrastructure.\n\nThis frame is deployed at https://votecaster.io\n\nThis repository contains the Go code necessary for constructing the server node. It features a web frontend that facilitates the creation of polls and oversees the communication with the Farcaster client, adhering to the frame specification.\n\nThe operation of the server polling node is centered around processing the signed message packet that originates from the Farcaster user upon engaging the vote button. This process involves extracting the public key from the signed message and packaging the signature into a Vocdoni vote transaction.\n\nFollowing the submission of the transaction, the Vocdoni blockchain undertakes the verification process to ensure:\n\n1. The public key is recognized as a valid Farcaster public key and is listed in the census.\n2. The signature correctly corresponds to the public key.\n3. The selected button accurately reflects the voting choice.\n\nTo assure the presence of a user's public key within the Farcaster protocol, the system employs the Vocdoni census3,\na service which persistently scans the Optimism network for Farcaster registrations. [Census3 GitHub Repository](https://github.com/vocdoni/census3)\n\n### Table of Contents\n- [Getting Started](#getting-started)\n- [Reference](#reference)\n- [Examples](#examples)\n- [Preview](#preview)\n- [Disclaimer](#disclaimer)\n- [Contributing](#contributing)\n- [License](#license)\n\n\n## Getting Started\n\nTo deploy the server node, Docker Compose is utilized:\n\n```sh\ncp .env.example .env\ndocker compose build\ndocker compose up -d\n```\n\nSee the `.env` file; you need to define at least a Neynar API key.\n\nAfter startup, navigate to http://localhost:8888 to access the web frontend.\n\nConfiguration and environment variables can be specified within the `.env` file.\n\nFor those operating within a Go-ready environment, you can also run the go code directly with several options:\n\n```sh\ngo run . --mongoURL=mongodb://root:vocdoni@127.0.0.1:27017 --logLevel=debug --neynarAPIKey=\u003cyour_key\u003e --web3=https://mainnet.optimism.io,https://optimism.llamarpc.com,https://optimism-mainnet.public.blastapi.io,https://rpc.ankr.com/optimism,https://optimism.drpc.org --indexer=false --apiEndpoint=https://api-dev.vocdoni.net/v2\n```\n\n## Reference\n\n### Authentication\n\nThe Authentication API provides a set of endpoints for managing user authentication via Warpcast.\nThis includes creating authentication links, verifying authentication status, and checking authentication tokens.\n\nThe authentication token must be set as a Bearer HTTP header `authorization: Bearer \u003ctoken\u003e`\n\nThe web application might store the bearer token in the local storage, so the user does not need to reauthenticate on each access.\n\nThe token expires after 15 days of non activity. Multiple tokens for the same user are allowed.\n\n#### 1. Create Authentication Link\n\nThe authantication link is a Warpcast deep link that should be returned to the user (usually showing a QR code to scan with the smartphone camera).\n\n- **Endpoint:** `/auth`\n- **Method:** `GET`\n- **Access:** Public\n- **Description:** Creates a new authentication channel and returns a URL and an ID for the client to initiate the authentication process.\n- **Returns:**\n  - **HTTP 200 OK** on success with JSON payload containing:\n    - `url`: The URL to which the user should be directed to complete the authentication process.\n    - `id`: The unique identifier for the authentication request.\n  - **HTTP 500 Internal Server Error** on failure with an error message.\n\n```sh\ncurl -X GET \"http://localhost:8888/auth\"\n```\n\n#### 2. Verify Authentication\n\nOnce the user verifies on Warpcast, this endpoint can be used to fetch the Bearer token.\nNote that this endpoint can only by called once (then it is removed and 404 will be returned).\n\n- **Endpoint:** `/auth/{id}`\n- **Method:** `GET`\n- **Access:** Public\n- **Description:** Verifies the status of an authentication channel using the ID provided when the channel was created. Returns an authentication token upon successful authentication.\n- **URL Parameters:**\n  - `id`: The unique identifier for the authentication request.\n- **Returns:**\n  - **HTTP 200 OK** on successful authentication with JSON payload containing:\n    - `authToken`: The authentication token.\n  - **HTTP 204 No Content** if authentication is still pending.\n  - **HTTP 404 Not Found** if the specified ID does not correspond to an existing authentication channel.\n  - **HTTP 500 Internal Server Error** on other errors with an error message.\n\n\n```sh\ncurl -X GET \"http://localhost:8888/auth/123e4567\"\n```\n\n```json\n{\n    \"authToken\": \"17c512b4-d55c-a2fe-144a-8fad0daa357c\",\n    \"profile\": {\n        \"fid\": 237855,\n        \"username\": \"foo\",\n        \"displayName\": \"bar 🎩 ⛓️‍💥\",\n        \"bio\": \"I do stuff\",\n        \"pfpUrl\": \"https://i.imgur.com/jFrkJ0KO.gif\",\n        \"custody\": \"0xabcde....\",\n        \"verifications\": [\n            \"0xabcde...\"\n        ]\n    },\n    \"reputation\": 12,\n    \"reputationData\": {\n        \"followersCount\": 200,\n        \"electionsCreated\": 20,\n        \"castedVotes\": 54,\n        \"participationAchievement\": 114\n    }\n}\n```\n\n#### 3. Check Authentication Token\n\nEvery time a user access the web application it is expected to check this endpoint.\nThis action will update the expiration date.\n\n- **Endpoint:** `/auth/check`\n- **Method:** `GET`\n- **Access:** Public\n- **Description:** Checks if the provided authentication token is valid and updates the activity time. This endpoint should be used to verify token validity and refresh token activity.\n- **Headers:**\n  - `AuthToken`: The authentication token to be validated.\n- **Returns:**\n  - **HTTP 200 OK** if the token is valid.\n  - **HTTP 404 Not Found** if the token is invalid or expired, with an error message.\n  - **HTTP 400 Bad Request** if the `AuthToken` header is missing.\n\n\n```sh\ncurl -X GET \"http://example.com/auth/check\" -H \"authorization: Bearer {your_auth_token}\"\n```\n\n```json\n{\n    \"reputation\": 12,\n    \"reputationData\": {\n        \"followersCount\": 200,\n        \"electionsCreated\": 20,\n        \"castedVotes\": 54,\n        \"participationAchievement\": 114\n    }\n}\n```\n\n## Preview\n\nThis frame is live at https://votecaster.io\n\n\n## Contributing\n\nWhile we welcome contributions from the community, we do not track all of our issues on Github and we may not have the resources to onboard developers and review complex pull requests. That being said, there are multiple ways you can get involved with the project.\n\nPlease review our [development guidelines](https://developer.vocdoni.io/development-guidelines).\n\n## License\n\nThis repository is licensed under the [GNU Affero General Public License v3.0.](./LICENSE)\n\n\n    Vocdoni Farcaster Vote Frame\n    Copyright (C) 2024 Vocdoni Association\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n\n[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvocdoni%2Fvotecaster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvocdoni%2Fvotecaster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvocdoni%2Fvotecaster/lists"}