Hello Everyone,
After Ethereum smart contract programming 101, I wanted to work on a small project… Where I can use a wallet similar to the one that we’d created during the course.
I’ve created a simple voting system using a multi-user wallet.
There may be some flaws in the code… maybe my implementation doesn’t work the way the actual system works… Still, here is a try.
Overview
Here in the project, I’m associating ethers present in a wallet with credits of a user that he/she can utilize for voting. For instance - 3 ethers correspond to 3 credits.
A user can express how strongly they feel about an issue by using voting points.
That is, a user can give voting points from the range of [-credits, credits]
for each poll.
An admin can create a poll and perform other duties…
I would be highly appreciative if anybody could suggest how to improve the code further, any new feature, any other suggestions…
Thanks,
Tanu
Wallet.sol
pragma solidity 0.7.5;
contract Wallet{
mapping(address => uint)balance;
event AmountDeposited(address sender, uint amount);
function deposit() public payable {
balance[msg.sender] += msg.value;
emit AmountDeposited(msg.sender,msg.value);
}
function withdraw(uint _amount) public {
require(balance[msg.sender] >= _amount,'Withdrawal is more than a deposit');
balance[msg.sender] -= _amount;
msg.sender.transfer(_amount);
}
function transfer(address payable _recipient, uint _amount) public {
require(balance[msg.sender] >= _amount,'Transfer is more than a deposit');
balance[msg.sender] -= _amount;
_recipient.transfer(_amount);
}
function getBalance(address _add) view external returns(uint) {
return balance[_add];
}
}
Admin.sol
pragma solidity 0.7.5;
pragma abicoder v2;
contract Admin{
struct Poll{
uint pollId;
string pollDetails;
uint256 creationTime;
uint256 expirationTime; // in days
uint voters;
int votes;
int result;
}
Poll [] polls;
address admin;
constructor(){
admin = msg.sender;
}
modifier onlyAdmin{
require(msg.sender == admin,'Accessible by Admin only');
_;
}
mapping(uint => Poll)pollLogs; //pollId => poll
event PollCreated(address creator,uint pollId, string pollDetails, uint validityInDays);
//validityTime - Validity in terms of days
function createPoll(string memory _pollDetails,uint validityTime) public onlyAdmin{
Poll memory p = Poll(polls.length,_pollDetails,block.timestamp,block.timestamp + (validityTime * 1 days),0,0,0);
pollLogs[p.pollId] = p;
polls.push(p);
emit PollCreated(admin,p.pollId,_pollDetails,validityTime);
}
function viewPoll(uint _pollId) public view returns(Poll memory){
return pollLogs[_pollId];
}
function getAllPolls() public view returns(Poll [] memory){
return polls;
}
function pollResult(uint _pollId) public view returns(string memory){
require(pollLogs[_pollId].voters != 0,'No one has voted in this poll');
require(block.timestamp > pollLogs[_pollId].expirationTime,'Poll result can not be declared before due date');
return pollLogs[_pollId].result > 0 ?'Accepted':'Rejected';
}
}
Voter.sol
pragma solidity 0.7.5;
pragma abicoder v2;
import './Admin.sol';
contract VoterPanel is Admin{
struct VoterHistory{
uint pollId;
int votes;
}
struct Voter{
uint credits;
VoterHistory [] history;
}
mapping(address => Voter)voterLog;
mapping(address => mapping(uint => bool))checkStatus; // address => pollId => T/F
function voterDetails(address _add) public view returns(Voter memory){
return voterLog[_add];
}
}
VotingSystem.sol
pragma solidity 0.7.5;
pragma abicoder v2;
import './Voter.sol';
interface WalletInterface{
function getBalance(address _add) view external returns(uint);
}
contract VotingPortal is VoterPanel{
WalletInterface walletInstance;
constructor(address walletAddress){
walletInstance = WalletInterface(walletAddress);
}
event CreditsEarned(address _voter, uint _creditsEarned);
function earnCredits () public returns(uint) {
require(voterLog[msg.sender].credits == 0,'Use your remaining credits first');
uint walletCredits = walletInstance.getBalance(msg.sender);
require(walletCredits > 0,'To earn credits fill your wallet first');
voterLog[msg.sender].credits = walletCredits/(1 ether);
emit CreditsEarned(msg.sender,voterLog[msg.sender].credits);
return voterLog[msg.sender].credits;
}
function viewCredits()public view returns(uint){
return voterLog[msg.sender].credits;
}
function abs(int x) private pure returns (uint) {
return x >= 0 ? uint(x) : uint(-x);
}
//votingPoints = [-credits,credits] , can be negative also
function vote(uint _pollId,int votingPoints) public {
require(checkStatus[msg.sender][_pollId] != true,"You've already voted for this poll");
require(pollLogs[_pollId].expirationTime > block.timestamp , "This poll has expired");
require(votingPoints != 0,'Voting Points can not be zero');
require(abs(votingPoints) <= voterLog[msg.sender].credits,'Voting Points can not be more than credits');
voterLog[msg.sender].credits = 0;
voterLog[msg.sender].history.push(VoterHistory(_pollId,votingPoints));
checkStatus[msg.sender][_pollId] = true;
pollLogs[_pollId].voters++;
pollLogs[_pollId].votes += votingPoints;
pollLogs[_pollId].result = pollLogs[_pollId].votes/int(pollLogs[_pollId].voters);
polls[_pollId] = pollLogs[_pollId];
}
}