The ethereum.org crowdsale tutorial: contributions run to a deadline against a goal, pay out a separate reward token, and are refunded if the goal is missed.
Historical Significance
This is what a token sale looked like before ERC-20 existed: a fixed price, a deadline, a threshold, an automatic refund if the threshold is missed, and the tokens themselves held in a separate contract addressed through sendCoin rather than transfer. The all-or-nothing goal it implements is the pattern token sales kept using for years after this code was replaced.
Context
Ethereum's Frontier network went live on 30 July 2015 and the ethereum.org tutorials were the main worked examples anyone had. This crowdsale predates ERC-20, which is why the token it pays out is addressed through sendCoin and coinBalanceOf rather than transfer and balanceOf.
Key Facts
Description
A crowdfunding contract from the 2015 ethereum.org tutorial. Its constructor fixes five things that can never be changed afterwards: who receives the money, the funding goal, how many minutes the campaign runs, the price of one reward token, and the address of the token contract that pays contributors.
Contributions arrive through the fallback function. Each sender is appended to a public funders array along with the amount, the running total goes up, and the reward token is asked to send that contributor the amount divided by the price. Once the deadline has passed anyone may call checkGoalReached(): if the total met the goal the balance goes to the beneficiary, otherwise the contract walks the funders array and refunds each one in turn. Either way it then self-destructs to the beneficiary.
The reward tokens have to be sitting in this contract before the sale opens and nothing here checks that they are. The refund loop is unbounded, so a campaign with enough contributors cannot be closed inside a block's gas limit, and neither the refunds nor the payout check whether send() succeeded.
This one pays 0x604dc1e94d7b241da29a7f3ac3589a462fa6c815 on success. It was opened with a goal of 100 ether, a window of 30 minutes, and a price of 0.02 ether for one token, handing out the token at 0x418b25158a556ac70f07c85ff4b29d58078cf395.
Heuristic Analysis
The following characteristics were detected through bytecode analysis and may not be accurate.
Frontier Era
The initial release of Ethereum. A bare-bones implementation for technical users.
Bytecode Overview
Verified Source Available
This contract has verified source code on Etherscan.
Show source code (Solidity)
// Submitted by EthereumHistory (ethereumhistory.com)
contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } }
contract CrowdSale {
address public beneficiary;
uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price;
token public tokenReward;
Funder[] public funders;
event FundTransfer(address backer, uint amount, bool isContribution);
/* data structure to hold information about campaign contributors */
struct Funder {
address addr;
uint amount;
}
/* at initialization, setup the owner */
function CrowdSale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) {
beneficiary = _beneficiary;
fundingGoal = _fundingGoal;
deadline = now + _duration * 1 minutes;
price = _price;
tokenReward = token(_reward);
}
/* The function without name is the default function that is called whenever anyone sends funds to a contract */
function () {
Funder f = funders[++funders.length];
f.addr = msg.sender;
f.amount = msg.value;
amountRaised += f.amount;
tokenReward.sendCoin(msg.sender, f.amount/price);
FundTransfer(f.addr, f.amount, true);
}
modifier afterDeadline() { if (now >= deadline) _ }
/* checks if the goal or time limit has been reached and ends the campaign */
function checkGoalReached() afterDeadline {
if (amountRaised >= fundingGoal){
beneficiary.send(amountRaised);
FundTransfer(beneficiary, amountRaised, false);
} else {
FundTransfer(0, 11, false);
for (uint i = 0; i < funders.length; ++i) {
funders[i].addr.send(funders[i].amount);
FundTransfer(funders[i].addr, funders[i].amount, false);
}
}
suicide(beneficiary);
}
}External Links
Related contracts
Greeter
Same deployerThe go-ethereum Contract Tutorial greeter, deployed with the greeting: Hello World!
0xb214cb...5cd6f7August 20, 2015Greeter
Same deployerThe go-ethereum Contract Tutorial greeter, deployed with the greeting: Hello World!
0x3d7ed1...246503August 22, 2015Contract 0x8e6f6a...5d9651
Same deployerThe mortal base contract of the go-ethereum Contract Tutorial, deployed on its own: it records its creator and lets only that account destroy it.
0x8e6f6a...5d9651August 22, 2015Contract 0x62697e...085ce0
Same deployerThe ethereum.org crowdsale tutorial: contributions run to a deadline against a goal, pay out a separate reward token, and are refunded if the goal is missed.
0x62697e...085ce0August 25, 2015Contract 0xd9ccf0...4ceb28
Same deployerThe ethereum.org crowdsale tutorial: contributions run to a deadline against a goal, pay out a separate reward token, and are refunded if the goal is missed.
0xd9ccf0...4ceb28August 25, 2015Contract 0xa7ccc2...d9cd63
Same deployerThe ethereum.org crowdsale tutorial: contributions run to a deadline against a goal, pay out a separate reward token, and are refunded if the goal is missed.
0xa7ccc2...d9cd63August 25, 2015