-
Notifications
You must be signed in to change notification settings - Fork 0
/
Crowdfunding.ds
112 lines (102 loc) · 3.58 KB
/
Crowdfunding.ds
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
(* Based on https://github.com/Zilliqa/scilla-coq/blob/master/Contracts/Crowdfunding.v used under the BSD-2-Clause license *)
(* Also a relevant reference: https://scilla.readthedocs.io/en/latest/scilla-by-example.html#a-second-example-crowdfunding *)
type message := int
const _deadlinePassed_msg = 0
const _successfullyDonated_msg = 1
const _alreadyDonated_msg = 2
const _funded_msg = 3
const _failed_msg = 4
const _too_early_to_claim_funds_msg = 5
const _too_early_to_reclaim_msg = 6
const _cannot_refund_msg = 7
const _here_is_your_money_msg = 8
const _only_owner_can_get_funds_msg = 9
event
| Message (msg : message)
object signature CrowdfundingSig = {
donate : unit -> unit;
getFunds : unit -> unit;
claim: unit -> unit
}
object Crowdfunding () : CrowdfundingSig {
let owner : address := address(0x9Be6210aD2EB7D510C7dBC7eA0C91e4591a9f813)
let max_block : uint := 0u140 (* The last block number when donations are accepted. *)
let goal : int := 50
let backers : mapping[address] int := mapping_init
let funded : bool := false
let donate () =
assert(msg_sender <> this_address);
assert(msg_value >= 0);
let bs = backers in
let blk = block_number in
let _max_block = max_block in
if (blk > _max_block) then
begin
emit Message(_deadlinePassed_msg);
assert(false) (* Revert: do not accept funds *)
end
else
begin
let backed_amount = backers[msg_sender] in
if (backed_amount = 0) then
backers[msg_sender] := msg_value
else
begin
emit Message(_alreadyDonated_msg);
assert(false) (* Revert: do not accept funds *)
end
end
let getFunds () =
assert(msg_sender <> this_address);
assert(msg_value = 0);
let _owner = owner in
if (msg_sender = _owner) then
begin
let blk = block_number in
let bal = balance(this_address) in
let _max_block = max_block in
if (blk > _max_block) then
let _goal = goal in
if (_goal <= bal) then
begin
funded := true;
(* Send all funds to owner *)
emit Message(_funded_msg);
transferEth(_owner, bal)
end
else
(* Funding campaign failed, do not send funds to owner *)
emit Message(_failed_msg)
else
(* Too early to claim funds, do not send funds to owner. *)
emit Message(_too_early_to_claim_funds_msg)
end
else
emit Message(_only_owner_can_get_funds_msg)
let claim() =
assert(msg_sender <> this_address);
assert(msg_value = 0);
let blk = block_number in
let _max_block = max_block in
if (blk <= _max_block) then
(* Too early to reclaim, do not send funds back. *)
emit Message(_too_early_to_reclaim_msg)
else
let bal = balance(this_address) in
let backed_amount = backers[msg_sender] in
let _funded = funded in
let _goal = goal in
if (backed_amount = 0 \/ _funded \/ _goal <= bal) then
(* Didn't back or campaign was successful so can't refund. *)
emit Message(_cannot_refund_msg)
else
begin
(* Can refund, send funds back *)
backers[msg_sender] := 0;
emit Message(_here_is_your_money_msg);
transferEth(msg_sender, backed_amount)
end
}
layer CONTRACT : [ { } ] {crowdfunding : CrowdfundingSig} = {
crowdfunding = Crowdfunding
}