Currently tests are not repeatable executable in the truffle develop
, but work well with truffle test
The purpose of this contracts is to allow to vote with tokens on proposals and assign budgets to it.
We are basing our work heavily on the OpenZeppelin Solidity library. On top of a vanilla Crowdsale we need the ability to keep Ether in Escrow and perform a proposal-vote-payout mechanism. e.g.:
- Crowdsale makes 10k ETH until endTime
- After endTime owner makes a proposal to payOut themselves 1k ETH (they also pass a URL and a hash along with the proposal for explanatory purposes)
- All token hodlers have 2 weeks to vote yes or no on the proposal
- By the end of the 2 week period the result is assessed, if a simple majority votes in favor the amount will be paid out to the beneficiary account specified in the proposal
- If the vote turns out as "no" then there is a 20 day lock up period in which the owner can not make new proposals to prevent spamming by owner.
Smart contracts have intrinsically:
- highest security requirements
- high requirements on gas operating costs. In fact the fluctuating gas prices impose themselfs a risk of service operation. Derived from the functional requirements no specific Quality Attributes arise.
- Open Closed Principle: Open for extension, closed for modification. Because security audits are costly and time-consuming, because modification of existing code is more risky than plugging in different modules on well defined interfaces, we endorse this paradigm
- Build on Standards: Reuse existing proven frameworks and libraries when possible (mostly Zeppelin)
LoggedTokenCrowdsale extend Zeppelins Crowdsale and overrides createTokenContract() so that we can use our LoggedToken. LoggedToken extends MintableToken with a feature copied by MiniMeToken: balanceOfAt(address _owner, uint _blockNumber).
This feature is used to snapshot the balance of tokens at proposal creation time. Only those addresses who hold tokens at the given blockheight can then vote on the proposal. VotingStrategy encapsulates the algorithm to decide the outcome of a Proposal ballot. This would make it easy to change the logic for the next foreseable step: requiring a minimal voting threshold (i.e. a Quorum)
First the BudgetWallet contracts must be created and injected in the constructor of the LoggedTokenCrowdsale. Only the address of the Wallet is required as the Crowdsale must only send funds to that address without caring if its a contract or an Externally Owned Address (EOA).During construction time, the LoggedTokenCrowdsale creates an instance of LoggedToken. This in inherited functionality enforced by Zeppelin's Crowdsale contract. Now the constructor of the voting system BudgetProposalVoting is called with both the token and the wallet as parameter. Finally the ownership of the BudgetWallet is handed over to the voting system, so that only this contract can withdraw funds.
In order to hinder the voting system to issue proposals before the crowdsale endet, it has always to check hasEnded()
of the LoggedTokenCrowdsale or better mintFinished of the MintableToken not introducing a dependency to the Crowdsale contract.
For now the preconditions for creating a proposals are:
- crowdsale ended
- owner is proposing
- no other proposal is currently voted for or it's budget not redeemed This allows us to use a simple struct of one active proposals, while logging all proposals as EVM Events instead of storing a history of proposals.
- owner has collected funds of the last proposal if it was successful.
It is important that new proposals remember the blockheight of their creation so that we can retrieve the balance of tokens at creation time borrowing from MiniMeToken's
balanceOfAt()
logic.
Voting starts after the owner successfully created a new Proposal. Voting rule is:
- Each tokenholder at proposal time blockheight can vote with the weight of his token.
- as long as the voting period is not over
- he can do this only once per proposal
Following conditions must hold
- only Owner can redeem
- voting period must be over to redeem
- voting must have been successful,
countYesVotes > countNoVotes
, to redeem - If not redeemed, owner can't issue a new proposal
Not comprehensive assesment of security issues
- Front running - a informed attacker can buy many tokens before a specific proposal will be made. He then can use this weight to nudge the outcome towards his advantage.
Some suggestions what to do next:
- Develop a EIP standard for token voting
- Allow for multiple proposals in parallel
- Allow for different amounts of budget per proposal