Skip to content

Instantly share code, notes, and snippets.

@MidnightLightning
Last active May 11, 2021 16:51
Show Gist options
  • Select an option

  • Save MidnightLightning/d3791c03c9fcdf3c2d935fcc8ea720ab to your computer and use it in GitHub Desktop.

Select an option

Save MidnightLightning/d3791c03c9fcdf3c2d935fcc8ea720ab to your computer and use it in GitHub Desktop.

Revisions

  1. MidnightLightning revised this gist May 11, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions !MoonCat Organizations.md
    Original file line number Diff line number Diff line change
    @@ -3,12 +3,12 @@ Mooncats have a unique situation where each and every one of them are uniquely i
    # MoonCat Clubs
    Mooncats have Red, Green, and Blue values that range from 0-255. Based on those parameters, they can be separated into different groups and vote as a unit.

    Three MoonCat Clubs, one for each of Red, Green, and Blue. They act as a DAO, where the voting rights on proposals are determined by the Red/Green/Blue values of the Cats.
    Three MoonCat Clubs, one for each of Red, Green, and Blue. They each act as a DAO, where the voting rights on proposals are determined by the Red/Green/Blue values of the Cats.

    The Club contracts operate like a DAO in that any member can put forth a proposal (in the form of a transaction to be executed on the blockchain), and all members can vote on it for a time, and after a specified voting time has passed, if successful, the Club contract sends that transaction. The upshot is that then the Club contract can be made the "owner" of other contracts (who grant their owner special rights), which effectively makes the child contract "owned" by the Club.

    ## Membership
    In order to belong to the Club at all, the cat's color value for that color must be greater than 127. If their color value is greater than this, they can't create proposals or vote at all in the Club.
    In order to belong to the Club at all, the cat's color value for that color must be greater than 127. If their color value is less than this, they can't create proposals or vote at all in the Club.

    Genesis cats are granted membership automatically.

  2. MidnightLightning revised this gist Oct 3, 2017. 2 changed files with 14 additions and 3 deletions.
    13 changes: 13 additions & 0 deletions !MoonCat Organizations.md
    Original file line number Diff line number Diff line change
    @@ -37,3 +37,16 @@ Genesis cats have a vote weight of 20.
    One global DAO where each Mooncat has one vote on each proposal the DAO considers. Genesis cats are _not_ treated differently in this DAO; they have one vote just like all the rest.

    This organization serves as the check-and-balance to the other clubs and can serve as a general consensus for the whole community.

    It consists of two Contracts, the MoonCat "Liquid Democracy" contract (following the model of the "Liquid Democracy" example DAO from Ethereum.org) and the MoonCat "United Nations" contract.

    The Democracy contract serves as the Executive branch of the MoonCat community. Each MoonCat can nominate either themselves, or another MoonCat to serve as representative of the whole community. After analyzing all the nominations, the MoonCat that has the most nominations (a plurality of nominations) is designated High Cat, and is recognized as the representative of the whole MoonCat community.

    The United Nations contract serves as the Legislative branch of the MoonCat community. Each MoonCat can create Proposals and Vote on them. The weight of each MoonCat's vote is the weight of the nominations that MoonCat has received in the Democracy contract. So even if an individual MoonCat is not the High Cat (the one with the highest weight), it can still have a large influence on the proposals put forth at the United Nations contract if it has a large number of nominations as well. Proposals that get a majority of the votes cast will be acted upon (as long as a minimum quorum of MoonCats voted).

    ## Developers
    If you wish to extend upon this government foundation and create contracts that are able to be acted-upon by the MoonCat community, simply pick which type of action is most approprate for your use-case.

    To create a function that should be able to be enacted by "executive order" (a single individual, with no other oversight other than the nominations of the community to act on their best interest) the function should give special permission to transactions coming from (`msg.sender`) the Democracy contract (only the High Cat can make that contract trigger transactions, through the `executiveOrder()` function).

    To create a function that the whole MoonCat community should vote on (like a bill passing through Congress) the function should give special permission to transactions coming from (`msg.sender`) the United Nations contract (the only way to trigger that contract sending a transaction is to have a Proposal be voted and approved by the community).
    4 changes: 1 addition & 3 deletions CatUnitedNations.sol
    Original file line number Diff line number Diff line change
    @@ -230,12 +230,10 @@ contract CatUnitedNations {

    require(quorum <= minimumQuorum); // Check if a minimum quorum has been reached

    p.executed = true;
    if (yea > nay) {
    // Proposal passed; execute the transaction

    p.executed = true;
    require (p.target.call.value(p.amount)(_transactionBytecode));

    p.proposalPassed = true;
    } else {
    // Proposal failed
  3. MidnightLightning revised this gist Oct 2, 2017. 1 changed file with 1 addition and 4 deletions.
    5 changes: 1 addition & 4 deletions LiquidCatDemocracy.sol
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,7 @@
    pragma solidity ^0.4.16;

    contract MoonCatToken {
    //mapping (bytes5 => address) public catOwners;
    function catOwners(bytes5 _catId) public returns (address owner) {
    return 0x00ca35b7d915458ef540ade6068dfe2f44e8fa733c;
    }
    mapping (bytes5 => address) public catOwners;
    }

    contract LiquidCatDemocracy {
  4. MidnightLightning revised this gist Oct 2, 2017. 1 changed file with 34 additions and 22 deletions.
    56 changes: 34 additions & 22 deletions LiquidCatDemocracy.sol
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,10 @@
    pragma solidity ^0.4.16;

    contract MoonCatToken {
    mapping (bytes5 => address) public catOwners;
    //mapping (bytes5 => address) public catOwners;
    function catOwners(bytes5 _catId) public returns (address owner) {
    return 0x00ca35b7d915458ef540ade6068dfe2f44e8fa733c;
    }
    }

    contract LiquidCatDemocracy {
    @@ -14,6 +17,8 @@ contract LiquidCatDemocracy {
    uint public delegatedPercent;
    uint public lastWeightCalculation;
    uint public numberOfDelegationRounds;
    uint public outstandingNominations;
    bool public isCalculating = false;

    uint public numberOfVotes;
    DelegatedVote[] public delegatedVotes;
    @@ -40,17 +45,20 @@ contract LiquidCatDemocracy {
    }

    function nominate(bytes5 _catId, bytes5 _nominee) public returns (uint voteIndex) {
    require(moonCats.catOwners(_catId) == msg.sender); // Must be the owner of that cat
    require(moonCats.catOwners(_catId) == msg.sender // Must be the owner of that cat
    && !isCalculating); // and must not be in the middle of a recalculation

    if (voterId[_catId] == 0) {
    // This cat hasn't delegated its vote yet; create a new record
    voterId[_catId] = delegatedVotes.length;
    numberOfVotes++;
    voteIndex = delegatedVotes.length++;
    numberOfVotes = voteIndex;
    } else {
    voteIndex = voterId[_catId];
    }

    delegatedVotes[voteIndex] = DelegatedVote({nominee: _nominee, voter: _catId});
    outstandingNominations++;

    return voteIndex;
    }
    @@ -66,32 +74,30 @@ contract LiquidCatDemocracy {
    underExecution = false;
    }

    function changeTokenAddress(address _newTarget) public {
    require(moonCats.catOwners(highCat) == msg.sender // If caller is owner of the High Cat,
    && numberOfDelegationRounds >= 4); // and delegation has been calculated enough...

    moonCats = MoonCatToken(_newTarget); // ...set new token location
    }

    function calculateVotes() public returns (bytes5 winner) {
    function calculateVotes() public payable returns (bytes5 winner) {
    bytes5 currentWinner = highCat;
    uint currentMax = 0;
    uint weight = 0;
    DelegatedVote storage v = delegatedVotes[0];

    if (now > lastWeightCalculation + 90 minutes) {

    if (outstandingNominations > 0) {
    // Something's changed; we need to start calculations from the beginning
    assert(now > lastWeightCalculation + 7 days); // Prevent spamming the recalculation

    // Start the calculations over from scratch
    numberOfDelegationRounds = 0;
    lastWeightCalculation = now;

    isCalculating = true;
    outstandingNominations = 0; // Reset counter for tracking changes to nominations

    // Distribute the initial weight
    for (uint i=1; i< delegatedVotes.length; i++) {
    voteWeight[delegatedVotes[i].nominee] = 0;
    }
    for (i=1; i< delegatedVotes.length; i++) {
    voteWeight[delegatedVotes[i].voter] = 1000; // Each cat gets 1000 vote weight, so the delegation percentage per round works
    }
    }
    else {
    } else {
    // Continue an existing calculation
    numberOfDelegationRounds++;
    uint lossRatio = 100 * delegatedPercent ** numberOfDelegationRounds / 100 ** numberOfDelegationRounds;
    if (lossRatio > 0) {
    @@ -110,11 +116,17 @@ contract LiquidCatDemocracy {
    }
    }
    }
    }

    if (numberOfDelegationRounds > 3) {
    NewHighCat(currentWinner, highCat == currentWinner);
    highCat = currentWinner;

    if (numberOfDelegationRounds > 3) {
    // Finalize the calculation
    NewHighCat(currentWinner, highCat == currentWinner);
    highCat = currentWinner;
    if (isCalculating == true) {
    lastWeightCalculation = now; // Reset timer for recalculating weights
    isCalculating = false; // Enable submission of nominations again
    }
    }

    }

    return currentWinner;
  5. MidnightLightning revised this gist Oct 2, 2017. 2 changed files with 19 additions and 17 deletions.
    24 changes: 13 additions & 11 deletions CatUnitedNations.sol
    Original file line number Diff line number Diff line change
    @@ -4,11 +4,11 @@ contract CatDemocracy {
    mapping (bytes5 => uint256) public voteWeight;
    uint public numberOfDelegationRounds;

    function balanceOf(bytes5 _catId) constant returns (uint256 _balance) {
    function balanceOf(bytes5 _catId) public constant returns (uint256 _balance) {
    if (numberOfDelegationRounds < 3) {
    return 0;
    } else {
    return this.voteWeight(_catId);
    return voteWeight[_catId];
    }
    }
    }
    @@ -70,7 +70,7 @@ contract CatUnitedNations {
    * @param _minimumQuorum proposal can conclude only if the sum of shares held by all voters exceed this number
    * @param _debatingPeriodInMinutes the minimum amount of delay between when a proposal is made and when it can be executed
    */
    function CatUnitedNations(address _token, address _democracyAddress, uint _minimumQuorum, uint _debatingPeriodInMinutes) payable {
    function CatUnitedNations(address _token, address _democracyAddress, uint _minimumQuorum, uint _debatingPeriodInMinutes) public payable {
    changeVotingRules(_token, _democracyAddress, _minimumQuorum, _debatingPeriodInMinutes);
    }

    @@ -79,7 +79,7 @@ contract CatUnitedNations {
    *
    * @param _newOwner address of new owner
    */
    function transferOwnership(address _newOwner) onlyOwner {
    function transferOwnership(address _newOwner) public onlyOwner {
    owner = _newOwner;
    }

    @@ -94,7 +94,7 @@ contract CatUnitedNations {
    * @param _minimumQuorum proposal can conclude only if the sum of shares held by all voters exceed this number
    * @param _debatingPeriodInMinutes the minimum amount of delay between when a proposal is made and when it can be executed
    */
    function changeVotingRules(address _token, address _democracyAddress, uint _minimumQuorum, uint _debatingPeriodInMinutes) onlyOwner {
    function changeVotingRules(address _token, address _democracyAddress, uint _minimumQuorum, uint _debatingPeriodInMinutes) public onlyOwner {
    moonCats = MoonCatToken(_token);
    democracy = CatDemocracy(_democracyAddress);
    if (_minimumQuorum == 0 ) _minimumQuorum = 1;
    @@ -121,6 +121,7 @@ contract CatUnitedNations {
    string _description,
    bytes _transactionBytecode
    )
    public
    returns (uint proposalID)
    {
    require(moonCats.catOwners(_catID) == msg.sender); // Must be the owner of that cat
    @@ -130,7 +131,7 @@ contract CatUnitedNations {
    p.target = _target;
    p.amount = _weiAmount;
    p.description = _description;
    p.proposalHash = sha3(_target, _weiAmount, _transactionBytecode);
    p.proposalHash = keccak256(_target, _weiAmount, _transactionBytecode);
    p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
    p.executed = false;
    p.proposalPassed = false;
    @@ -156,11 +157,11 @@ contract CatUnitedNations {
    uint _weiAmount,
    bytes _transactionBytecode
    )
    constant
    public constant
    returns (bool codeChecksOut)
    {
    Proposal storage p = proposals[_proposalNumber];
    return p.proposalHash == sha3(_target, _weiAmount, _transactionBytecode);
    return p.proposalHash == keccak256(_target, _weiAmount, _transactionBytecode);
    }

    /**
    @@ -177,6 +178,7 @@ contract CatUnitedNations {
    uint _proposalNumber,
    bool _supportsProposal
    )
    public
    returns (uint voteID)
    {
    require(moonCats.catOwners(_catID) == msg.sender); // Must be the owner of that cat
    @@ -202,12 +204,12 @@ contract CatUnitedNations {
    * @param _proposalNumber proposal number
    * @param _transactionBytecode optional: if the transaction contained a bytecode, you need to send it
    */
    function executeProposal(uint _proposalNumber, bytes _transactionBytecode) {
    function executeProposal(uint _proposalNumber, bytes _transactionBytecode) public {
    Proposal storage p = proposals[_proposalNumber];

    require(now > p.votingDeadline // If it is past the voting deadline
    && !p.executed // and it has not already been executed
    && p.proposalHash == sha3(p.target, p.amount, _transactionBytecode)); // and the supplied code matches the proposal...
    && p.proposalHash == keccak256(p.target, p.amount, _transactionBytecode)); // and the supplied code matches the proposal...


    // ...then tally the results
    @@ -243,4 +245,4 @@ contract CatUnitedNations {
    // Fire Events
    ProposalTallied(_proposalNumber, yea - nay, quorum, p.proposalPassed);
    }
    }
    }
    12 changes: 6 additions & 6 deletions LiquidCatDemocracy.sol
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,7 @@ contract LiquidCatDemocracy {
    address _token,
    string _forbiddenFunction,
    uint _percentLossInEachRound
    ) {
    ) public {
    moonCats = MoonCatToken(_token);
    delegatedVotes.length++;
    delegatedVotes[0] = DelegatedVote({nominee: 0, voter: 0});
    @@ -39,7 +39,7 @@ contract LiquidCatDemocracy {
    if (delegatedPercent > 100) delegatedPercent = 100;
    }

    function nominate(bytes5 _catId, bytes5 _nominee) returns (uint voteIndex) {
    function nominate(bytes5 _catId, bytes5 _nominee) public returns (uint voteIndex) {
    require(moonCats.catOwners(_catId) == msg.sender); // Must be the owner of that cat
    if (voterId[_catId] == 0) {
    voterId[_catId] = delegatedVotes.length;
    @@ -55,25 +55,25 @@ contract LiquidCatDemocracy {
    return voteIndex;
    }

    function executiveOrder(address _target, uint _valueInWei, bytes32 _bytecode) {
    function executiveOrder(address _target, uint _valueInWei, bytes32 _bytecode) public {
    require(moonCats.catOwners(highCat) == msg.sender // If caller is owner of the High Cat,
    && !underExecution // and the call is not currently being executed,
    && bytes4(_bytecode) != bytes4(sha3(forbiddenFunction)) // and it's not trying to do the forbidden function
    && bytes4(_bytecode) != bytes4(keccak256(forbiddenFunction)) // and it's not trying to do the forbidden function
    && numberOfDelegationRounds >= 4); // and delegation has been calculated enough...

    underExecution = true;
    assert(_target.call.value(_valueInWei)(_bytecode)); // ...then execute the command.
    underExecution = false;
    }

    function changeTokenAddress(address _newTarget) {
    function changeTokenAddress(address _newTarget) public {
    require(moonCats.catOwners(highCat) == msg.sender // If caller is owner of the High Cat,
    && numberOfDelegationRounds >= 4); // and delegation has been calculated enough...

    moonCats = MoonCatToken(_newTarget); // ...set new token location
    }

    function calculateVotes() returns (bytes5 winner) {
    function calculateVotes() public returns (bytes5 winner) {
    bytes5 currentWinner = highCat;
    uint currentMax = 0;
    uint weight = 0;
  6. MidnightLightning revised this gist Sep 1, 2017. 1 changed file with 246 additions and 0 deletions.
    246 changes: 246 additions & 0 deletions CatUnitedNations.sol
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,246 @@
    pragma solidity ^0.4.16;

    contract CatDemocracy {
    mapping (bytes5 => uint256) public voteWeight;
    uint public numberOfDelegationRounds;

    function balanceOf(bytes5 _catId) constant returns (uint256 _balance) {
    if (numberOfDelegationRounds < 3) {
    return 0;
    } else {
    return this.voteWeight(_catId);
    }
    }
    }
    contract MoonCatToken {
    mapping (bytes5 => address) public catOwners;
    }


    /**
    * The shareholder association contract itself
    */
    contract CatUnitedNations {

    address public owner = msg.sender;
    uint public minimumQuorum;
    uint public debatingPeriodInMinutes;
    Proposal[] public proposals;
    uint public numProposals;
    CatDemocracy public democracy;
    MoonCatToken public moonCats;

    event ProposalAdded(uint proposalID, address target, uint amount, string description);
    event Voted(uint proposalID, bool position, bytes5 voter);
    event ProposalTallied(uint proposalID, uint result, uint quorum, bool active);
    event ChangeOfRules(uint newMinimumQuorum, uint newDebatingPeriodInMinutes, address newSharesTokenAddress);

    struct Proposal {
    address target;
    uint amount;
    string description;
    uint votingDeadline;
    bool executed;
    bool proposalPassed;
    uint numberOfVotes;
    bytes32 proposalHash;
    Vote[] votes;
    mapping (bytes5 => bool) voted;
    }

    struct Vote {
    bool inSupport;
    bytes5 voter;
    }

    // Modifier that only allows the current owner to execute
    modifier onlyOwner {
    require(msg.sender == owner);
    _;
    }


    /**
    * Constructor function
    *
    * First time setup
    *
    * @param _token location of the MoonCatRescue contract
    * @param _democracyAddress location of the LiquidCatDemocracy contract
    * @param _minimumQuorum proposal can conclude only if the sum of shares held by all voters exceed this number
    * @param _debatingPeriodInMinutes the minimum amount of delay between when a proposal is made and when it can be executed
    */
    function CatUnitedNations(address _token, address _democracyAddress, uint _minimumQuorum, uint _debatingPeriodInMinutes) payable {
    changeVotingRules(_token, _democracyAddress, _minimumQuorum, _debatingPeriodInMinutes);
    }

    /**
    * Set new owner for the contract
    *
    * @param _newOwner address of new owner
    */
    function transferOwnership(address _newOwner) onlyOwner {
    owner = _newOwner;
    }

    /**
    * Change voting rules
    *
    * Make so that proposals need tobe discussed for at least `minutesForDebate/60` hours
    * and all voters combined must own more than `minimumSharesToPassAVote` shares of token `sharesAddress` to be executed
    *
    * @param _token location of the MoonCatRescue contract
    * @param _democracyAddress location of the LiquidCatDemocracy contract
    * @param _minimumQuorum proposal can conclude only if the sum of shares held by all voters exceed this number
    * @param _debatingPeriodInMinutes the minimum amount of delay between when a proposal is made and when it can be executed
    */
    function changeVotingRules(address _token, address _democracyAddress, uint _minimumQuorum, uint _debatingPeriodInMinutes) onlyOwner {
    moonCats = MoonCatToken(_token);
    democracy = CatDemocracy(_democracyAddress);
    if (_minimumQuorum == 0 ) _minimumQuorum = 1;
    minimumQuorum = _minimumQuorum;
    debatingPeriodInMinutes = _debatingPeriodInMinutes;
    ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, democracy);
    }

    /**
    * Add Proposal
    *
    * Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
    *
    * @param _catID the cat making the proposal
    * @param _target who to send the ether to
    * @param _weiAmount amount of ether to send, in wei
    * @param _description Description of job
    * @param _transactionBytecode bytecode of transaction
    */
    function newProposal(
    bytes5 _catID,
    address _target,
    uint _weiAmount,
    string _description,
    bytes _transactionBytecode
    )
    returns (uint proposalID)
    {
    require(moonCats.catOwners(_catID) == msg.sender); // Must be the owner of that cat
    proposalID = proposals.length++;

    Proposal storage p = proposals[proposalID];
    p.target = _target;
    p.amount = _weiAmount;
    p.description = _description;
    p.proposalHash = sha3(_target, _weiAmount, _transactionBytecode);
    p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
    p.executed = false;
    p.proposalPassed = false;
    p.numberOfVotes = 0;

    ProposalAdded(proposalID, _target, _weiAmount, _description);
    numProposals = proposalID+1;

    return proposalID;
    }

    /**
    * Check if a proposal code matches
    *
    * @param _proposalNumber ID number of the proposal to query
    * @param _target who to send the ether to
    * @param _weiAmount amount of ether to send
    * @param _transactionBytecode bytecode of transaction
    */
    function checkProposalCode(
    uint _proposalNumber,
    address _target,
    uint _weiAmount,
    bytes _transactionBytecode
    )
    constant
    returns (bool codeChecksOut)
    {
    Proposal storage p = proposals[_proposalNumber];
    return p.proposalHash == sha3(_target, _weiAmount, _transactionBytecode);
    }

    /**
    * Log a vote for a proposal
    *
    * Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
    *
    * @param _catID The cat submitting the vote
    * @param _proposalNumber number of proposal
    * @param _supportsProposal either in favor or against it
    */
    function vote(
    bytes5 _catID,
    uint _proposalNumber,
    bool _supportsProposal
    )
    returns (uint voteID)
    {
    require(moonCats.catOwners(_catID) == msg.sender); // Must be the owner of that cat
    Proposal storage p = proposals[_proposalNumber];
    require(p.voted[_catID] != true);

    voteID = p.votes.length++;
    p.votes[voteID] = Vote({
    inSupport: _supportsProposal,
    voter: _catID
    });
    p.voted[_catID] = true;
    p.numberOfVotes = voteID +1;
    Voted(_proposalNumber, _supportsProposal, _catID);
    return voteID;
    }

    /**
    * Finish vote
    *
    * Count the votes proposal #`proposalNumber` and execute it if approved
    *
    * @param _proposalNumber proposal number
    * @param _transactionBytecode optional: if the transaction contained a bytecode, you need to send it
    */
    function executeProposal(uint _proposalNumber, bytes _transactionBytecode) {
    Proposal storage p = proposals[_proposalNumber];

    require(now > p.votingDeadline // If it is past the voting deadline
    && !p.executed // and it has not already been executed
    && p.proposalHash == sha3(p.target, p.amount, _transactionBytecode)); // and the supplied code matches the proposal...


    // ...then tally the results
    uint quorum = 0;
    uint yea = 0;
    uint nay = 0;

    for (uint i = 0; i < p.votes.length; ++i) {
    Vote storage v = p.votes[i];
    uint voteWeight = democracy.balanceOf(v.voter);
    quorum += voteWeight;
    if (v.inSupport) {
    yea += voteWeight;
    } else {
    nay += voteWeight;
    }
    }

    require(quorum <= minimumQuorum); // Check if a minimum quorum has been reached

    if (yea > nay) {
    // Proposal passed; execute the transaction

    p.executed = true;
    require (p.target.call.value(p.amount)(_transactionBytecode));

    p.proposalPassed = true;
    } else {
    // Proposal failed
    p.proposalPassed = false;
    }

    // Fire Events
    ProposalTallied(_proposalNumber, yea - nay, quorum, p.proposalPassed);
    }
    }
  7. MidnightLightning revised this gist Aug 31, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions LiquidCatDemocracy.sol
    Original file line number Diff line number Diff line change
    @@ -55,14 +55,14 @@ contract LiquidCatDemocracy {
    return voteIndex;
    }

    function executiveOrder(address _target, uint _valueInEther, bytes32 _bytecode) {
    function executiveOrder(address _target, uint _valueInWei, bytes32 _bytecode) {
    require(moonCats.catOwners(highCat) == msg.sender // If caller is owner of the High Cat,
    && !underExecution // and the call is not currently being executed,
    && bytes4(_bytecode) != bytes4(sha3(forbiddenFunction)) // and it's not trying to do the forbidden function
    && numberOfDelegationRounds >= 4); // and delegation has been calculated enough...

    underExecution = true;
    assert(_target.call.value(_valueInEther * 1 ether)(_bytecode)); // ...then execute the command.
    assert(_target.call.value(_valueInWei)(_bytecode)); // ...then execute the command.
    underExecution = false;
    }

  8. MidnightLightning renamed this gist Aug 31, 2017. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  9. MidnightLightning revised this gist Aug 31, 2017. 1 changed file with 122 additions and 0 deletions.
    122 changes: 122 additions & 0 deletions LiquidCatDemocracy.sol
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,122 @@
    pragma solidity ^0.4.16;

    contract MoonCatToken {
    mapping (bytes5 => address) public catOwners;
    }

    contract LiquidCatDemocracy {
    MoonCatToken public moonCats;
    bool underExecution;
    bytes5 public highCat;
    mapping (bytes5 => uint) public voterId;
    mapping (bytes5 => uint256) public voteWeight;

    uint public delegatedPercent;
    uint public lastWeightCalculation;
    uint public numberOfDelegationRounds;

    uint public numberOfVotes;
    DelegatedVote[] public delegatedVotes;
    string public forbiddenFunction;

    event NewHighCat(bytes5 newHighCat, bool changed);

    struct DelegatedVote {
    bytes5 nominee;
    bytes5 voter;
    }

    function LiquidCatDemocracy(
    address _token,
    string _forbiddenFunction,
    uint _percentLossInEachRound
    ) {
    moonCats = MoonCatToken(_token);
    delegatedVotes.length++;
    delegatedVotes[0] = DelegatedVote({nominee: 0, voter: 0});
    forbiddenFunction = _forbiddenFunction;
    delegatedPercent = 100 - _percentLossInEachRound;
    if (delegatedPercent > 100) delegatedPercent = 100;
    }

    function nominate(bytes5 _catId, bytes5 _nominee) returns (uint voteIndex) {
    require(moonCats.catOwners(_catId) == msg.sender); // Must be the owner of that cat
    if (voterId[_catId] == 0) {
    voterId[_catId] = delegatedVotes.length;
    numberOfVotes++;
    voteIndex = delegatedVotes.length++;
    numberOfVotes = voteIndex;
    } else {
    voteIndex = voterId[_catId];
    }

    delegatedVotes[voteIndex] = DelegatedVote({nominee: _nominee, voter: _catId});

    return voteIndex;
    }

    function executiveOrder(address _target, uint _valueInEther, bytes32 _bytecode) {
    require(moonCats.catOwners(highCat) == msg.sender // If caller is owner of the High Cat,
    && !underExecution // and the call is not currently being executed,
    && bytes4(_bytecode) != bytes4(sha3(forbiddenFunction)) // and it's not trying to do the forbidden function
    && numberOfDelegationRounds >= 4); // and delegation has been calculated enough...

    underExecution = true;
    assert(_target.call.value(_valueInEther * 1 ether)(_bytecode)); // ...then execute the command.
    underExecution = false;
    }

    function changeTokenAddress(address _newTarget) {
    require(moonCats.catOwners(highCat) == msg.sender // If caller is owner of the High Cat,
    && numberOfDelegationRounds >= 4); // and delegation has been calculated enough...

    moonCats = MoonCatToken(_newTarget); // ...set new token location
    }

    function calculateVotes() returns (bytes5 winner) {
    bytes5 currentWinner = highCat;
    uint currentMax = 0;
    uint weight = 0;
    DelegatedVote storage v = delegatedVotes[0];

    if (now > lastWeightCalculation + 90 minutes) {
    numberOfDelegationRounds = 0;
    lastWeightCalculation = now;

    // Distribute the initial weight
    for (uint i=1; i< delegatedVotes.length; i++) {
    voteWeight[delegatedVotes[i].nominee] = 0;
    }
    for (i=1; i< delegatedVotes.length; i++) {
    voteWeight[delegatedVotes[i].voter] = 1000; // Each cat gets 1000 vote weight, so the delegation percentage per round works
    }
    }
    else {
    numberOfDelegationRounds++;
    uint lossRatio = 100 * delegatedPercent ** numberOfDelegationRounds / 100 ** numberOfDelegationRounds;
    if (lossRatio > 0) {
    for (i=1; i< delegatedVotes.length; i++){
    v = delegatedVotes[i];

    if (v.nominee != v.voter && voteWeight[v.voter] > 0) {
    weight = voteWeight[v.voter] * lossRatio / 100;
    voteWeight[v.voter] -= weight;
    voteWeight[v.nominee] += weight;
    }

    if (numberOfDelegationRounds>3 && voteWeight[v.nominee] > currentMax) {
    currentWinner = v.nominee;
    currentMax = voteWeight[v.nominee];
    }
    }
    }
    }

    if (numberOfDelegationRounds > 3) {
    NewHighCat(currentWinner, highCat == currentWinner);
    highCat = currentWinner;
    }

    return currentWinner;
    }
    }
  10. MidnightLightning created this gist Aug 28, 2017.
    39 changes: 39 additions & 0 deletions MoonCat Organizations.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    Mooncats have a unique situation where each and every one of them are uniquely identified and distinct from all the other Mooncats. In most smart-contract-based voting systems/DAOs, Ethereum addresses hold some number of tokens/shares and get some proportional voting weight. But then care has to be taken that in a given voting period for any proposal, that someone cannot vote with their shares, transfer the shares to another address, and then vote again. By having the _cats_ be the voting unit rather than the _addresses_, MoonCats can solve this issue very neatly.

    # MoonCat Clubs
    Mooncats have Red, Green, and Blue values that range from 0-255. Based on those parameters, they can be separated into different groups and vote as a unit.

    Three MoonCat Clubs, one for each of Red, Green, and Blue. They act as a DAO, where the voting rights on proposals are determined by the Red/Green/Blue values of the Cats.

    The Club contracts operate like a DAO in that any member can put forth a proposal (in the form of a transaction to be executed on the blockchain), and all members can vote on it for a time, and after a specified voting time has passed, if successful, the Club contract sends that transaction. The upshot is that then the Club contract can be made the "owner" of other contracts (who grant their owner special rights), which effectively makes the child contract "owned" by the Club.

    ## Membership
    In order to belong to the Club at all, the cat's color value for that color must be greater than 127. If their color value is greater than this, they can't create proposals or vote at all in the Club.

    Genesis cats are granted membership automatically.

    ## Voting weight
    A cat's vote counts for `(x-127)/8+1`. Thus color values are grouped in chunks of 8, but a cat with a value of 255 gets one extra vote (17, compared to 254 which gets a vote weight of 16).

    A cat gets an additional 5 points added to their vote weight if they are a named cat, and their name honors the mythical founder of the club (a specific string [is found anywhere](https://github.com/Arachnid/solidity-stringutils#containsslice-self-slice-needle-internal-returns-bool) in their name).

    Genesis cats have a vote weight of 20.

    ## Clubs

    ### Raskal's Regal Reds
    - Founder: Raskal Ratter-Ra
    - Key string: "rat" or "Rat"

    ### Giggums' Glorious Greens
    - Founder: Sir Giggums Gobo III
    - Key string "gig" or "Gig"

    ### Bessie's Beautiful Blues
    - Founder: Bessie Belle
    - Key string: "bel" or "Bel"

    # United Nations of MoonCats
    One global DAO where each Mooncat has one vote on each proposal the DAO considers. Genesis cats are _not_ treated differently in this DAO; they have one vote just like all the rest.

    This organization serves as the check-and-balance to the other clubs and can serve as a general consensus for the whole community.