ICO
A real life ico process
This is the archetype version of the ICO process set up by BCDiploma and described at the following address:
1
archetype[%erc20%] ico
2
3
constant symbol : string = "BCDT"
4
5
constant decimals : int = 18
6
7
(* contribution thresholds *)
8
variable[%mutable (owner, (state = Init))%] min_contribution : tez = 1tz
9
variable[%mutable (owner, (state = Init))%] max_contribution_silver : tez = 10tz
10
11
(* bcd token data *)
12
variable[%mutable (owner, (state = Init))%] max_bcd_to_sell : tez = 100000000tz
13
variable[%mutable (owner, (state = Init))%] exchange_rate_bcd_tez : int = 13000
14
15
(* round caps *)
16
variable[%mutable (owner, (state = Init))%] soft_cap : tez = 1800tz
17
variable[%mutable (owner, (state = Init))%] presales_cap : tez = 1800tz
18
variable[%mutable (owner, (state = Init))%] round1_cap : tez = 3600tz
19
(* presales_cap + 1600 *)
20
21
(* Number tokens sent, eth raised, ... *)
22
variable nb_bcd_sold : tez = 0tz
23
variable nb_tez_raised : tez = 0tz
24
25
(* Roles *)
26
27
variable[%transferable%] owner : role = @tz1_owner
28
29
variable whitelister : role = @tz1Lc2qBKEWCBeDU8npG6zCeCqpmaegRi6Jg
30
31
variable reserve : role = @tz1bfVgcJC4ukaQSHUe1EbrUd5SekXeP9CWk
32
33
variable community : role = @tz1iawHeddgggn6P5r5jtq2wDRqcJVksGVSa
34
35
(* contributor *)
36
37
enum whitelist =
38
| Silver
39
| Gold
40
41
asset[@add @remove @update owner (state = Init)]
42
contributor identified by id {
43
id : address;
44
wlist : whitelist;
45
contrib : tez = 0tz;
46
}
47
48
enum gstate =
49
| Init initial (* ICO isn't started yet, initial state *)
50
| PresaleRunning (* Presale has started *)
51
| PresaleFinished (* Presale has ended *)
52
| Round1Running (* Round 1 has started *)
53
| Round1Finished (* Round 1 has ended *)
54
| Round2Running (* Round 2 has started *)
55
| Round2Finished (* Round 2 has ended *)
56
57
variable vstate : gstate = Init
58
59
function is_running () : bool {
60
return
61
match vstate with
62
| PresaleRunning | Round1Running | Round2Running -> true
63
| _ -> false
64
end
65
}
66
67
function get_rate () : rational {
68
let coeff : rational =
69
match vstate with
70
| PresaleRunning -> 1.2
71
| Round1Running -> 1.1
72
| _ -> 1
73
end
74
in
75
return coeff * exchange_rate_bcd_tez
76
}
77
78
function get_remaining_tez_to_raise () : tez {
79
return
80
match vstate with
81
| PresaleRunning | PresaleFinished -> presales_cap - nb_tez_raised
82
| Round1Running | Round1Finished -> round1_cap - nb_tez_raised
83
| _ -> (
84
let remaining_bcd : tez = max_bcd_to_sell - nb_bcd_sold in
85
remaining_bcd / exchange_rate_bcd_tez)
86
end
87
}
88
89
function transition_to_finished () : gstate {
90
return
91
match vstate with
92
| PresaleRunning -> PresaleFinished
93
| Round1Running -> Round1Finished
94
| Round1Finished -> Round2Running
95
| _ -> Round2Finished
96
end
97
}
98
99
action contribute () {
100
101
(* specification {
102
postcondition p1 {
103
let some c = contributor.get(caller) in
104
let some c_old = before.contributor.get(caller) in
105
transferred = transferred_to(caller) + c.contrib - c_old.contrib
106
otherwise true
107
otherwise true
108
}
109
} *)
110
111
require {
112
c1 : contributor.contains(caller);
113
c2 : is_running ();
114
c3 : transferred >= min_contribution;
115
c4 : (let c = contributor.get(caller) in
116
not (c.wlist = Silver and transferred >= max_contribution_silver));
117
}
118
119
effect {
120
let c = contributor.get(caller) in
121
(* cap contribution to max_contrib if necessary *)
122
let lcontrib = transferred in
123
if c.wlist = Silver
124
and c.contrib + lcontrib >= max_contribution_silver
125
then lcontrib := max_contribution_silver - c.contrib;
126
(* cap contribution to round cap if necessary *)
127
let remaining_tez : tez = get_remaining_tez_to_raise () in
128
if remaining_tez <= lcontrib
129
then (
130
lcontrib := remaining_tez;
131
vstate := transition_to_finished ()
132
);
133
(* convert contribution to nb of bcd tokens *)
134
let rate = get_rate () in
135
let nb_tokens : tez = lcontrib * rate in
136
(* update ico stats *)
137
nb_bcd_sold += nb_tokens;
138
nb_tez_raised += lcontrib;
139
(* update caller's contribution *)
140
c.contrib += lcontrib;
141
(* syntaxic sugar for
142
contributor.update caller { contrib += contrib } *)
143
if lcontrib <= transferred
144
then transfer (transferred - lcontrib) to caller
145
}
146
}
147
148
(* the onlyonce extension specifies that withdraw action can be
149
executed only once, that is a contributor can withdraw only once. *)
150
151
action[%onlyonce%] withdraw () {
152
require {
153
c5 : vstate = Round2Finished;
154
c6 : nb_tez_raised <= soft_cap;
155
c7 : contributor.get(caller).contrib > 0tz;
156
}
157
158
effect {
159
let c = contributor.get(caller) in
160
transfer c.contrib to caller;
161
(* do not forget this *)
162
c.contrib := 0tz
163
}
164
}
Copied!
Last modified 1mo ago
Export as PDF
Copy link
Edit on GitHub