First test work commit, don't touch
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
|
||||
open Rte;
|
||||
|
||||
/* Contract type */
|
||||
module type Voting = {
|
||||
type state;
|
||||
type args = list(string);
|
||||
let stateRep : state_rep(state);
|
||||
|
||||
let init : args => state;
|
||||
let giveRightToVote : address => unit;
|
||||
let delegate : address => unit;
|
||||
let vote : int => unit;
|
||||
let winnerName : unit => string;
|
||||
let currentTally : unit => list((string, int));
|
||||
};
|
||||
|
||||
/* Contract implementation */
|
||||
module Voting : Voting = {
|
||||
|
||||
/* Not so nice */
|
||||
module AddrKey = { type t = address; let compare = Pervasives.compare };
|
||||
module AddrMap = Map.Make(AddrKey);
|
||||
type addr_map('a) = AddrMap.t('a);
|
||||
|
||||
/* Types */
|
||||
|
||||
type proposal =
|
||||
{ name: string
|
||||
, mutable voteCount: uint
|
||||
};
|
||||
|
||||
type voter =
|
||||
{ mutable weight: int
|
||||
, mutable delegate: option(address)
|
||||
, mutable vote: option(int)
|
||||
};
|
||||
|
||||
type state =
|
||||
{ chairPerson: address
|
||||
, mutable voters: addr_map(voter)
|
||||
, proposals: list(proposal)
|
||||
};
|
||||
|
||||
/* Initialization */
|
||||
type args = list(string);
|
||||
let init(proposalNames: args): state =
|
||||
{ chairPerson: caller(),
|
||||
voters: AddrMap.empty,
|
||||
proposals: List.map((name) => {name: name, voteCount: 0}, proposalNames)
|
||||
};
|
||||
|
||||
/* Boilerplate */
|
||||
let stateRep = newStateRep();
|
||||
let state() = getState(stateRep);
|
||||
|
||||
let initVoter() = { weight: 1, delegate: None, vote: None };
|
||||
|
||||
let giveRightToVote(voter: address) = {
|
||||
require(caller() == state().chairPerson);
|
||||
require(!AddrMap.mem(voter, state().voters));
|
||||
state().voters = AddrMap.add(voter, initVoter(), state().voters);
|
||||
()
|
||||
};
|
||||
|
||||
let rec delegateChain(delegate: address) = {
|
||||
require(delegate != caller()); /* Delegation loop! */
|
||||
let voter = AddrMap.find(delegate, state().voters);
|
||||
switch(voter.delegate) {
|
||||
| None => delegate;
|
||||
| Some(d) => delegateChain(d)
|
||||
}
|
||||
};
|
||||
|
||||
let addVote(candidate, weight) = {
|
||||
let proposal = List.nth(state().proposals, candidate);
|
||||
proposal.voteCount = proposal.voteCount + weight;
|
||||
};
|
||||
|
||||
let delegateVote(delegateTo: address, weight: uint) = {
|
||||
let voter = AddrMap.find(delegateTo, state().voters);
|
||||
switch(voter.vote) {
|
||||
| Some(vote) => addVote(vote, weight)
|
||||
| None => voter.weight = voter.weight + weight
|
||||
}
|
||||
};
|
||||
|
||||
let delegate(delegateTo: address) = {
|
||||
require(delegateTo != caller());
|
||||
let voter = AddrMap.find(caller(), state().voters);
|
||||
require(voter.vote == None);
|
||||
let finalDelegate = delegateChain(delegateTo);
|
||||
voter.vote = Some(0); /* Hm... */
|
||||
voter.delegate = Some(finalDelegate);
|
||||
delegateVote(finalDelegate, voter.weight)
|
||||
};
|
||||
|
||||
let vote(candidate: uint) = {
|
||||
let voter = AddrMap.find(caller(), state().voters);
|
||||
require(voter.vote == None);
|
||||
voter.vote = Some(candidate);
|
||||
addVote(candidate, voter.weight);
|
||||
};
|
||||
|
||||
let rec winningProposal'(current, rest) =
|
||||
switch(rest) {
|
||||
| [] => current;
|
||||
| [p, ...ps] => winningProposal'(p.voteCount > current.voteCount ? p : current, ps)
|
||||
};
|
||||
|
||||
/* const */
|
||||
let winningProposal() : proposal = {
|
||||
switch(state().proposals) {
|
||||
| [] => abort()
|
||||
| [p, ...ps] => winningProposal'(p, ps)
|
||||
}
|
||||
};
|
||||
|
||||
/* const */
|
||||
let winnerName() = winningProposal().name;
|
||||
|
||||
/* const */
|
||||
let currentTally() =
|
||||
List.map((p) => (p.name, p.voteCount), state().proposals);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user