-
Notifications
You must be signed in to change notification settings - Fork 0
/
CrowdFunder.sol
131 lines (110 loc) · 3.58 KB
/
CrowdFunder.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// *** EXAMPLE: A crowdfunding example (broadly similar to Kickstarter) ***
// ** START EXAMPLE **
// CrowdFunder.sol
/// @title CrowdFunder
/// @author Ashwani K Luhaniwal
contract CrowdFunder {
// Variables set on create by creator
address public creator;
address public fundRecipient; // creator may be different than recipient
uint public minimumToRaise; // required to tip, else everyone gets refund
string campaignUrl;
byte constant version = 1;
// Data structures
enum State {
Fundraising,
ExpiredRefund,
Successful
}
struct Contribution {
uint amount;
address contributor;
}
// State variables
State public state = State.Fundraising; // initialize on create
uint public totalRaised;
uint public raiseBy;
uint public completeAt;
Contribution[] contributions;
// event declaration
event LogFundingReceived(address addr, uint amount, uint currentTotal);
event LogWinnerPaid(address winnerAddress);
// modifier definition
modifier inState(State _state) {
if (state != _state) throw;
_;
}
modifier isCreator() {
if (msg.sender != creator) throw;
_;
}
// Wait 6 months after final contract state before allowing contract destruction
modifier atEndOfLifecycle() {
if ( !((state == State.ExpiredRefund || state == State.Successful) && completeAt + 6 months < now) ) {
throw;
}
_;
}
// constructor
function CrowdFunder(
uint timeInHoursForFundraising,
string _campaignUrl,
address _fundRecipient,
uint _minimumToRaise)
{
creator = msg.sender;
fundRecipient = _fundRecipient;
campaignUrl = _campaignUrl;
minimumToRaise = _minimumToRaise;
raiseBy = now + (timeInHoursForFundraising * 1 hours);
}
function contribute() public inState(State.Fundraising) {
contributions.push (
Contribution({
amount: msg.value,
contributor: msg.sender
}) // use array, so can iterate
);
totalRaised += msg.value;
LogFundingReceived(msg.sender, msg.value, totalRaised);
checkIfFundingCompleteOrExpired();
return contributions.length - 1; // return id
}
function checkIfFundingCompleteOrExpired() {
if (totalRaised > minimumToRaise) {
state = State.Successful;
payOut();
// could incentivize sender who initiated state change here
}
else if (now > raiseBy) {
state = State.ExpiredRefund; // backers can now collect refunds by calling getRefund(id)
}
completeAt = now;
}
function payOut() public inState(State.Successful) {
if (!fundRecipient.send(this.balance)) {
throw;
}
LogWinnerPaid(fundRecipient);
}
function getRefund(id) public inState(State.ExpiredRefund) {
if (contributions.length <= id || id < 0 || contributions[id].amount == 0) {
throw;
}
uint amountToRefund = contributions[id].amount;
contributions[id].amount = 0;
if (!contributions[id].contributor.send(amountToSend)) {
contributions[id].amount = amountToSend;
return false;
}
return true;
}
function removeContract() public isCreator() atEndOfLifecycle() {
selfdestruct(msg.sender);
// creator gets all money that hasn't be claimed
}
function() {
throw;
}
}
// ** END EXAMPLE **