1
- Require Import Coq.Lists.List.
2
- Require Import Coq.Strings.String.
1
+ Require Export Coq.Lists.List.
2
+ Require Export Coq.Strings.String.
3
3
4
4
Import ListNotations.
5
5
@@ -21,6 +21,9 @@ Parameter TokenKind : Set.
21
21
will be positive integer or a positive real number, if we allow to own a part of a token. *)
22
22
Parameter TokenQuantity : forall (token_kind : TokenKind), Set .
23
23
24
+ (** A quantity of one token for a given [token_kind]. *)
25
+ Parameter TokenQuantityOne : forall {token_kind : TokenKind}, TokenQuantity token_kind.
26
+
24
27
(** The primitives that we assume as given on the types provided above. *)
25
28
Module Primitives.
26
29
(** Create a new kind of token, different from all the kinds that existed before, and return the
@@ -69,6 +72,22 @@ Module Primitives.
69
72
TokenQuantity token_kind ->
70
73
World ->
71
74
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.
72
91
End Primitives.
73
92
74
93
(** Actions are the primitives that we can run in our DSL to interact with tokens, make transfers,
@@ -93,6 +112,8 @@ Module Action.
93
112
(account : User)
94
113
(value : TokenQuantity token_kind) :
95
114
t bool
115
+ | GetUniqueTokenKindOwner (token_kind : TokenKind) : t (option User)
116
+ | UserEq (user1 user2 : User) : t bool
96
117
.
97
118
98
119
(** This function maps the actions we defined to the primitives acting on the world above *)
@@ -116,6 +137,10 @@ Module Action.
116
137
| Some world' => (true, world')
117
138
| None => (false, world)
118
139
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)
119
144
end .
120
145
End Action.
121
146
@@ -220,88 +245,6 @@ Module SmartContract.
220
245
Arguments t : clear implicits.
221
246
End SmartContract.
222
247
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
-
305
248
(** Here we will define what it means for a smart contract defined in our DSL to be safe, in the
306
249
sense that no one can steal money from others. *)
307
250
Module NoStealing.
@@ -323,6 +266,8 @@ Module NoStealing.
323
266
| Action.Approve _ user _ _ =>
324
267
user = sender
325
268
| Action.Mint token_kind account value => True
269
+ | Action.GetUniqueTokenKindOwner _ => True
270
+ | Action.UserEq _ _ => True
326
271
end .
327
272
End InAction.
328
273
@@ -353,107 +298,3 @@ Module NoStealing.
353
298
}.
354
299
End InSmartContract.
355
300
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