Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
164 lines (135 sloc) 4.63 KB
pragma solidity ^0.4.21;
import '../math/SafeMath.sol';
import '../token/IERC20Token.sol';
/**
* @title BasePoll
* @dev Abstract base class for polling contracts
*/
contract BasePoll is SafeMath {
struct Vote {
uint256 time;
uint256 weight;
bool agree;
}
uint256 public constant MAX_TOKENS_WEIGHT_DENOM = 1000;
IERC20Token public token;
address public fundAddress;
uint256 public startTime;
uint256 public endTime;
bool checkTransfersAfterEnd;
uint256 public yesCounter = 0;
uint256 public noCounter = 0;
uint256 public totalVoted = 0;
bool public finalized;
mapping(address => Vote) public votesByAddress;
modifier checkTime() {
require(now >= startTime && now <= endTime);
_;
}
modifier notFinalized() {
require(!finalized);
_;
}
/**
* @dev BasePoll constructor
* @param _tokenAddress ERC20 compatible token contract address
* @param _fundAddress Fund contract address
* @param _startTime Poll start time
* @param _endTime Poll end time
*/
function BasePoll(address _tokenAddress, address _fundAddress, uint256 _startTime, uint256 _endTime, bool _checkTransfersAfterEnd) public {
require(_tokenAddress != address(0));
require(_startTime >= now && _endTime > _startTime);
token = IERC20Token(_tokenAddress);
fundAddress = _fundAddress;
startTime = _startTime;
endTime = _endTime;
finalized = false;
checkTransfersAfterEnd = _checkTransfersAfterEnd;
}
/**
* @dev Process user`s vote
* @param agree True if user endorses the proposal else False
*/
function vote(bool agree) public checkTime {
require(votesByAddress[msg.sender].time == 0);
uint256 voiceWeight = token.balanceOf(msg.sender);
uint256 maxVoiceWeight = safeDiv(token.totalSupply(), MAX_TOKENS_WEIGHT_DENOM);
voiceWeight = voiceWeight <= maxVoiceWeight ? voiceWeight : maxVoiceWeight;
if(agree) {
yesCounter = safeAdd(yesCounter, voiceWeight);
} else {
noCounter = safeAdd(noCounter, voiceWeight);
}
votesByAddress[msg.sender].time = now;
votesByAddress[msg.sender].weight = voiceWeight;
votesByAddress[msg.sender].agree = agree;
totalVoted = safeAdd(totalVoted, 1);
}
/**
* @dev Revoke user`s vote
*/
function revokeVote() public checkTime {
require(votesByAddress[msg.sender].time > 0);
uint256 voiceWeight = votesByAddress[msg.sender].weight;
bool agree = votesByAddress[msg.sender].agree;
votesByAddress[msg.sender].time = 0;
votesByAddress[msg.sender].weight = 0;
votesByAddress[msg.sender].agree = false;
totalVoted = safeSub(totalVoted, 1);
if(agree) {
yesCounter = safeSub(yesCounter, voiceWeight);
} else {
noCounter = safeSub(noCounter, voiceWeight);
}
}
/**
* @dev Function is called after token transfer from user`s wallet to check and correct user`s vote
*
*/
function onTokenTransfer(address tokenHolder, uint256 amount) public {
require(msg.sender == fundAddress);
if(votesByAddress[tokenHolder].time == 0) {
return;
}
if(!checkTransfersAfterEnd) {
if(finalized || (now < startTime || now > endTime)) {
return;
}
}
if(token.balanceOf(tokenHolder) >= votesByAddress[tokenHolder].weight) {
return;
}
uint256 voiceWeight = amount;
if(amount > votesByAddress[tokenHolder].weight) {
voiceWeight = votesByAddress[tokenHolder].weight;
}
if(votesByAddress[tokenHolder].agree) {
yesCounter = safeSub(yesCounter, voiceWeight);
} else {
noCounter = safeSub(noCounter, voiceWeight);
}
votesByAddress[tokenHolder].weight = safeSub(votesByAddress[tokenHolder].weight, voiceWeight);
}
/**
* Finalize poll and call onPollFinish callback with result
*/
function tryToFinalize() public notFinalized returns(bool) {
if(now < endTime) {
return false;
}
finalized = true;
onPollFinish(isSubjectApproved());
return true;
}
function isNowApproved() public view returns(bool) {
return isSubjectApproved();
}
function isSubjectApproved() internal view returns(bool) {
return yesCounter > noCounter;
}
/**
* @dev callback called after poll finalization
*/
function onPollFinish(bool agree) internal;
}
You can’t perform that action at this time.