Back to Home

FoundationTipJar

DAO
0xfb6916095ca1...a74c37c5d359
FrontierContract #8,365Source VerifiedEdit this contract
Deployed February 11, 2016 (10 years ago)Block 988,725

An early Ethereum smart contract that enabled direct, on-chain donations to the Ethereum Foundation and issued the original Unicorn token.

Key Facts

Deployment Block
988,725
Deployment Date
Feb 11, 2016, 05:14 PM
Code Size
7.0 KB
Gas at Deploy
1,864,511
Transactions by Year
2016520
2017479
2018171
2019123
202033
202138
202233
20234
20256

Description

The Tip Jar functioned as a simple but deliberate demonstration of Ethereum’s capabilities. It replaced traditional donation mechanisms with on-chain logic, making contributions publicly auditable and programmatically handled. The associated Unicorn token was intended as a symbolic acknowledgment of participation rather than a financial asset.

The Foundation Tip Jar was a smart contract deployed in 2015 by Alex Van de Sande while working at the Ethereum Foundation. It allowed anyone to send Ether directly to the Foundation through a transparent, permissionless contract. In return, contributors received a small experimental token known as the Unicorn token, issued automatically by the contract.

Source Verified

Etherscan verified

Heuristic Analysis

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

Detected Type: DAO

Frontier Era

The initial release of Ethereum. A bare-bones implementation for technical users.

Block span: 01,149,999
July 30, 2015March 14, 2016

Bytecode Overview

Opcodes7,189
Unique Opcodes228
Jump Instructions301
Storage Operations275

Verified Source Available

Source verified on Etherscan.

Show source code (Solidity)
contract owned {
        address public owner;

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

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

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

/* The token is used as a voting shares */
contract token {
        function mintToken(address target, uint256 mintedAmount);
}

contract Congress is owned {

        /* Contract Variables and events */
        uint public minimumQuorum;
        uint public debatingPeriodInMinutes;
        int public majorityMargin;
        Proposal[] public proposals;
        uint public numProposals;
        mapping(address => uint) public memberId;
        Member[] public members;

        address public unicornAddress;
        uint public priceOfAUnicornInFinney;

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

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

        struct Member {
                address member;
                uint voteWeight;
                bool canAddProposals;
                string name;
                uint memberSince;
        }

        struct Vote {
                bool inSupport;
                address voter;
                string justification;
        }


        /* First time setup */
        function Congress(uint minimumQuorumForProposals, uint minutesForDebate, int marginOfVotesForMajority, address congressLeader) {
                minimumQuorum = minimumQuorumForProposals;
                debatingPeriodInMinutes = minutesForDebate;
                majorityMargin = marginOfVotesForMajority;
                members.length++;
                members[0] = Member({
                        member: 0,
                        voteWeight: 0,
                        canAddProposals: false,
                        memberSince: now,
                        name: ''
                });
                if (congressLeader != 0) owner = congressLeader;

        }

        /*make member*/
        function changeMembership(address targetMember, uint voteWeight, bool canAddProposals, string memberName) onlyOwner {
                uint id;
                if (memberId[targetMember] == 0) {
                        memberId[targetMember] = members.length;
                        id = members.length++;
                        members[id] = Member({
                                member: targetMember,
                                voteWeight: voteWeight,
                                canAddProposals: canAddProposals,
                                memberSince: now,
                                name: memberName
                        });
                } else {
                        id = memberId[targetMember];
                        Member m = members[id];
                        m.voteWeight = voteWeight;
                        m.canAddProposals = canAddProposals;
                        m.name = memberName;
                }

                MembershipChanged(targetMember);

        }

        /*change rules*/
        function changeVotingRules(uint minimumQuorumForProposals, uint minutesForDebate, int marginOfVotesForMajority) onlyOwner {
                minimumQuorum = minimumQuorumForProposals;
                debatingPeriodInMinutes = minutesForDebate;
                majorityMargin = marginOfVotesForMajority;

                ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, majorityMargin);
        }

        // ribbonPriceInEther
        function changeUnicorn(uint newUnicornPriceInFinney, address newUnicornAddress) onlyOwner {
                unicornAddress = newUnicornAddress;
                priceOfAUnicornInFinney = newUnicornPriceInFinney;
        }

        /* Function to create a new proposal */
        function newProposalInWei(address beneficiary, uint weiAmount, string JobDescription, bytes transactionBytecode) returns(uint proposalID) {
                if (memberId[msg.sender] == 0 || !members[memberId[msg.sender]].canAddProposals) throw;

                proposalID = proposals.length++;
                Proposal p = proposals[proposalID];
                p.recipient = beneficiary;
                p.amount = weiAmount;
                p.description = JobDescription;
                p.proposalHash = sha3(beneficiary, weiAmount, transactionBytecode);
                p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
                p.executed = false;
                p.proposalPassed = false;
                p.numberOfVotes = 0;
                ProposalAdded(proposalID, beneficiary, weiAmount, JobDescription);
                numProposals = proposalID + 1;
        }

        /* Function to create a new proposal */
        function newProposalInEther(address beneficiary, uint etherAmount, string JobDescription, bytes transactionBytecode) returns(uint proposalID) {
                if (memberId[msg.sender] == 0 || !members[memberId[msg.sender]].canAddProposals) throw;

                proposalID = proposals.length++;
                Proposal p = proposals[proposalID];
                p.recipient = beneficiary;
                p.amount = etherAmount * 1 ether;
                p.description = JobDescription;
                p.proposalHash = sha3(beneficiary, etherAmount * 1 ether, 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 amount, bytes transactionBytecode) constant returns(bool codeChecksOut) {
                Proposal p = proposals[proposalNumber];
                return p.proposalHash == sha3(beneficiary, amount, transactionBytecode);
        }

        function vote(uint proposalNumber, bool supportsProposal, string justificationText) returns(uint voteID) {
                if (memberId[msg.sender] == 0) throw;

                uint voteWeight = members[memberId[msg.sender]].voteWeight;

                Proposal p = proposals[proposalNumber]; // Get the proposal
                if (p.voted[msg.sender] == true) throw; // If has already voted, cancel
                p.voted[msg.sender] = true; // Set this voter as having voted
                p.numberOfVotes += voteWeight; // Increase the number of votes
                if (supportsProposal) { // If they support the proposal
                        p.currentResult += int(voteWeight); // Increase score
                } else { // If they don't
                        p.currentResult -= int(voteWeight); // Decrease the score
                }
                // Create a log of this event
                Voted(proposalNumber, supportsProposal, msg.sender, justificationText);
        }

        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? 
                        || p.numberOfVotes < minimumQuorum) // has minimum quorum?
                        throw;

                /* execute result */
                if (p.currentResult > majorityMargin) {
                        /* If difference between support and opposition is larger than margin */
                        p.recipient.call.value(p.amount)(transactionBytecode);
                        p.executed = true;
                        p.proposalPassed = true;
                } else {
                        p.executed = true;
                        p.proposalPassed = false;
                }
                // Fire Events
                ProposalTallied(proposalNumber, p.currentResult, p.numberOfVotes, p.proposalPassed);
        }

        function() {
                if (msg.value > priceOfAUnicornInFinney) {
                        token unicorn = token(unicornAddress);
                        unicorn.mintToken(msg.sender, msg.value / (priceOfAUnicornInFinney * 1 finney));
                }

        }
}


contract MyToken is owned {
        /* Public variables of the token */
        string public name;
        string public symbol;
        uint8 public decimals;
        uint256 public totalSupply;

        /* This creates an array with all balances */
        mapping(address => uint256) public balanceOf;
        mapping(address => bool) public frozenAccount;
        mapping(address => mapping(address => uint)) public allowance;
        mapping(address => mapping(address => uint)) public spentAllowance;


        /* This generates a public event on the blockchain that will notify clients */
        event Transfer(address indexed from, address indexed to, uint256 value);
        event FrozenFunds(address target, bool frozen);

        /* Initializes contract with initial supply tokens to the creator of the contract */
        function MyToken(uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol, address centralMinter) {
                if (centralMinter != 0) owner = centralMinter; // Sets the minter
                balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens                    
                name = tokenName; // Set the name for display purposes     
                symbol = tokenSymbol; // Set the symbol for display purposes    
                decimals = decimalUnits; // Amount of decimals for display purposes        
                totalSupply = initialSupply;
        }

        /* Send coins */
        function transfer(address _to, uint256 _value) {
                if (balanceOf[msg.sender] < _value) throw; // Check if the sender has enough   
                if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
                if (frozenAccount[msg.sender]) throw; // Check if frozen
                balanceOf[msg.sender] -= _value; // Subtract from the sender
                balanceOf[_to] += _value; // Add the same to the recipient            
                Transfer(msg.sender, _to, _value); // Notify anyone listening that this transfer took place
        }

        function mintToken(address target, uint256 mintedAmount) onlyOwner {
                balanceOf[target] += mintedAmount;
                totalSupply += mintedAmount;
                Transfer(owner, target, mintedAmount);
        }

        function freezeAccount(address target, bool freeze) onlyOwner {
                frozenAccount[target] = freeze;
                FrozenFunds(target, freeze);
        }

        function transferFrom(address _from, address _to, uint256 _value) returns(bool success) {
                if (balanceOf[_from] < _value) throw; // Check if the sender has enough   
                if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows
                if (frozenAccount[_from]) throw; // Check if frozen
                if (spentAllowance[_from][msg.sender] + _value > allowance[_from][msg.sender]) throw; // Check allowance
                balanceOf[_from] -= _value; // Subtract from the sender
                balanceOf[_to] += _value; // Add the same to the recipient            
                spentAllowance[_from][msg.sender] += _value;
                Transfer(msg.sender, _to, _value);
        }

        function approve(address _spender, uint256 _value) returns(bool success) {
                allowance[msg.sender][_spender] = _value;
        }

        function() {
                //owner.send(msg.value);
                throw;
        }
}

External Links