Back to Home

Unicorn Meat Grinder Association

DAO
0xc7e9ddd5358e...73149beeaa32
HomesteadContract #13KAuthor-Published SourceEdit this contract
Deployed March 25, 2016 (10 years ago)Block 1,211,176

An early DAO made to demonstrate token swaps, mutations, and quadratic voting.

Key Facts

Deployment Block
1,211,176
Deployment Date
Mar 25, 2016, 02:55 AM
Code Size
4.5 KB
Gas at Deploy
1,445,663
Transactions by Year
201615
20177
202519

Description

The Unicorn Meat Grinder Association DAO was an early decentralized autonomous organization designed and deployed in 2016 by Alex Van de Sande, then a leading figure at the Ethereum Foundation. The DAO governed a set of smart contracts that allowed holders of the original Unicorn token, an experimental token distributed by the Ethereum Foundation, to swap (“grind”) those tokens for a new asset known as Unicorn Meat. The contract was announced by Ethereum as an April Fool's joke in 2016.

The Unicorn Meat Grinder Association DAO was a decentralized autonomous organization deployed on the Ethereum blockchain in March 2016. It governed a set of smart contracts that allowed holders of the original Unicorn token — a small gratitude token created by the Ethereum Foundation — to exchange (“grind”) those unicorns for a new token called Unicorn Meat. Governance decisions within the DAO were made on-chain using a voting mechanism where token holders could submit and vote on proposals.

Source Verified

SolidityAuthor-published source
Compiler: soljson

DAO controlling the Unicorn Meat grinder rules. Source and compiler settings published by Alex Van de Sande (avsa). Features quadratic voting where each negative vote is worth 4 support votes.

Heuristic Analysis

The following characteristics were detected through bytecode analysis and may not be accurate.

Detected Type: DAO
Has ERC-20-like patterns

Homestead Era

The first planned hard fork. Removed the canary contract, adjusted gas costs.

Block span: 1,150,0001,919,999
March 14, 2016July 20, 2016

Bytecode Overview

Opcodes4,640
Unique Opcodes214
Jump Instructions196
Storage Operations141

Verified Source Available

Source code published by the original contract author.

View Verification Proof
Show source code (Solidity)
/*

Solc: '0.2.1-91a6b35f/.-Emscripten/clang/int linked to libethereum-' with optim
Address: 0xc7e9dDd5358e08417b1C88ed6f1a73149BEeaa32
Interface:
[ { "constant": true, "inputs": [ { "name": "", "type": "uint256", "index": 0, "typeShort": "uint", "bits": "256", "displayName": "", "template": "elements_input_uint" } ], "name": "proposals", "outputs": [ { "name": "recipient", "type": "address" }, { "name": "amount", "type": "uint256" }, { "name": "description", "type": "string" }, { "name": "votingDeadline", "type": "uint256" }, { "name": "executed", "type": "bool" }, { "name": "proposalPassed", "type": "bool" }, { "name": "numberOfVotes", "type": "uint256" }, { "name": "proposalHash", "type": "bytes32" } ], "type": "function", "displayName": "proposals" }, { "constant": true, "inputs": [], "name": "rejectionMultiplier", "outputs": [ { "name": "", "type": "uint256", "value": "4", "displayName": "" } ], "type": "function", "displayName": "rejection Multiplier" }, { "constant": false, "inputs": [ { "name": "proposalNumber", "type": "uint256", "index": 0, "typeShort": "uint", "bits": "256", "displayName": "proposal Number", "template": "elements_input_uint" }, { "name": "transactionBytecode", "type": "bytes", "index": 1, "typeShort": "bytes", "bits": "", "displayName": "transaction Bytecode", "template": "elements_input_bytes" } ], "name": "executeProposal", "outputs": [ { "name": "result", "type": "int256" } ], "type": "function", "displayName": "execute Proposal" }, { "constant": true, "inputs": [], "name": "numProposals", "outputs": [ { "name": "", "type": "uint256", "value": "0", "displayName": "" } ], "type": "function", "displayName": "num Proposals" }, { "constant": false, "inputs": [ { "name": "_from", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "&thinsp;<span class=\"punctuation\">_</span>&thinsp;from", "template": "elements_input_address" }, { "name": "_value", "type": "uint256", "index": 1, "typeShort": "uint", "bits": "256", "displayName": "&thinsp;<span class=\"punctuation\">_</span>&thinsp;value", "template": "elements_input_uint" }, { "name": "_token", "type": "address", "index": 2, "typeShort": "address", "bits": "", "displayName": "&thinsp;<span class=\"punctuation\">_</span>&thinsp;token", "template": "elements_input_address" } ], "name": "receiveApproval", "outputs": [], "type": "function", "displayName": "receive Approval" }, { "constant": false, "inputs": [ { "name": "amountOfUnicornsToGrind", "type": "uint256", "index": 0, "typeShort": "uint", "bits": "256", "displayName": "amount Of Unicorns To Grind", "template": "elements_input_uint" } ], "name": "grindUnicorns", "outputs": [], "type": "function", "displayName": "grind Unicorns" }, { "constant": false, "inputs": [ { "name": "unicornAddress", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "unicorn Address", "template": "elements_input_address" }, { "name": "meatAddress", "type": "address", "index": 1, "typeShort": "address", "bits": "", "displayName": "meat Address", "template": "elements_input_address" }, { "name": "minimumSharesToPassAVote", "type": "uint256", "index": 2, "typeShort": "uint", "bits": "256", "displayName": "minimum Shares To Pass A Vote", "template": "elements_input_uint" }, { "name": "minutesForDebate", "type": "uint256", "index": 3, "typeShort": "uint", "bits": "256", "displayName": "minutes For Debate", "template": "elements_input_uint" }, { "name": "multiplierForVotesAgainst", "type": "uint256", "index": 4, "typeShort": "uint", "bits": "256", "displayName": "multiplier For Votes Against", "template": "elements_input_uint" } ], "name": "changeVotingRules", "outputs": [], "type": "function", "displayName": "change Voting Rules" }, { "constant": true, "inputs": [], "name": "unicornTokenAddress", "outputs": [ { "name": "", "type": "address", "value": "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7", "displayName": "" } ], "type": "function", "displayName": "unicorn Token Address" }, { "constant": true, "inputs": [ { "name": "x", "type": "uint256", "index": 0, "typeShort": "uint", "bits": "256", "displayName": "x", "template": "elements_input_uint" } ], "name": "sqrt", "outputs": [ { "name": "y", "type": "uint256", "value": "0", "displayName": "y" } ], "type": "function", "displayName": "sqrt" }, { "constant": true, "inputs": [], "name": "debatingPeriodInMinutes", "outputs": [ { "name": "", "type": "uint256", "value": "0", "displayName": "" } ], "type": "function", "displayName": "debating Period In Minutes" }, { "constant": true, "inputs": [], "name": "minimumQuorum", "outputs": [ { "name": "", "type": "uint256", "value": "1", "displayName": "" } ], "type": "function", "displayName": "minimum Quorum" }, { "constant": true, "inputs": [ { "name": "", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "", "template": "elements_input_address" } ], "name": "unicornsKilled", "outputs": [ { "name": "", "type": "uint256", "value": "0", "displayName": "" } ], "type": "function", "displayName": "unicorns Killed" }, { "constant": true, "inputs": [], "name": "owner", "outputs": [ { "name": "", "type": "address", "value": "0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb", "displayName": "" } ], "type": "function", "displayName": "owner" }, { "constant": false, "inputs": [ { "name": "beneficiary", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "beneficiary", "template": "elements_input_address" }, { "name": "etherAmount", "type": "uint256", "index": 1, "typeShort": "uint", "bits": "256", "displayName": "ether Amount", "template": "elements_input_uint" }, { "name": "JobDescription", "type": "string", "index": 2, "typeShort": "string", "bits": "", "displayName": " Job Description", "template": "elements_input_string" }, { "name": "transactionBytecode", "type": "bytes", "index": 3, "typeShort": "bytes", "bits": "", "displayName": "transaction Bytecode", "template": "elements_input_bytes" } ], "name": "newProposal", "outputs": [ { "name": "proposalID", "type": "uint256" } ], "type": "function", "displayName": "new Proposal" }, { "constant": false, "inputs": [ { "name": "proposalNumber", "type": "uint256", "index": 0, "typeShort": "uint", "bits": "256", "displayName": "proposal Number", "template": "elements_input_uint" }, { "name": "supportsProposal", "type": "bool", "index": 1, "typeShort": "bool", "bits": "", "displayName": "supports Proposal", "template": "elements_input_bool" } ], "name": "vote", "outputs": [ { "name": "voteID", "type": "uint256" } ], "type": "function", "displayName": "vote" }, { "constant": true, "inputs": [], "name": "totalUnicornsKilled", "outputs": [ { "name": "", "type": "uint256", "value": "0", "displayName": "" } ], "type": "function", "displayName": "total Unicorns Killed" }, { "constant": true, "inputs": [], "name": "meatTokenAddress", "outputs": [ { "name": "", "type": "address", "value": "0xed6ac8de7c7ca7e3a22952e09c2a2a1232ddef9a", "displayName": "" } ], "type": "function", "displayName": "meat Token Address" }, { "constant": false, "inputs": [ { "name": "newMeatProvider", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "new Meat Provider", "template": "elements_input_address" } ], "name": "changeMeatProvider", "outputs": [], "type": "function", "displayName": "change Meat Provider" }, { "constant": true, "inputs": [ { "name": "proposalNumber", "type": "uint256", "index": 0, "typeShort": "uint", "bits": "256", "displayName": "proposal Number", "template": "elements_input_uint" }, { "name": "beneficiary", "type": "address", "index": 1, "typeShort": "address", "bits": "", "displayName": "beneficiary", "template": "elements_input_address" }, { "name": "etherAmount", "type": "uint256", "index": 2, "typeShort": "uint", "bits": "256", "displayName": "ether Amount", "template": "elements_input_uint" }, { "name": "transactionBytecode", "type": "bytes", "index": 3, "typeShort": "bytes", "bits": "", "displayName": "transaction Bytecode", "template": "elements_input_bytes" } ], "name": "checkProposalCode", "outputs": [ { "name": "codeChecksOut", "type": "bool", "value": false, "displayName": "code Checks Out" } ], "type": "function", "displayName": "check Proposal Code" }, { "constant": true, "inputs": [], "name": "meatProvider", "outputs": [ { "name": "", "type": "address", "value": "0x4ab274fc3a81b300a0016b3805d9b94c81fa54d2", "displayName": "" } ], "type": "function", "displayName": "meat Provider" }, { "constant": false, "inputs": [ { "name": "newOwner", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "new Owner", "template": "elements_input_address" } ], "name": "transferOwnership", "outputs": [], "type": "function", "displayName": "transfer Ownership" }, { "inputs": [ { "name": "unicornAddress", "type": "address", "index": 0, "typeShort": "address", "bits": "", "displayName": "unicorn Address", "template": "elements_input_address", "value": "0x89205a3a3b2a69de6dbf7f01ed13b2108b2c43e7" }, { "name": "meatAddress", "type": "address", "index": 1, "typeShort": "address", "bits": "", "displayName": "meat Address", "template": "elements_input_address", "value": "0xED6aC8de7c7CA7e3A22952e09C2a2A1232DDef9A" }, { "name": "minimumUnicornsToPassAVote", "type": "uint256", "index": 2, "typeShort": "uint", "bits": "256", "displayName": "minimum Unicorns To Pass A Vote", "template": "elements_input_uint", "value": "1" }, { "name": "minutesForDebate", "type": "uint256", "index": 3, "typeShort": "uint", "bits": "256", "displayName": "minutes For Debate", "template": "elements_input_uint", "value": "" }, { "name": "multiplierForVotesAgainst", "type": "uint256", "index": 4, "typeShort": "uint", "bits": "256", "displayName": "multiplier For Votes Against", "template": "elements_input_uint", "value": "4" }, { "name": "meatCalculator", "type": "address", "index": 5, "typeShort": "address", "bits": "", "displayName": "meat Calculator", "template": "elements_input_address", "value": "0x4AB274FC3A81B300A0016b3805d9b94C81FA54d2" } ], "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "proposalID", "type": "uint256" }, { "indexed": false, "name": "recipient", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" }, { "indexed": false, "name": "description", "type": "string" } ], "name": "ProposalAdded", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "proposalID", "type": "uint256" }, { "indexed": false, "name": "position", "type": "bool" }, { "indexed": false, "name": "voter", "type": "address" } ], "name": "Voted", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "proposalID", "type": "uint256" }, { "indexed": false, "name": "result", "type": "int256" }, { "indexed": false, "name": "quorum", "type": "uint256" }, { "indexed": false, "name": "active", "type": "bool" } ], "name": "ProposalTallied", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "minimumQuorum", "type": "uint256" }, { "indexed": false, "name": "debatingPeriodInMinutes", "type": "uint256" }, { "indexed": false, "name": "sharesTokenAddress", "type": "address" } ], "name": "ChangeOfRules", "type": "event" } ]

testnet unicorn: 0x21E6fc92f93C8A1Bb41e2Be64b4E1f88a54d3576
Meat Grinders Association Address: 0x7cb292Ab6d4170D263609572ee087Bc78b85A92b

Alice: 0xDC9974d8D61EBb673b1D132E0b767f4e38FBA057
Bob: 0x5F8f68a0D1CbC75f6eF764a44619277092C32DF0
Eve: 0xafA55A04adE6645f676F50e45CdE7C90F75Fab99*/
/* The token is used as a voting shares */
contract token { 
    mapping (address => uint256) public balanceOf;  
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    function mintToken(address target, uint256 mintedAmount);    
}

/* define 'owned' */
contract owned {
    address public owner;

    function owned() {
        owner = msg.sender;
    }

    modifier onlyOwner {
        if (msg.sender != owner) throw;
        _
    }

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}


contract MeatCalculator {
    function calculateMeat(uint amountOfUnicorns) constant returns (uint amountOfMeat);
}

/* The democracy contract itself */
contract MeatGrindersAssociation is owned {

    /* Contract Variables and events */
    uint public minimumQuorum;
    uint public debatingPeriodInMinutes;
    uint public rejectionMultiplier;
    Proposal[] public proposals;
    uint public numProposals;
    
    mapping (address => uint256) public unicornsKilled;
    uint public totalUnicornsKilled;

    token public unicornTokenAddress;
    token public meatTokenAddress;
    MeatCalculator public meatProvider;

    event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
    event Voted(uint proposalID, bool position, address voter);
    event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
    event ChangeOfRules(uint minimumQuorum, uint debatingPeriodInMinutes, address sharesTokenAddress);

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

    struct Vote {
        bool inSupport;
        uint bribe;
        address voter;
    }
    


    /* modifier that allows only shareholders to vote and create new proposals */
    modifier onlyShareholders {
        if (unicornTokenAddress.balanceOf(msg.sender) == 0) throw;
        _
    }

    /* First time setup */
    function MeatGrindersAssociation(
        address unicornAddress, 
        address meatAddress, 
        uint minimumUnicornsToPassAVote, 
        uint minutesForDebate, 
        uint multiplierForVotesAgainst, 
        address meatCalculator
    ) {
        if (minimumUnicornsToPassAVote == 0 ) minimumUnicornsToPassAVote = 1;
        changeVotingRules( unicornAddress,  meatAddress,  minimumUnicornsToPassAVote,  minutesForDebate,  multiplierForVotesAgainst); 
        changeMeatProvider(meatCalculator);
    }

    /*change rules*/
    function changeVotingRules(address unicornAddress, address meatAddress, uint minimumSharesToPassAVote, uint minutesForDebate, uint multiplierForVotesAgainst) onlyOwner {
        unicornTokenAddress = token(unicornAddress);
        meatTokenAddress = token(meatAddress);
        minimumQuorum = minimumSharesToPassAVote;
        debatingPeriodInMinutes = minutesForDebate;
        rejectionMultiplier = multiplierForVotesAgainst;
        ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, unicornTokenAddress);
    }
    
    function changeMeatProvider(address newMeatProvider) {
        meatProvider = MeatCalculator(newMeatProvider);
    }

    /* Function to create a new proposal */
    function newProposal(address beneficiary, uint etherAmount, string JobDescription, bytes transactionBytecode) onlyShareholders returns (uint proposalID) {
        proposalID = proposals.length++;
        Proposal p = proposals[proposalID];
        p.recipient = beneficiary;
        p.amount = etherAmount;
        p.description = JobDescription;
        p.proposalHash = sha3(beneficiary, etherAmount, transactionBytecode);
        p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
        p.executed = false;
        p.proposalPassed = false;
        p.numberOfVotes = 0;
        ProposalAdded(proposalID, beneficiary, etherAmount, JobDescription);
        numProposals = proposalID+1;
    }

    /* function to check if a proposal code matches */
    function checkProposalCode(uint proposalNumber, address beneficiary, uint etherAmount, bytes transactionBytecode) constant returns (bool codeChecksOut) {
        Proposal p = proposals[proposalNumber];
        return p.proposalHash == sha3(beneficiary, etherAmount, transactionBytecode);
    }

    /* */
    function vote(uint proposalNumber, bool supportsProposal) onlyShareholders returns (uint voteID){
        Proposal p = proposals[proposalNumber];
        if (p.voted[msg.sender] == true) throw;

        voteID = p.votes.length++;
        p.votes[voteID] = Vote({inSupport: supportsProposal, voter: msg.sender, bribe: sqrt(msg.value + msg.gas*tx.gasprice)});
        p.voted[msg.sender] = true;
        p.numberOfVotes = voteID +1;
        Voted(proposalNumber,  supportsProposal, msg.sender);
    }

    function executeProposal(uint proposalNumber, bytes transactionBytecode) returns (int result) {
        Proposal p = proposals[proposalNumber];
        /* Check if the proposal can be executed */
        if (now < p.votingDeadline  /* has the voting deadline arrived? */ 
            ||  p.executed        /* has it been already executed? */
            ||  p.proposalHash != sha3(p.recipient, p.amount, transactionBytecode)) /* Does the transaction code match the proposal? */
            throw;

        /* tally the votes */
        uint quorum = 0;
        uint yea = 0; 
        uint nay = 0;

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

        /* execute result */
        if (quorum <= minimumQuorum) {
            /* Not enough significant voters */
            throw;
        } else if (yea > nay ) {
            /* has quorum and was approved */
            p.recipient.call.value(p.amount * 1 ether)(transactionBytecode);
            p.executed = true;
            p.proposalPassed = true;
        } else {
            p.executed = true;
            p.proposalPassed = false;
        } 
        // Fire Events
        ProposalTallied(proposalNumber, result, quorum, p.proposalPassed);
    }
    
    function sqrt(uint x) constant returns (uint y) {
        if (x == 0) return 0;
        else if (x <= 3) return 1;
        uint z = (x + 1) / 2;
        y = x;
        while (z < y)
        /// @why3 invariant { to_int !_z = div ((div (to_int arg_x) (to_int !_y)) + (to_int !_y)) 2 }
        /// @why3 invariant { to_int arg_x < (to_int !_y + 1) * (to_int !_y + 1) }
        /// @why3 invariant { to_int arg_x < (to_int !_z + 1) * (to_int !_z + 1) }
        /// @why3 variant { to_int !_y }
        {
            y = z;
            z = (x / z + z) / 2;
        }
    }    

    function receiveApproval(address _from, uint256 _value, address _token) {
        if(token(_token) != unicornTokenAddress) throw;
        if (!unicornTokenAddress.transferFrom(_from, address(this), _value)) throw;
    
        meatTokenAddress.mintToken(_from, meatProvider.calculateMeat(_value));
        unicornsKilled[_from] += _value;
        totalUnicornsKilled += _value;
    }    
    
    function grindUnicorns(uint256 amountOfUnicornsToGrind) {
        unicornTokenAddress.transferFrom(msg.sender, address(this), amountOfUnicornsToGrind);
        meatTokenAddress.mintToken(msg.sender, meatProvider.calculateMeat(amountOfUnicornsToGrind));
        unicornsKilled[msg.sender] += amountOfUnicornsToGrind;
        totalUnicornsKilled += amountOfUnicornsToGrind;
    }
}

External Links