Tabulation and determining final result

This commit is contained in:
Richard Ramos 2018-06-25 14:35:16 -04:00
parent 93d96c07da
commit 9f122d36ff
2 changed files with 92 additions and 30 deletions

View File

@ -11,7 +11,10 @@ class Voting extends Component {
super(props); super(props);
this.state = { this.state = {
decision: 0, decision: 0,
finalResult: null finalResult: null,
data: null,
tabulationAvailable: false,
votingAvailable: false
}; };
} }
@ -21,23 +24,26 @@ class Voting extends Component {
}); });
} }
componentDidMount(){
__embarkContext.execWhenReady(async () => {
this._loadProposalData();
});
}
async _loadProposalData() { async _loadProposalData() {
ProposalManager.options.address = await ProposalCuration.methods.proposalManager().call(); ProposalManager.options.address = await ProposalCuration.methods.proposalManager().call();
let _proposal = await ProposalManager.methods.getVoteInfo(this.props.proposalId, web3.eth.defaultAccount).call(); const _votingInfo = await ProposalManager.methods.getVoteInfo(this.props.proposalId, web3.eth.defaultAccount).call();
let blockNum = await web3.eth.getBlockNumber(); const _blockNum = await web3.eth.getBlockNumber();
let _data = await ProposalManager.methods.proposals(this.props.proposalId).call(); const _data = await ProposalManager.methods.proposals(this.props.proposalId).call();
const _votingAvailable = await ProposalManager.methods.isVotingAvailable(this.props.proposalId).call();
const _tabulationAvailable = await ProposalManager.methods.isTabulationAvailable(this.props.proposalId).call();
const _voteTabulated = await ProposalManager.methods.isDelegatorVoteTabulated(this.props.proposalId, web3.eth.defaultAccount).call();
const _canCalculateFinalResult = await ProposalManager.methods.canCalculateFinalResult(this.props.proposalId).call();
this.setState({ this.setState({
data: _data, data: _data,
decision: _proposal.vote, decision: _votingInfo.vote,
block: blockNum, block: _blockNum,
finalResult: _data.result finalResult: _data.result,
votingAvailable: _votingAvailable,
tabulationAvailable: _tabulationAvailable,
canCalculateFinalResult: _canCalculateFinalResult,
voteTabulated: _voteTabulated
}); });
} }
@ -45,15 +51,26 @@ class Voting extends Component {
e.preventDefault(); e.preventDefault();
let receipt = await ProposalManager.methods.finalResult(this.props.proposalId) let receipt = await ProposalManager.methods.finalResult(this.props.proposalId)
.send({from: web3.eth.defaultAccount}); .send({from: web3.eth.defaultAccount, gasLimit: 1000000});
if(receipt.status == '0x1'){ if(receipt.status == '0x1'){
this.setState({ this.setState({
finalResult: receipt.events.ProposalResult.returnValues.finalResult finalResult: receipt.events.ProposalResult.returnValues.finalResult,
finalResultAvailable: false
}); });
} }
} }
async tabulateVote(e){
e.preventDefault();
const receipt = await ProposalManager.methods.tabulateVote(this.props.proposalId, web3.eth.defaultAccount)
.send({from: web3.eth.defaultAccount, gasLimit: 1000000});
// TODO: handle error
this._loadProposalData();
}
async handleClick(e, vote){ async handleClick(e, vote){
e.preventDefault(); e.preventDefault();
@ -63,16 +80,25 @@ class Voting extends Component {
else else
choice = 1; choice = 1;
let proposal = this.props.proposalId; const proposal = this.props.proposalId;
let receipt = await ProposalManager.methods.voteProposal(this.props.proposalId, choice) const receipt = await ProposalManager.methods.voteProposal(this.props.proposalId, choice)
.send({from: web3.eth.defaultAccount}); .send({from: web3.eth.defaultAccount});
let blockNum = await web3.eth.getBlockNumber();
const _votingAvailable = await ProposalManager.methods.isVotingAvailable(this.props.proposalId).call();
const _tabulationAvailable = await ProposalManager.methods.isTabulationAvailable(this.props.proposalId).call();
const _voteTabulated = await ProposalManager.methods.isDelegatorVoteTabulated(this.props.proposalId, web3.eth.defaultAccount).call();
const _canCalculateFinalResult = await ProposalManager.methods.canCalculateFinalResult(this.props.proposalId).call();
const blockNum = await web3.eth.getBlockNumber();
if(receipt.status == '0x1'){ if(receipt.status == '0x1'){
this.setState({ this.setState({
decision: choice, decision: choice,
block: blockNum block: blockNum,
votingAvailable: _votingAvailable,
tabulationAvailable: _tabulationAvailable,
finalResultAvailable: _canCalculateFinalResult,
voteTabulated: _voteTabulated
}); });
} }
// TODO: handle error // TODO: handle error
@ -87,7 +113,7 @@ class Voting extends Component {
} }
{ {
this.state.data != null && this.state.block < this.state.data.voteBlockEnd ? this.state.data != null && this.state.votingAvailable ?
<Fragment> <Fragment>
<Button onClick={(e) => this.handleClick(e, 'APPROVE') }>Approve</Button> <Button onClick={(e) => this.handleClick(e, 'APPROVE') }>Approve</Button>
<Button onClick={(e) => this.handleClick(e, 'REJECT') }>Reject</Button> <Button onClick={(e) => this.handleClick(e, 'REJECT') }>Reject</Button>
@ -96,11 +122,19 @@ class Voting extends Component {
} }
{ {
this.state.data != null && this.state.block >= this.state.data.voteBlockEnd && this.state.data.result == 0 ? this.state.data != null && this.state.tabulationAvailable && !this.state.voteTabulated ?
<Button onClick={(e) => this.determineFinalResult(e) }>Determine final result</Button> <Button onClick={(e) => this.tabulateVote(e) }>Tabulate your vote</Button>
: '' : ''
} }
{
this.state.finalResultAvailable ?
<Button onClick={(e) => this.determineFinalResult(e) }>Determine final result</Button>
: !this.state.tabulationAvailable && !this.state.voteTabulated ?
<p>Final results aren't available yet</p> : ''
}
{ this.state.data != null ? { this.state.data != null ?
<ul> <ul>
<li>Voting ends on block: {this.state.data.voteBlockEnd }</li> <li>Voting ends on block: {this.state.data.voteBlockEnd }</li>

View File

@ -51,7 +51,7 @@ contract ProposalManager is Controlled {
{ {
trustNet = _trustNet; trustNet = _trustNet;
token = _token; token = _token;
tabulationBlockDelay = 7 days; tabulationBlockDelay = 10 seconds; // TODO: set 7 days
quorumPercentage = 50; quorumPercentage = 50;
} }
@ -106,8 +106,10 @@ contract ProposalManager is Controlled {
Proposal storage proposal = proposals[_proposalId]; Proposal storage proposal = proposals[_proposalId];
require(block.number > proposal.voteBlockEnd); require(block.number > proposal.voteBlockEnd);
require(!proposal.tabulated[_delegator]); require(!proposal.tabulated[_delegator]);
proposal.tabulated[_delegator] = true;
Vote _vote = proposal.voteMap[_delegator]; Vote _vote = proposal.voteMap[_delegator];
if(_vote == Vote.Null) { if(_vote == Vote.Null) {
address delegate = trustNet.getVoteDelegation(proposal.topic).delegationOfAt(_delegator, proposal.voteBlockEnd); address delegate = trustNet.getVoteDelegation(proposal.topic).delegationOfAt(_delegator, proposal.voteBlockEnd);
_vote = proposal.voteMap[delegate]; _vote = proposal.voteMap[delegate];
@ -116,6 +118,8 @@ contract ProposalManager is Controlled {
if (_vote == Vote.Reject || _vote == Vote.Approve) { if (_vote == Vote.Reject || _vote == Vote.Approve) {
proposal.results[uint8(_vote)] += token.balanceOfAt(_delegator, proposal.voteBlockEnd); proposal.results[uint8(_vote)] += token.balanceOfAt(_delegator, proposal.voteBlockEnd);
} }
proposal.tabulated[_delegator] = true;
proposal.lastTabulationTimestamp = block.timestamp; proposal.lastTabulationTimestamp = block.timestamp;
} }
@ -131,6 +135,7 @@ contract ProposalManager is Controlled {
public public
{ {
Proposal storage proposal = proposals[_proposalId]; Proposal storage proposal = proposals[_proposalId];
require(block.number > proposal.voteBlockEnd);
require(proposal.lastTabulationTimestamp + tabulationBlockDelay < block.timestamp); require(proposal.lastTabulationTimestamp + tabulationBlockDelay < block.timestamp);
require(proposal.result == Vote.Null); require(proposal.result == Vote.Null);
uint256 totalTokens = token.totalSupplyAt(proposal.voteBlockEnd); uint256 totalTokens = token.totalSupplyAt(proposal.voteBlockEnd);
@ -194,7 +199,30 @@ contract ProposalManager is Controlled {
function isVotingAvailable(uint _proposalId) public view returns (bool){ function isVotingAvailable(uint _proposalId) public view returns (bool){
Proposal memory p = proposals[_proposalId]; Proposal memory p = proposals[_proposalId];
return p.voteBlockEnd > block.number && p.result == Vote.Null; return p.voteBlockEnd > block.number && p.result == Vote.Null && p.lastTabulationTimestamp == 0;
}
function canCalculateFinalResult(uint _proposalId) public view returns (bool){
Proposal memory proposal = proposals[_proposalId];
return proposal.lastTabulationTimestamp + tabulationBlockDelay < block.timestamp &&
proposal.result == Vote.Null &&
block.number > proposal.voteBlockEnd;
}
function isTabulationAvailable(uint _proposalId) public view returns (bool){
Proposal memory p = proposals[_proposalId];
return !isVotingAvailable(_proposalId) &&
block.timestamp > p.lastTabulationTimestamp + tabulationBlockDelay;
}
function isDelegatorVoteTabulated(uint _proposalId, address _delegator)
public
view
returns (bool)
{
Proposal storage proposal = proposals[_proposalId];
return proposal.tabulated[_delegator];
} }
function getVoteInfo(uint _proposalId, address voter) function getVoteInfo(uint _proposalId, address voter)