Created test case to demonstrate how to use contracts

This commit is contained in:
Richard Ramos 2018-06-26 13:34:24 -04:00
parent a712cece85
commit 3759522633
6 changed files with 227 additions and 14 deletions

7
config/namesystem.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
default: {
enabled: false,
available_providers: ["ens"],
provider: "ens"
}
};

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11; pragma solidity ^0.4.23;
import "../common/Controlled.sol"; import "../common/Controlled.sol";
import "./LowLevelStringManipulator.sol"; import "./LowLevelStringManipulator.sol";
@ -27,6 +27,8 @@ contract PollManager is LowLevelStringManipulator, Controlled {
address token; address token;
address pollContract; address pollContract;
bool canceled; bool canceled;
uint voters;
mapping(bytes32 => uint) votersPerBallot;
mapping(address => VoteLog) votes; mapping(address => VoteLog) votes;
} }
@ -62,10 +64,10 @@ contract PollManager is LowLevelStringManipulator, Controlled {
Poll p = _polls[ _idPoll ]; Poll p = _polls[ _idPoll ];
p.startBlock = _startBlock; p.startBlock = _startBlock;
p.endBlock = _endBlock; p.endBlock = _endBlock;
p.voters = 0;
var (name, symbol) = getTokenNameSymbol(address(token));
var (name,symbol) = getTokenNameSymbol(address(token)); string memory proposalName = strConcat(name, "_", uint2str(_idPoll));
string memory proposalName = strConcat(name , "_", uint2str(_idPoll));
string memory proposalSymbol = strConcat(symbol, "_", uint2str(_idPoll)); string memory proposalSymbol = strConcat(symbol, "_", uint2str(_idPoll));
p.token = tokenFactory.createCloneToken( p.token = tokenFactory.createCloneToken(
@ -80,6 +82,8 @@ contract PollManager is LowLevelStringManipulator, Controlled {
p.pollContract = IPollFactory(_pollFactory).create(_description); p.pollContract = IPollFactory(_pollFactory).create(_description);
if (p.pollContract == 0) throw; if (p.pollContract == 0) throw;
emit PollCreated(_idPoll);
} }
function cancelPoll(uint _idPoll) onlyController { function cancelPoll(uint _idPoll) onlyController {
@ -90,6 +94,18 @@ contract PollManager is LowLevelStringManipulator, Controlled {
PollCanceled(_idPoll); PollCanceled(_idPoll);
} }
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;
}
function vote(uint _idPoll, bytes32 _ballot) { function vote(uint _idPoll, bytes32 _ballot) {
if (_idPoll >= _polls.length) throw; if (_idPoll >= _polls.length) throw;
Poll p = _polls[_idPoll]; Poll p = _polls[_idPoll];
@ -110,6 +126,10 @@ contract PollManager is LowLevelStringManipulator, Controlled {
p.votes[msg.sender].ballot = _ballot; p.votes[msg.sender].ballot = _ballot;
p.votes[msg.sender].amount = amount; p.votes[msg.sender].amount = amount;
p.voters++;
p.votersPerBallot[_ballot]++;
if (!IPollContract(p.pollContract).deltaVote(int(amount), _ballot)) throw; if (!IPollContract(p.pollContract).deltaVote(int(amount), _ballot)) throw;
@ -129,9 +149,11 @@ contract PollManager is LowLevelStringManipulator, Controlled {
if (!IPollContract(p.pollContract).deltaVote(-int(amount), ballot)) throw; if (!IPollContract(p.pollContract).deltaVote(-int(amount), ballot)) throw;
p.votes[msg.sender].ballot = 0; p.votes[msg.sender].ballot = 0;
p.votes[msg.sender].amount = 0; p.votes[msg.sender].amount = 0;
p.votersPerBallot[ballot]--;
p.voters--;
// enableTransfers = true; // enableTransfers = true;
if (!MiniMeToken(p.token).transferFrom(address(this), msg.sender, amount)) throw; if (!MiniMeToken(p.token).transferFrom(address(this), msg.sender, amount)) throw;
@ -155,7 +177,8 @@ contract PollManager is LowLevelStringManipulator, Controlled {
bytes32 _pollType, bytes32 _pollType,
string _question, string _question,
bool _finalized, bool _finalized,
uint _totalCensus uint _totalCensus,
uint _voters
) { ) {
if (_idPoll >= _polls.length) throw; if (_idPoll >= _polls.length) throw;
Poll p = _polls[_idPoll]; Poll p = _polls[_idPoll];
@ -168,6 +191,7 @@ contract PollManager is LowLevelStringManipulator, Controlled {
_question = getString(p.pollContract, bytes4(sha3("question()"))); _question = getString(p.pollContract, bytes4(sha3("question()")));
_finalized = (!p.canceled) && (getBlockNumber() >= _endBlock); _finalized = (!p.canceled) && (getBlockNumber() >= _endBlock);
_totalCensus = MiniMeToken(p.token).totalSupply(); _totalCensus = MiniMeToken(p.token).totalSupply();
_voters = p.voters;
} }
function getVote(uint _idPoll, address _voter) constant returns (bytes32 _ballot, uint _amount) { function getVote(uint _idPoll, address _voter) constant returns (bytes32 _ballot, uint _amount) {
@ -178,6 +202,16 @@ contract PollManager is LowLevelStringManipulator, Controlled {
_amount = p.votes[_voter].amount; _amount = p.votes[_voter].amount;
} }
function getVotesByBallot(uint _idPoll, bytes32 _ballot)
public view returns(uint voters, uint votes) {
if (_idPoll >= _polls.length) throw;
Poll storage p = _polls[_idPoll];
voters = p.votersPerBallot[_ballot];
votes = p.votersPerBallot[_ballot];
}
function proxyPayment(address ) payable returns(bool) { function proxyPayment(address ) payable returns(bool) {
return false; return false;
} }
@ -199,6 +233,7 @@ contract PollManager is LowLevelStringManipulator, Controlled {
event Vote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount); 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 Unvote(uint indexed idPoll, address indexed _voter, bytes32 ballot, uint amount);
event PollCanceled(uint indexed idPoll); event PollCanceled(uint indexed idPoll);
event PollCreated(uint indexed idPoll);

View File

@ -26,7 +26,7 @@ contract SingleChoice is Controlled {
using RLP for bytes; using RLP for bytes;
string public question; string public question;
string[] public options; string[] public choices;
int[] public result; int[] public result;
bytes32 uid; bytes32 uid;
@ -50,11 +50,11 @@ contract SingleChoice is Controlled {
var itrOptions = itmOptions.iterator(); var itrOptions = itmOptions.iterator();
while(itrOptions.hasNext()) { while(itrOptions.hasNext()) {
options.length++; choices.length++;
options[options.length-1] = itrOptions.next().toAscii(); choices[choices.length-1] = itrOptions.next().toAscii();
} }
result.length = options.length; result.length = choices.length;
} }
function pollType() constant returns (bytes32) { function pollType() constant returns (bytes32) {
@ -63,7 +63,7 @@ contract SingleChoice is Controlled {
function isValid(bytes32 _ballot) constant returns(bool) { function isValid(bytes32 _ballot) constant returns(bool) {
uint v = uint(_ballot) / (2**248); uint v = uint(_ballot) / (2**248);
if (v>=options.length) return false; if (v>=choices.length) return false;
if (getBallot(v) != _ballot) return false; if (getBallot(v) != _ballot) return false;
return true; return true;
} }
@ -76,7 +76,7 @@ contract SingleChoice is Controlled {
} }
function nOptions() constant returns(uint) { function nOptions() constant returns(uint) {
return options.length; return choices.length;
} }
function getBallot(uint _option) constant returns(bytes32) { function getBallot(uint _option) constant returns(bytes32) {

View File

@ -1,8 +1,9 @@
pragma solidity ^0.4.6; pragma solidity ^0.4.6;
import "./SingleChoice.sol"; import "./SingleChoice.sol";
import "./PollManager.sol";
contract SingleChoiceFactory { contract SingleChoiceFactory is IPollFactory {
uint salt; uint salt;
function create(bytes _description) returns(address) { function create(bytes _description) returns(address) {
salt++; salt++;

View File

@ -22,10 +22,12 @@
"bignumber.js": "^5.0.0", "bignumber.js": "^5.0.0",
"formik": "^0.11.11", "formik": "^0.11.11",
"jquery": "^3.3.1", "jquery": "^3.3.1",
"lodash": "^4.17.10",
"react": "^16.3.2", "react": "^16.3.2",
"react-blockies": "^1.3.0", "react-blockies": "^1.3.0",
"react-bootstrap": "^0.32.1", "react-bootstrap": "^0.32.1",
"react-dom": "^16.3.2", "react-dom": "^16.3.2",
"react-toggle": "^4.0.2" "react-toggle": "^4.0.2",
"rlp": "^2.0.0"
} }
} }

168
test/votingdapp.js Normal file
View File

@ -0,0 +1,168 @@
const utils = require('../utils/testUtils')
const assert = require('assert');
const SingleChoice = require('Embark/contracts/SingleChoice');
const BN = web3.utils.BN;
var _ = require('lodash');
var rlp = require('rlp');
config({
contracts: {
"MiniMeTokenFactory": {
"gasLimit": 4000000
},
"MiniMeToken": {
"deploy": false,
},
"SNT":{
"instanceOf": "MiniMeToken",
"args": [
"$MiniMeTokenFactory",
utils.zeroAddress,
0,
"TestMiniMeToken",
18,
"TST",
true
],
"gasLimit": 4000000
},
"PollManager": {
"deploy": true,
"args": ["$MiniMeTokenFactory", "$SNT"]
},
"SingleChoiceFactory": {
"deploy": true
}
}
});
singleChoiceDef = (question, options) => {
var d = [
new Buffer(question),
_.map(options, function(o) {
return new Buffer(o);
})
];
var b= rlp.encode(d);
var rlpDefinition = '0x' + b.toString('hex');
return rlpDefinition;
}
describe("VotingDapp", function () {
this.timeout(0);
let accounts;
before(function(done) {
web3.eth.getAccounts().then((acc) => {
accounts = acc;
return SNT.methods.generateTokens(accounts[0], 123456).send()
}).then((receipt) => {
return SNT.methods.generateTokens(accounts[1], 789012).send()
}).then((receipt) => {
return SNT.methods.generateTokens(accounts[2], 345678).send()
}).then((receipt) => {
return SNT.methods.generateTokens(accounts[3], 901234).send()
}).then((receipt) => {
done();
});
});
it("Test", async () => {
const blockNumber = await web3.eth.getBlockNumber();
const question = singleChoiceDef("Move from Slack to Status Desktop", [ "Yes", "No" ]);
let receipt;
// ===================================================
// Creating a proposal without holding SNT SHOULD FAIL!
try {
receipt = await PollManager.methods.addPoll(
blockNumber,
blockNumber + 10,
SingleChoiceFactory.options.address,
question)
.send({from: accounts[8]});
assert.fail('should have reverted before');
} catch(error) {
utils.assertJump(error);
}
// ===================================================
// Creating a proposal as a SNT holder
receipt = await PollManager.methods.addPoll(
blockNumber,
blockNumber + 10,
SingleChoiceFactory.options.address,
question)
.send({from: accounts[0]});
assert.equal(!!receipt.events.PollCreated, true, "PollCreated not triggered");
const pollId = receipt.events.PollCreated.returnValues.idPoll;
let poll = await PollManager.methods.poll(pollId).call();
SingleChoice.options.address = poll._pollContract;
const pollContract = SingleChoice;
// Options are represented as a hex value
const Yes = await SingleChoice.methods.getBallot(0).call();
const No = await SingleChoice.methods.getBallot(1).call();
// ===================================================
// Determining if I can vote por a proposal
let canVote = await PollManager.methods.canVote(pollId).call({from: accounts[0]});
assert.equal(canVote, true, "User should be able to vote");
// ===================================================
// Voting
receipt = await PollManager.methods.vote(pollId, Yes).send({from: accounts[0]});
assert.equal(!!receipt.events.Vote, true, "Vote not triggered");
// ===================================================
// Getting what option the voter selected
let myVote = await PollManager.methods.getVote(pollId, accounts[0]).call();
assert.equal(myVote._ballot, Yes, "Vote is different from selected");
// ===================================================
// Voting when you're not a SNT holder SHOULD FAIL!
try {
receipt = await PollManager.methods.vote(pollId, Yes)
.send({from: accounts[8]});
assert.fail('should have reverted before');
} catch(error) {
utils.assertJump(error);
}
// ===================================================
// Getting proposal information
poll = await PollManager.methods.poll(pollId).call();
let votersByBallotYES = await PollManager.methods.getVotesByBallot(pollId, Yes).call();
let tokenVotesByBallotYES = await pollContract.methods.result(0).call(); // 0 == Yes (because it is the initial option )
// console.dir(poll); // Will contain state of the poll
// console.log(tokenVotesByBallotYES); // Contains how many votes has a ballot
// console.log(votersByBallotYES); // Contains how many voters voted for that option
// ===================================================
// Unvote
receipt = await PollManager.methods.unvote(pollId).send({from: accounts[0]});
assert.equal(!!receipt.events.Unvote, true, "Unvote not triggered");
});
});