Skip to content

Commit cc5c67a

Browse files
authored
Merge pull request #4 from formal-land/guillaume-claret@split-files
Split the Erc20.v file
2 parents 583cf30 + 1de3fd7 commit cc5c67a

File tree

3 files changed

+351
-188
lines changed

3 files changed

+351
-188
lines changed

erc20.v Common.v

+29-188
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Require Import Coq.Lists.List.
2-
Require Import Coq.Strings.String.
1+
Require Export Coq.Lists.List.
2+
Require Export Coq.Strings.String.
33

44
Import ListNotations.
55

@@ -21,6 +21,9 @@ Parameter TokenKind : Set.
2121
will be positive integer or a positive real number, if we allow to own a part of a token. *)
2222
Parameter TokenQuantity : forall (token_kind : TokenKind), Set.
2323

24+
(** A quantity of one token for a given [token_kind]. *)
25+
Parameter TokenQuantityOne : forall {token_kind : TokenKind}, TokenQuantity token_kind.
26+
2427
(** The primitives that we assume as given on the types provided above. *)
2528
Module Primitives.
2629
(** Create a new kind of token, different from all the kinds that existed before, and return the
@@ -69,6 +72,22 @@ Module Primitives.
6972
TokenQuantity token_kind ->
7073
World ->
7174
option World.
75+
76+
(** Get the unique owner of a certain token kind. This owner must some bits of the token kind,
77+
and there must be no other owner for this token kind. *)
78+
Parameter get_unique_token_kind_owner :
79+
forall (token_kind : TokenKind),
80+
World ->
81+
option User.
82+
83+
Parameter user_eq :
84+
forall (user1 user2 : User),
85+
bool.
86+
87+
Axiom user_eq_is_valid :
88+
forall (user1 user2 : User),
89+
user_eq user1 user2 = true ->
90+
user1 = user2.
7291
End Primitives.
7392

7493
(** Actions are the primitives that we can run in our DSL to interact with tokens, make transfers,
@@ -93,6 +112,8 @@ Module Action.
93112
(account : User)
94113
(value : TokenQuantity token_kind) :
95114
t bool
115+
| GetUniqueTokenKindOwner (token_kind : TokenKind) : t (option User)
116+
| UserEq (user1 user2 : User) : t bool
96117
.
97118

98119
(** This function maps the actions we defined to the primitives acting on the world above *)
@@ -116,6 +137,10 @@ Module Action.
116137
| Some world' => (true, world')
117138
| None => (false, world)
118139
end
140+
| GetUniqueTokenKindOwner token_kind =>
141+
(Primitives.get_unique_token_kind_owner token_kind world, world)
142+
| UserEq user1 user2 =>
143+
(Primitives.user_eq user1 user2, world)
119144
end.
120145
End Action.
121146

@@ -220,88 +245,6 @@ Module SmartContract.
220245
Arguments t : clear implicits.
221246
End SmartContract.
222247

223-
(** Here we give an application of our DSL above with a representation of a simplified version of
224-
an [ERC-20] smart contract. *)
225-
Module Erc20.
226-
(** The init parameters are a name and a symbol for the token we are creating. They do not play
227-
any role in the computations, but are there in the ERC-20 of OpenZeppelin that we study. *)
228-
Definition InitInput : Set :=
229-
string * string.
230-
231-
(** The init outputs a new token kind *)
232-
Definition InitOutput : Set :=
233-
TokenKind.
234-
235-
(** The state of the contract is just the name and the symbol of its token. The token balance for
236-
each user is stored in the global world and we do not have to handle it here. *)
237-
Module State.
238-
Record t : Set := {
239-
name : string;
240-
symbol : string;
241-
}.
242-
End State.
243-
244-
(** The commands representing the entrypoints of our smart contract, with the type of their
245-
output. *)
246-
Module Command.
247-
Inductive t {token_kind : InitOutput} : Set -> Set :=
248-
| BalanceOf : User -> t (TokenQuantity token_kind)
249-
| GetAllowance : User -> User -> t (TokenQuantity token_kind)
250-
| Transfer : User -> TokenQuantity token_kind -> t unit
251-
| Approve (spender : User) (quantity : TokenQuantity token_kind) : t unit
252-
| Mint (account : User) (value : TokenQuantity token_kind) : t unit.
253-
Arguments t : clear implicits.
254-
End Command.
255-
256-
(** The definition of our ERC-20 smart contract *)
257-
Definition smart_contract :
258-
SmartContract.t
259-
InitInput
260-
InitOutput
261-
Command.t
262-
State.t :=
263-
{|
264-
(* The constructor function *)
265-
SmartContract.init _sender '(name, symbol) :=
266-
let! token_kind := M.MakeAction Action.CreateTokenKind in
267-
let state := {|
268-
State.name := name;
269-
State.symbol := symbol;
270-
|} in
271-
M.Pure (Some (token_kind, state));
272-
SmartContract.call A token_kind sender command state :=
273-
match command in Command.t _ A return M.t (option (A * _)) with
274-
(* The "balanceOf" entrypoint *)
275-
| Command.BalanceOf user =>
276-
(* We run the action to get the balance *)
277-
let! balance := M.MakeAction (Action.GetBalance token_kind user) in
278-
M.Pure (Some (balance, state))
279-
(* The "allowance" entrypoint *)
280-
| Command.GetAllowance user spender =>
281-
let! allowance := M.MakeAction (Action.GetAllowance token_kind user spender) in
282-
M.Pure (Some (allowance, state))
283-
(* The "transfer" entrypoint *)
284-
| Command.Transfer to value =>
285-
(* We run the action to make the transfer and to know if it succeeded *)
286-
let! is_success := M.MakeAction (Action.Transfer token_kind sender to value) in
287-
if is_success then
288-
M.Pure (Some (tt, state))
289-
else
290-
M.Pure None
291-
(* The "approve" entrypoint *)
292-
| Command.Approve spender value =>
293-
let! _ := M.MakeAction (Action.Approve token_kind sender spender value) in
294-
M.Pure (Some (tt, state))
295-
| Command.Mint account value =>
296-
let! is_success := M.MakeAction (Action.Mint token_kind account value) in
297-
if is_success then
298-
M.Pure (Some (tt, state))
299-
else
300-
M.Pure None
301-
end;
302-
|}.
303-
End Erc20.
304-
305248
(** Here we will define what it means for a smart contract defined in our DSL to be safe, in the
306249
sense that no one can steal money from others. *)
307250
Module NoStealing.
@@ -323,6 +266,8 @@ Module NoStealing.
323266
| Action.Approve _ user _ _ =>
324267
user = sender
325268
| Action.Mint token_kind account value => True
269+
| Action.GetUniqueTokenKindOwner _ => True
270+
| Action.UserEq _ _ => True
326271
end.
327272
End InAction.
328273

@@ -353,107 +298,3 @@ Module NoStealing.
353298
}.
354299
End InSmartContract.
355300
End NoStealing.
356-
357-
(** Now we will verify that our ERC-20 smart contract is safe *)
358-
Module Erc20IsSafe.
359-
(** Here is the specification saying that our smart contract is safe. It applies the predicate
360-
saying that a smart contract is safe to our definition of ERC-20. *)
361-
Lemma is_safe : NoStealing.InSmartContract.t Erc20.smart_contract.
362-
(** Here is the proof that the specification is correct. It should be executed in an IDE to see
363-
the proof state as we progress line by line.
364-
365-
The general idea is to go over all the possible execution scenarios of the smart contract,
366-
with the init, the "balanceOf", and the "transfer" entrypoints, and to prove that they are all
367-
safe.
368-
*)
369-
Proof.
370-
constructor; intros; cbn.
371-
{ (* init *)
372-
destruct init_input as [name symbol].
373-
unfold NoStealing.InRun.t; cbn.
374-
destruct Primitives.create_token_kind.
375-
apply ActionTree.Forall.Let. {
376-
(* The init is safe because the action we make to create a new token kind is safe *)
377-
apply ActionTree.Forall.MakeAction.
378-
cbn.
379-
trivial.
380-
}
381-
apply ActionTree.Forall.Pure.
382-
}
383-
{ (* call *)
384-
destruct command.
385-
{ (* BalanceOf *)
386-
unfold NoStealing.InRun.t; cbn.
387-
apply ActionTree.Forall.Let. {
388-
(* The "balanceOf" entrypoint is safe because the action we make to get the balance of a
389-
user is safe *)
390-
apply ActionTree.Forall.MakeAction.
391-
cbn.
392-
trivial.
393-
}
394-
apply ActionTree.Forall.Pure.
395-
}
396-
{ (* GetAllowance *)
397-
cbn.
398-
unfold NoStealing.InActionTree.t.
399-
apply ActionTree.Forall.Let. {
400-
apply ActionTree.Forall.MakeAction.
401-
cbn.
402-
trivial.
403-
}
404-
apply ActionTree.Forall.Pure.
405-
}
406-
{ (* Transfer *)
407-
unfold NoStealing.InRun.t; cbn.
408-
(* We have two cases, depending on whether the transfer succeeded or not. In both cases we
409-
make a single transfer (or transfer attempt) with the right user for the source account,
410-
so this is safe.
411-
*)
412-
destruct Primitives.transfer; cbn.
413-
{ apply ActionTree.Forall.Let. {
414-
apply ActionTree.Forall.MakeAction.
415-
cbn.
416-
reflexivity.
417-
}
418-
apply ActionTree.Forall.Pure.
419-
}
420-
{ apply ActionTree.Forall.Let. {
421-
apply ActionTree.Forall.MakeAction.
422-
cbn.
423-
reflexivity.
424-
}
425-
apply ActionTree.Forall.Pure.
426-
}
427-
}
428-
{ (* Approve *)
429-
cbn.
430-
apply ActionTree.Forall.Let. {
431-
apply ActionTree.Forall.MakeAction.
432-
cbn.
433-
trivial.
434-
}
435-
apply ActionTree.Forall.Pure.
436-
}
437-
{ (* Mint *)
438-
unfold NoStealing.InRun.t; cbn.
439-
destruct Primitives.mint.
440-
{ cbn.
441-
apply ActionTree.Forall.Let. {
442-
apply ActionTree.Forall.MakeAction.
443-
cbn.
444-
trivial.
445-
}
446-
apply ActionTree.Forall.Pure.
447-
}
448-
{ cbn.
449-
apply ActionTree.Forall.Let. {
450-
apply ActionTree.Forall.MakeAction.
451-
cbn.
452-
trivial.
453-
}
454-
apply ActionTree.Forall.Pure.
455-
}
456-
}
457-
}
458-
Qed.
459-
End Erc20IsSafe.

0 commit comments

Comments
 (0)