# degen chain hackathon idea Deploy your own Farcaster community, using DegenChain as settlement layer + New Frontend that allows creating your Farcaster community: + Set a name for your community (i.e Yellow Collective) + Set the census (i.e NFT: 0x1234 or ERC20: 0x567) + supported networks: base, optimism, polygon, ethereum + Upload a Logo + Set a Farcaster channel (i.e /yellow) + Set who can create voting proposals + farcaster user handles + holders (all) + holders with mínimum followers + Enable/Disable notifications via Farcaster when new voting proposal + Pay with degen + When voting ends on Farcaster, the following information is uploaded to DegenChain + Question and options + Date + Results of the vote + Turnout + List of the participants When a new Community is created on the DegenChain smartcontract, it will automatically appear available on https://farcaster.vote New voting proposals can then be created using such community on Farcaster.vote using the current standard flow. Question and result are automatically uploaded to DegenChain, so anyone can verify it and remains settled forever. ![degenvote.drawio](https://hackmd.io/_uploads/r1ewXUNxC.svg) --- ### Formulari creació community - s'utilitza el signer Ethereum i s'envia la TX al smartcontract #### Required API endpoints - Create a community: - `GET /users/profile/{fid}` | `/users/profile/{username}`: Get Farcaster user by FID or username. - `GET /channels`: List of Farcaster channels. - `GET /channels/{channelID}`: Information about Farcaster channel, if it exists. - Validate default census: - `POST /census/check/[nft/erc20]`: If it is a contract, validate that it exists in the associated network. - `Body: {"address": "", "blockchain": "base"}` - ~~`POST /census/check/channel-gated`: If it is a channel, validate that it exists~~ --> **Replaced by `GET /channels/{channelID}`** - `POST /community` Store the resulting community in the database when contract interaction success. ### Dashboard community ### EVM contracts #### Communities - This is the community registry, where communities are created and managed. ```solidity contract CommunityHub is Ownable { constructor(address owner) Ownable(owner) {} enum CreateElectionPermission { GUARDIAN, CENSUS } enum TokenType { ERC20, ERC721, ERC1155 } struct Token { string name; string symbol; uint8 decimals; TokenType tokenType; string chainId; } enum CensusType { FC, CHANNEL, FOLLOWERS, CSV, TOKEN } struct Census { CensusType censusType; Token[] tokens; } struct CommunityMetadata { string name; string imageURI; string channel; bool notifications; } struct Community { CommunityMetadata metadata; Census census; EnumerableSet.Set guardians; address electionResultsContract; CreateElectionPermission createElectionPermission; uint256 cooldown; } mapping(uint256 => Community) private communities; // create community function CreateCommunity( CommunityMetadata memory metadata, Census memory census, address[] memory guardians, address electionResultsContract, CreateElectionPermission createElectionPermission, uint256 cooldown ) public {} // delete community function DeleteCommunity(uint256 communityId) public onlyOwner {} // admin manage community function AdminManageCommunity( uint256 communityId, CommunityMetadata memory metadata, Census memory census, address[] memory guardians, address electionResultsContract, CreateElectionPermission createElectionPermission ) public onlyOwner {} // set metadata function SetMetadata(uint256 communityId, CommunityMetadata memory metadata) public onlyGuardian(communityId) {} // add guardian function AddGuardian(uint256 communityId, address guardian) public onlyGuardian(communityId) {} // remove guardian function RemoveGuardian(uint256 communityId, address guardian) public onlyGuardian(communityId) {} // isGuardian function IsGuardian(uint256 communityId, address guardian) internal view returns (bool) {} // add census function AddCensus(uint256 communityId, Census memory census) public onlyGuardian(communityId) {} // remove census function RemoveCensus(uint256 communityId) public onlyGuardian(communityId) {} // set election results contract function SetElectionResultsContract(uint256 communityId, address electionResultsContract) public onlyGuardian(communityId) {} // set create election permission function SetCreateElectionPermission(uint256 communityId, CreateElectionPermission createElectionPermission) public onlyGuardian(communityId) {} // set notifiable elections function SetNotifiableElections(uint256 communityId, bool notifiableElections) public onlyGuardian(communityId) {} // set election results function SetElectionResults( uint256 communityId, bytes32 electionId, string memory question, string[] memory options, string memory date, uint256[][] memory tally, uint256 turnout, string[] memory participants, bytes memory action, bytes32 censusRoot, string memory censusURI ) public onlyGuardian(communityId) {} function GetElectionResults(uint256 communityId, string memory electionId) public view returns ( string memory question, string[] memory options, string memory date, uint256[][] memory tally, uint256 turnout, string[] memory participants, bytes memory action, bytes32 censusRoot, string memory censusURI ) {} } ``` #### Results - This contract is set by the community, by default Vocdoni will take care of this, but the user can choose to change. - Stores all the organizations elections results ```solidity struct Result { string question; string[] options; string date; uint256[][] tally; uint256 turnout; uint256 totalVotingPower; string[] participants; bytes action; bytes32 censusRoot; string censusURI; } // CommunityId => ElectionId => Result mapping(bytes32 => mapping(bytes32 => Result)) public results; // set results function setResult(bytes32 communityId, bytes32 electionId, Result memory result) public onlyOwner { results[communityId][electionId] = result; } // get results function getResult(bytes32 communityId, bytes32 electionId) public view returns (Result memory) { return results[communityId][electionId]; } ```