This is the archetype version of the ICO process set up by BCDiploma and described at the following address:
archetype icoconstant symbol : string = "BCDT"constant decimals : int = 18(* contribution thresholds *)variable min_contribution : tez = 1tzvariable max_contribution_silver : tez = 10tz(* bcd token data *)variable max_bcd_to_sell : tez = 100000000tzvariable exchange_rate_bcd_tez : int = 13000(* round caps *)variable soft_cap : tez = 1800tzvariable presales_cap : tez = 1800tzvariable round1_cap : tez = 3600tz(* presales_cap + 1600 *)(* Number tokens sent, eth raised, ... *)variable nb_bcd_sold : tez = 0tzvariable nb_tez_raised : tez = 0tz(* Roles *)variable owner : role = @tz1XZ7s6uStC2hZVpPQhXgcdXPwxifByF3Aovariable whitelister : role = @tz1Lc2qBKEWCBeDU8npG6zCeCqpmaegRi6Jgvariable reserve : role = @tz1bfVgcJC4ukaQSHUe1EbrUd5SekXeP9CWkvariable community : role = @tz1iawHeddgggn6P5r5jtq2wDRqcJVksGVSa(* contributor *)enum whitelist =| Silver| Goldasset contributor identified by id {id : address;wlist : whitelist;contrib : tez = 0tz;}enum gstate =| Init initial (* ICO isn't started yet, initial state *)| PresaleRunning (* Presale has started *)| PresaleFinished (* Presale has ended *)| Round1Running (* Round 1 has started *)| Round1Finished (* Round 1 has ended *)| Round2Running (* Round 2 has started *)| Round2Finished (* Round 2 has ended *)variable vstate : gstate = Initfunction is_running () : bool {returnmatch vstate with| PresaleRunning | Round1Running | Round2Running -> true| _ -> falseend}function get_rate () : rational {var coeff : rational =match vstate with| PresaleRunning -> 1.2| Round1Running -> 1.1| _ -> 1end;return (coeff * exchange_rate_bcd_tez)}function get_remaining_tez_to_raise () : tez {returnmatch vstate with| PresaleRunning | PresaleFinished -> presales_cap - nb_tez_raised| Round1Running | Round1Finished -> round1_cap - nb_tez_raised| _ -> (let remaining_bcd : tez = max_bcd_to_sell - nb_bcd_sold in(1 / exchange_rate_bcd_tez) * remaining_bcd)end}function transition_to_finished () : gstate {returnmatch vstate with| PresaleRunning -> PresaleFinished| Round1Running -> Round1Finished| Round1Finished -> Round2Running| _ -> Round2Finishedend}entry contribute () {require {c1 : contributor.contains(caller);c2 : is_running ();c3 : transferred >= min_contribution;c4 : (not (contributor[caller].wlist = Silver and transferred >= max_contribution_silver));}effect {(* cap contribution to max_contrib if necessary *)var lcontrib = transferred;if contributor[caller].wlist = Silverand contributor[caller].contrib + lcontrib >= max_contribution_silverthen lcontrib := max_contribution_silver - contributor[caller].contrib;(* cap contribution to round cap if necessary *)var remaining_tez : tez = get_remaining_tez_to_raise ();if remaining_tez <= lcontribthen (lcontrib := remaining_tez;vstate := transition_to_finished ());(* convert contribution to nb of bcd tokens *)var rate = get_rate ();var nb_tokens : tez = rate * lcontrib;(* update ico stats *)nb_bcd_sold += nb_tokens;nb_tez_raised += lcontrib;(* update caller's contribution *)contributor[caller].contrib += lcontrib;(* syntaxic sugar forcontributor.update caller { contrib += contrib } *)if lcontrib <= transferredthen transfer (transferred - lcontrib) to caller}}(* the onlyonce extension specifies that withdraw action can beexecuted only once, that is a contributor can withdraw only once. *)entry withdraw () {require {c5 : vstate = Round2Finished;c6 : nb_tez_raised <= soft_cap;c7 : contributor[caller].contrib > 0tz;}effect {transfer contributor[caller].contrib to caller;(* do not forget this *)contributor[caller].contrib := 0tz}}