Build and Deploy a Governance Voting Dashboard on Rootstock
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.
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 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
- Create Teams
Users can establish teams by providing:
- A team name
- A meme token address (used for team identity)
- A team leader address
- Vote for Teams Users cast votes for their preferred teams using governance tokens.
- Token Balance Tracking The system monitors each team leader's balance of governance tokens.
- Smart Contracts Integration The project integrates smart contracts to handle team creation, voting, and token transactions.
- 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.
-
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 = [""];}