This project is a **Governance Voting Dashboard** built on the **Rootstock blockchain**. It allows users to create and vote for teams using governance tokens [ERC20 tokens](/concepts/glossary/). The voting is managed by a smart contract, making it decentralized and transparent. Each team has a unique name, a governance token, and a leader, and users can vote by transferring tokens to their preferred teams. The dashboard is designed for token-based voting, where votes are reflected in a team's score. Higher scores indicate more community support for that team. ## Prerequisites Before you begin your journey into deploying smart contracts on the Rootstock blockchain, ensure you have the following essential tools set up: - **Node.js** You will need Node.js installed on your machine to run the project locally. [Download NodeJS](https://nodejs.org/en/download) the latest LTS version, which is recommended for most users. - **Web3 Wallet (Metamask)** A Web3 wallet is required for signing transactions and interacting with the Rootstock network. This wallet will enable you to manage your cryptocurrencies and deploy your smart contracts securely. ## Features 1. **Create Teams** Users can establish teams by providing: * A team name * A meme token address (used for team identity) * A team leader address 2. **Vote for Teams** Users cast votes for their preferred teams using governance tokens. 3. **Token Balance Tracking** The system monitors each team leader's balance of governance tokens. 4. **Smart Contracts Integration** The project integrates smart contracts to handle team creation, voting, and token transactions. 5. **ERC20 Governance** Votes are cast using ERC20 tokens, ensuring decentralized governance. ## Core Smart Contract: TeamsManager The `TeamsManager` contract, written in Solidity, is the foundation of the voting system. It manages team creation, voting, and score tracking, and enforces administrative controls. :::info[Key functions:] * **`vote(teamName, transferAmount)`** Allows users to vote for a team by transferring governance tokens. teamName specifies the team to receive the vote, and transferAmount is the token amount to transfer. ``` function vote(string memory teamName, uint256 transferAmount) public nonReentrant { require(bytes(_teams[teamName].teamName).length > 0, "Unknown team"); require(keccak256(abi.encodePacked(_teamLeaders[msg.sender])) != keccak256(abi.encodePacked(teamName)), "Cannot vote for own team"); _teams[teamName].score += transferAmount; bool success = _votingTokenContract.transferFrom(msg.sender, address(this), transferAmount); require(success, "Token transfer failed"); } ``` * **`getTeamNames()`** Returns a list of all teams registered in the contract. ``` function getTeamNames() external view returns(string[] memory) { return _teamNames; } ``` * **`getTeamInfo(teamName)`** Provides detailed information on a specified team. ``` function getTeamInfo(string memory teamName) public view returns(TeamInfo memory) { return _teams[teamName]; } ``` * **`getScore(teamName)`** Retrieves the current vote score for a team. ``` function getScore(string memory teamName) public view returns(uint256) { return _teams[teamName].score; } ``` * **`addTeam(teamName, memeTokenAddress, teamLeaderAddress)`** Allows administrators to add a new team, specifying the team's name, meme token address, and leader address. ``` function addTeam(string memory teamName, address memeTokenAddress, address teamLeaderAddress) public { require(bytes(_teams[teamName].teamName).length == 0, "Team already added"); require(bytes(_teamLeaders[teamLeaderAddress]).length == 0, "Leader already assigned to a team"); IERC20 memeTokenContract = IERC20(memeTokenAddress); string memory memeTokenName = memeTokenContract.name(); string memory memeTokenUri = memeTokenContract.getUri(); _teamNames.push(teamName); _teamLeaders[teamLeaderAddress] = teamName; _teams[teamName] = TeamInfo(teamName, memeTokenName, memeTokenUri, memeTokenAddress, teamLeaderAddress, 0); } ``` * **`setReadyToVote()`** Marks the contract as ready for voting. Only administrators can call this function. ``` function setReadyToVote() public onlyAdmins { _readyToVote = true; } ``` * **`reset()`** Resets the contract's voting state and clears team data. Only administrators can execute this. ``` function reset() public onlyAdmins { for (uint256 i; i < _teamNames.length; i++) { _readyToVote = false; _teamLeaders[_teams[_teamNames[i]].teamLeaderAddress] = ""; _teams[_teamNames[i]] = TeamInfo("", "", "", address(0), address(0), 0); } _teamNames = [""]; } ``` ::: ## **Getting Started** ````mdx-code-block
NEXT_PUBLIC_TEAM_MANAGER_ADDRESS (fig 1.)
:::note If you’re new to deploying contracts on Remix, check out this [tutorial](https://dev.rootstock.io/developers/quickstart/remix/) for more detailed steps. ::: * **How to get it**: * Deploy the TeamsManager.sol contract to the Rootstock network using RemixIDE, a popular tool for writing and deploying smart contracts. * Once deployed, you’ll find the contract’s address in the Remix’s console. Copy this address. * Paste this address into your .env file as shown below: ``` NEXT_PUBLIC_TEAM_MANAGER_ADDRESS=
NEXT_PUBLIC_PINATA_URL (fig 2.)
* **How to get it**: * Start by logging into your Pinata Cloud account and navigate to the dashboard [Pinata](https://www.pinata.cloud/). * In the dashboard, click on the **"Files"** tab to access the file storage area. * Click the **"Upload"** button and select a sample image file from your device to upload. * After the upload is complete, locate the uploaded image in the file list. You’ll see a **URL** provided by Pinata that can be used to access your file. For example: ``` https://emerald-familiar-cobra-431.mypinata.cloud/ipfs/QmVsBy3vo9tmbjYmFNCiRwAvCBU7p9peEEgyR9awJg4Tyj ``` * The base URL is the part of the file URL before the unique CID (Content Identifier). In this example, the base URL is: ``` https://emerald-familiar-cobra-431.mypinata.cloud/ipfs/ ``` * To display images or files from Pinata Cloud on your frontend, simply append the CID to the base URL. **Example:** ``` NEXT_PUBLIC_PINATA_URL=
Development server (fig 3.)
```` ## Interacting with the Frontend ````mdx-code-block
Explore the Teams (fig 4.)
* Explore the list of teams in the **Teams List** section. * For each team, you can view: - **Logo**: Visual representation or meme associated with the team. - **Team Name**: Helps identify each team uniquely. - **Symbol**: Represents the token each team uses for voting. - **Leader Address**: Shows the team leader’s wallet address. - **Meme Token Address**: Address of the token associated with the team. - **Score**: The number of votes the team has received. * This information helps you decide which team to support with your vote.
Vote for a Team (fig 5.)
* To vote, find the team you want to support and click the **Vote** button in the **Option** column. * You will see a pop up screen with a field to add the amount to vote and an Add vote button. * Confirm the transaction in your wallet. You’ll need `governance tokens` to cast your vote and a small amount of `RBTC tokens` for transaction fees. * Once confirmed, your vote will be registered, and the team’s score will update to reflect your support.
Adding a Team (fig 6.)
* If you have administrative privileges, you can add a new team by clicking the **Add Team** button. * Enter the following details to create a new team: * **Team Name**: A unique name for the team. * **Meme Token Address**: Address of the meme token associated with the team. * **Team Leader Address**: Wallet address of the team leader. * Once added, the new team will appear in the Teams List, and users can start voting for it. ```` ## Conclusion Following this guide, you can build and deploy a fully functional Governance Voting Dashboard that supports decentralized decision-making on the Rootstock Network. This dApp enables users to create teams, manage proposals, and cast votes using governance tokens (ERC20). The dApp simplifies the voting process and enhances user engagement with an intuitive interface and smooth interactions. Whether you're a developer looking to learn or a project leader aiming to implement decentralized governance, this guide equips you with all the tools and knowledge needed to succeed. Start building your dApp today and unlock the potential of transparent and efficient governance!