visual-identity/contracts/polls/PollManager.sol

294 lines
7.5 KiB
Solidity
Raw Normal View History

pragma solidity ^0.4.23;
2018-06-26 10:19:04 -04:00
import "../common/Controlled.sol";
import "./LowLevelStringManipulator.sol";
import "../token/MiniMeToken.sol";
2018-06-26 15:41:28 -04:00
import "./IPollFactory.sol";
import "./SingleChoiceFactory.sol";
2018-06-26 10:19:04 -04:00
contract IPollContract {
2018-06-26 14:44:45 -04:00
function deltaVote(int _amount, bytes32 _ballot) public returns (bool _succes);
function pollType() public constant returns (bytes32);
function question() public constant returns (string);
2018-06-26 10:19:04 -04:00
}
contract PollManager is LowLevelStringManipulator, Controlled {
struct VoteLog {
bytes32 ballot;
uint amount;
}
struct Poll {
uint startBlock;
uint endBlock;
address token;
address pollContract;
bool canceled;
uint voters;
mapping(bytes32 => uint) votersPerBallot;
2018-06-26 10:19:04 -04:00
mapping(address => VoteLog) votes;
}
Poll[] _polls;
2018-06-26 15:41:28 -04:00
IPollFactory pollFactory;
2018-06-26 10:19:04 -04:00
MiniMeTokenFactory public tokenFactory;
MiniMeToken public token;
2018-06-26 14:44:45 -04:00
constructor(address _tokenFactory, address _token)
2018-06-26 10:19:04 -04:00
public {
tokenFactory = MiniMeTokenFactory(_tokenFactory);
token = MiniMeToken(_token);
2018-06-26 15:41:28 -04:00
pollFactory = IPollFactory(new SingleChoiceFactory());
2018-06-26 10:19:04 -04:00
}
modifier onlySNTHolder {
// TODO: require min number of tokens?
require(token.balanceOf(msg.sender) > 0);
_;
}
function addPoll(
uint _endBlock,
bytes _description)
2018-06-26 14:44:45 -04:00
public
2018-06-26 10:19:04 -04:00
onlySNTHolder
returns (uint _idPoll)
{
2018-06-26 17:02:04 -04:00
require(_endBlock > block.number);
2018-06-26 14:44:45 -04:00
2018-06-26 10:19:04 -04:00
_idPoll = _polls.length;
_polls.length ++;
2018-06-26 14:44:45 -04:00
Poll storage p = _polls[ _idPoll ];
2018-06-26 17:02:04 -04:00
p.startBlock = block.number;
2018-06-26 10:19:04 -04:00
p.endBlock = _endBlock;
p.voters = 0;
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
string memory name;
string memory symbol;
(name, symbol) = getTokenNameSymbol(address(token));
string memory proposalName = strConcat(name, "_", uint2str(_idPoll));
2018-06-26 10:19:04 -04:00
string memory proposalSymbol = strConcat(symbol, "_", uint2str(_idPoll));
p.token = tokenFactory.createCloneToken(
address(token),
2018-06-26 17:02:04 -04:00
block.number - 1,
2018-06-26 10:19:04 -04:00
proposalName,
token.decimals(),
proposalSymbol,
true);
2018-06-26 15:41:28 -04:00
p.pollContract = pollFactory.create(_description);
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
require(p.pollContract != 0);
emit PollCreated(_idPoll);
2018-06-26 10:19:04 -04:00
}
2018-06-26 14:44:45 -04:00
function cancelPoll(uint _idPoll)
onlyController
public
{
require(_idPoll < _polls.length);
Poll storage p = _polls[_idPoll];
require(p.endBlock < block.number);
2018-06-26 10:19:04 -04:00
p.canceled = true;
2018-06-26 14:44:45 -04:00
emit PollCanceled(_idPoll);
2018-06-26 10:19:04 -04:00
}
2018-06-26 14:44:45 -04:00
function canVote(uint _idPoll)
public
view
returns(bool)
{
if(_idPoll >= _polls.length) return false;
Poll storage p = _polls[_idPoll];
uint balance = MiniMeToken(p.token).balanceOf(msg.sender);
return block.number >= p.startBlock &&
block.number <= p.endBlock &&
!p.canceled &&
balance != 0;
}
2018-06-26 14:44:45 -04:00
function vote(uint _idPoll, bytes32 _ballot) public {
require(_idPoll < _polls.length);
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
Poll storage p = _polls[_idPoll];
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
require(block.number >= p.startBlock && block.number < p.endBlock && !p.canceled);
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
unvote(_idPoll);
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
uint amount = MiniMeToken(p.token).balanceOf(msg.sender);
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
require(amount != 0);
require(MiniMeToken(p.token).transferFrom(msg.sender, address(this), amount));
2018-06-26 10:19:04 -04:00
p.votes[msg.sender].ballot = _ballot;
p.votes[msg.sender].amount = amount;
p.voters++;
p.votersPerBallot[_ballot]++;
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
require(IPollContract(p.pollContract).deltaVote(int(amount), _ballot));
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
emit Vote(_idPoll, msg.sender, _ballot, amount);
2018-06-26 10:19:04 -04:00
}
2018-06-27 13:27:01 -04:00
function customVote(uint _idPoll, bytes32 _ballot, uint _amount) public {
require(_idPoll < _polls.length);
Poll storage p = _polls[_idPoll];
require(block.number >= p.startBlock && block.number < p.endBlock && !p.canceled);
unvote(_idPoll);
uint balance = MiniMeToken(p.token).balanceOf(msg.sender);
require(balance != 0 && balance >= _amount);
require(MiniMeToken(p.token).transferFrom(msg.sender, address(this), _amount));
p.votes[msg.sender].ballot = _ballot;
p.votes[msg.sender].amount = _amount;
p.voters++;
p.votersPerBallot[_ballot]++;
require(IPollContract(p.pollContract).deltaVote(int(_amount), _ballot));
emit Vote(_idPoll, msg.sender, _ballot, _amount);
}
2018-06-26 14:44:45 -04:00
function unvote(uint _idPoll) public {
require(_idPoll < _polls.length);
Poll storage p = _polls[_idPoll];
require(block.number >= p.startBlock && block.number < p.endBlock && !p.canceled);
2018-06-26 10:19:04 -04:00
uint amount = p.votes[msg.sender].amount;
bytes32 ballot = p.votes[msg.sender].ballot;
if (amount == 0) return;
2018-06-26 14:44:45 -04:00
require(IPollContract(p.pollContract).deltaVote(-int(amount), ballot));
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
p.votes[msg.sender].ballot = 0x00;
2018-06-26 10:19:04 -04:00
p.votes[msg.sender].amount = 0;
p.votersPerBallot[ballot]--;
p.voters--;
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
require(MiniMeToken(p.token).transferFrom(address(this), msg.sender, amount));
2018-06-26 10:19:04 -04:00
2018-06-26 14:44:45 -04:00
emit Unvote(_idPoll, msg.sender, ballot, amount);
2018-06-26 10:19:04 -04:00
}
// Constant Helper Function
2018-06-26 14:44:45 -04:00
function nPolls()
public
view
returns(uint)
{
2018-06-26 10:19:04 -04:00
return _polls.length;
}
2018-06-26 14:44:45 -04:00
function poll(uint _idPoll)
public
view
returns(
2018-06-26 10:19:04 -04:00
uint _startBlock,
uint _endBlock,
address _token,
address _pollContract,
bool _canceled,
bytes32 _pollType,
string _question,
bool _finalized,
uint _totalCensus,
uint _voters
2018-06-26 14:44:45 -04:00
)
{
require(_idPoll < _polls.length);
Poll storage p = _polls[_idPoll];
2018-06-26 10:19:04 -04:00
_startBlock = p.startBlock;
_endBlock = p.endBlock;
_token = p.token;
_pollContract = p.pollContract;
_canceled = p.canceled;
_pollType = IPollContract(p.pollContract).pollType();
2018-06-26 14:44:45 -04:00
_question = getString(p.pollContract, bytes4(keccak256("question()")));
_finalized = (!p.canceled) && (block.number >= _endBlock);
2018-06-26 10:19:04 -04:00
_totalCensus = MiniMeToken(p.token).totalSupply();
_voters = p.voters;
2018-06-26 10:19:04 -04:00
}
2018-06-26 14:44:45 -04:00
function getVote(uint _idPoll, address _voter)
public
view
returns (bytes32 _ballot, uint _amount)
{
require(_idPoll < _polls.length);
Poll storage p = _polls[_idPoll];
2018-06-26 10:19:04 -04:00
_ballot = p.votes[_voter].ballot;
_amount = p.votes[_voter].amount;
}
function getVotesByBallot(uint _idPoll, bytes32 _ballot)
2018-06-26 14:44:45 -04:00
public
view
returns(uint voters, uint votes)
{
require(_idPoll < _polls.length);
Poll storage p = _polls[_idPoll];
voters = p.votersPerBallot[_ballot];
votes = p.votersPerBallot[_ballot];
}
2018-06-26 14:44:45 -04:00
function proxyPayment(address )
payable
returns(bool) {
2018-06-26 10:19:04 -04:00
return false;
}
2018-06-26 14:44:45 -04:00
function onTransfer(address , address , uint )
public
pure
returns(bool)
{
2018-06-26 10:19:04 -04:00
return true;
}
2018-06-26 14:44:45 -04:00
function onApprove(address , address , uint )
public
pure
returns(bool) {
2018-06-26 10:19:04 -04:00
return true;
}
event Vote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
event Unvote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
event PollCanceled(uint indexed idPoll);
event PollCreated(uint indexed idPoll);
2018-06-26 10:19:04 -04:00
}