Repository navigation
Token and hybrid voting #90
Description
9.3.2 Token weighted voting
Unlike with reputation, we do not have the ability to ‘freeze’ the token distribution when a vote starts. While this is effectively possible with something like the MiniMe token [8], we envision token-weighted votes will still be regular enough within a Colony that we do not wish to burden users with the gas costs of deploying a new contract every time.
When conducting a token weighted vote, steps must be taken to ensure that tokens cannot be
used to vote multiple times. In the case of “The DAO”, once a user had voted their tokens were locked until the vote completed. This introduced peculiar incentives to delay voting until as late as possible to avoid locking tokens unnecessarily. Our locking scheme avoids such skewed incentives. Instead, once a vote enters the reveal phase, any user who has voted on that vote will find themselves unable to see tokens sent to them, or be able to send tokens themselves — their token balance has become locked. To unlock their token balance, users only have to reveal the vote they cast for any polls that have entered the reveal phase — something they can do at any time. Once their tokens are unlocked, any tokens they have notionally received since their tokens became locked are added to their balance.
It is possible to achieve this locking in constant gas by storing all submitted secrets for votes in a sorted linked list indexed by close_time. If the first key in this linked list is earlier than now when a user sends or would receive funds, then they find their tokens locked. Revealing a vote causes the key to be deleted (if the user has no other votes submitted for polls that closed at the same time). This will unlock the tokens so long as the next key in the list is a timestamp in the future. A more detailed description of our implementation can be found on the Colony blog [9].
Insertion into this structure can also be done in constant gas if the client supplies the correct insertion location, which can be checked efficiently on-chain, rather than searching for the correct location to insert new items.
9.3.3 Hybrid voting
A hybrid vote would allow both reputation holders and token holders to vote on a decision. We envision such a vote being used when the action being voted on would potentially have a sizeable impact on both reputation holders and token holders. This would include altering the supply of the colony tokens beyond the parameters already agreed (see Section 5.1) or when deciding whether to execute an arbitrary transaction (see Section 11.4).
In order for a proposal to successfully pass through a hybrid vote, both the reputation holders and the token holders must have reached quorum, and a majority of both reputation and token holders who vote must agree that the change should be enacted.
Activity
elenadimitrova commentedon Feb 11, 2018
This is already implemented in https://github.com/JoinColony/colonyNetwork/tree/feature/token-weighted-voting branch but that is well out of date with
developas it uses theEterenalStorage-contract and libraries upgrade approach rather thanEtherRouter.It is however well documented functionality presented at devcon2 and the 3-part blog series and so it makes a good first issue for contributors.
mametrine commentedon Aug 28, 2018
I'd like to study your blogs and return to this issue. I see, for instance, VotingLibrary in the old branch. Is this where I get most/some of the functionality?
elenadimitrova commentedon Aug 28, 2018
Yes @markhainesii . You can compare the changes there to
masterasdevelopis based on the new upgrade model using delegate proxies a.k.a.EtherRouterwhereasmasteris still on the simplerEthernalStoragepattern master...feature/token-weighted-votingmametrine commentedon Aug 29, 2018
@elenadimitrova I have a general idea now and a few cursory points about the old branch to start:
elenadimitrova commentedon Aug 30, 2018
@markhainesii sounds very much like you're on the right track! On your questions respectively:
EtherRouterhas to be followed here as we want both upgradability and gas efficiency in the implementationTokenLockinghas been designed for reuse indeed!mametrine commentedon Aug 30, 2018
Great, thanks for clarifying. I'm interested in spending some time on this. Do I need to be assigned at this stage?
elenadimitrova commentedon Aug 30, 2018
Great. Not for now Mark. This conversation is sufficient for other collaborators to understand you're actively working on it. Any questions or if something blocks you, let us know here or Gitter
mametrine commentedon Sep 6, 2018
I'm looking at the
TokenLockingcontract and the function:where is the address for
_coloyNetworkcoming from? Is it normally passed during migration?elenadimitrova commentedon Sep 6, 2018
Indeed we wire that up in https://github.com/JoinColony/colonyNetwork/blob/develop/migrations/5_setup_token_locking.js migrations script
mametrine commentedon Sep 7, 2018
Relating to the proxy pattern: do all new "logic" contracts require address setter functions added to ColonyNetwork.sol? Then
setResolver()is passed these addresses? I'm trying to follow the order of things!elenadimitrova commentedon Sep 9, 2018
setResolveris only called once on the respectiveEtherRouterso the latter knows where to lookup incoming function signatures (that is in theResolverinstance). To get new logic contract functions registered properly we expose their public functions through the corresponding interface contract e.g.IColonyNetwork,IColonyetc. Then the script here registers all that in the resolver https://github.com/JoinColony/colonyNetwork/blob/develop/helpers/upgradable-contracts.js#L60Not sure I answered your question though..
9 remaining items
elenadimitrova commentedon Sep 18, 2018
I can't think of anything but the token locking which needs to reuse the one we've already implemented. Although it has been two years after we wrote it and I'm pretty sure in the course of implementation there maybe changes needed.
mametrine commentedon Sep 25, 2018
Going on the struct idea in previous comments, this old code will not be compatible with a mapping to struct type:
var pollOptionCount = EternalStorage(_storageContract).getUIntValue(keccak256("Poll", pollId, "OptionsCount"));So if it's the
uint256value being assigned topollOptionCountI'm hoping it will be safe to change this to:uint256 pollOptionCount = option[keccak256(abi.encodePacked("Poll", pollId, "OptionsCount"))].pollOptionCount;elenadimitrova commentedon Sep 26, 2018
Bear in mind that the
EternalStoragedesign was made to ensure mapping keys are unique, hence the long key"Poll", pollId, "OptionsCount"...being hashed. You don't have to do any of that in theEtherRouterand can just mapuint256 -> Pollmametrine commentedon Sep 26, 2018
ok, that will look a lot nicer as well. So I don't go too far, I have a Gist showing a concept for this. Is it similar to what you are expecting? https://gist.github.com/markhainesii/f06ad9f928d554aead30fc1ada53042b
elenadimitrova commentedon Sep 26, 2018
I don't know what storage will end up looking like but this seems like a good enough starting point. I expect there will be further normalization of the storage design needed once you start refactoring.
mametrine commentedon Oct 3, 2018
Does a linked list have to be at least two polls: one zero poll and one real poll so as to keep the "closed" relationship:
prevTimestamp>prevPollId>nextTimestamp>nextPollId?elenadimitrova commentedon Oct 3, 2018
Yes exactly @markhainesii
mametrine commentedon Oct 4, 2018
Great. And I know it's not necessary this time, but how should I interpret mapping keys like
"Voting", userAddress, prevTimestamp, "secrets", zeroUint, "nextPollId"so I can create new struct variables?elenadimitrova commentedon Oct 5, 2018
I'm not sure I understand completely but basically yes, there will likely need to be a struct defined containing some of these properties. Also as a general comment, it might be best to get a branch in so we can have a look at actual implementation changes.
[-]Token weighted voting[/-][+]Token and hybrid voting[/+]