@@ -36,6 +36,14 @@ Module Primitives.
36
36
World ->
37
37
TokenQuantity token_kind.
38
38
39
+ (** Get the number of token that a [spender] is allowed to spend from a [user] *)
40
+ Parameter get_allowance :
41
+ forall (token_kind : TokenKind),
42
+ forall (user : User),
43
+ forall (spender : User),
44
+ World ->
45
+ TokenQuantity token_kind.
46
+
39
47
(** Transfer a certain quantity of tokens from a user to another, and return the new state of the
40
48
world where the quantity of tokens they both own has been updated. *)
41
49
Parameter transfer :
@@ -45,6 +53,22 @@ Module Primitives.
45
53
TokenQuantity token_kind ->
46
54
World ->
47
55
option World.
56
+
57
+ (** Set the allowance for a certain [spender] at a certain amount from the account of a [user] *)
58
+ Parameter approve :
59
+ forall (token_kind : TokenKind),
60
+ forall (user : User),
61
+ forall (spender : User),
62
+ TokenQuantity token_kind ->
63
+ World ->
64
+ World.
65
+
66
+ Parameter mint :
67
+ forall (token_kind : TokenKind),
68
+ User ->
69
+ TokenQuantity token_kind ->
70
+ World ->
71
+ option World.
48
72
End Primitives.
49
73
50
74
(** Actions are the primitives that we can run in our DSL to interact with tokens, make transfers,
@@ -59,9 +83,17 @@ Module Action.
59
83
| CreateTokenKind : t TokenKind
60
84
(** Ask for the number of tokens owned by a user *)
61
85
| GetBalance (token_kind : TokenKind) (user : User) : t (TokenQuantity token_kind)
86
+ | GetAllowance (token_kind : TokenKind) (user spender : User) : t (TokenQuantity token_kind)
62
87
(** Ask to transfer token from a user to another one. The result is a boolean stating if the
63
88
transfer was successful, meaning if there were enough funds. *)
64
- | Transfer (token_kind : TokenKind) (from to : User) (value : TokenQuantity token_kind) : t bool.
89
+ | Transfer (token_kind : TokenKind) (from to : User) (value : TokenQuantity token_kind) : t bool
90
+ | Approve (token_kind : TokenKind) (user spender : User) (value : TokenQuantity token_kind) : t unit
91
+ | Mint
92
+ (token_kind : TokenKind)
93
+ (account : User)
94
+ (value : TokenQuantity token_kind) :
95
+ t bool
96
+ .
65
97
66
98
(** This function maps the actions we defined to the primitives acting on the world above *)
67
99
Definition run (world : World) {A : Set } (action : t A) : A * World :=
@@ -70,11 +102,20 @@ Module Action.
70
102
Primitives.create_token_kind world
71
103
| GetBalance token_kind user =>
72
104
(Primitives.get_balance token_kind user world, world)
105
+ | GetAllowance token_kind user spender =>
106
+ (Primitives.get_allowance token_kind user spender world, world)
73
107
| Transfer token_kind from to value =>
74
108
match Primitives.transfer token_kind from to value world with
75
109
| Some world' => (true, world')
76
110
| None => (false, world)
77
111
end
112
+ | Approve token_kind user spender value =>
113
+ (tt, Primitives.approve token_kind user spender value world)
114
+ | Mint token_kind account value =>
115
+ match Primitives.mint token_kind account value world with
116
+ | Some world' => (true, world')
117
+ | None => (false, world)
118
+ end
78
119
end .
79
120
End Action.
80
121
@@ -205,7 +246,10 @@ Module Erc20.
205
246
Module Command.
206
247
Inductive t {token_kind : InitOutput} : Set -> Set :=
207
248
| BalanceOf : User -> t (TokenQuantity token_kind)
208
- | Transfer : User -> TokenQuantity token_kind -> t unit.
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.
209
253
Arguments t : clear implicits.
210
254
End Command.
211
255
@@ -232,6 +276,10 @@ Module Erc20.
232
276
(* We run the action to get the balance *)
233
277
let ! balance := M.MakeAction (Action.GetBalance token_kind user) in
234
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))
235
283
(* The "transfer" entrypoint *)
236
284
| Command.Transfer to value =>
237
285
(* We run the action to make the transfer and to know if it succeeded *)
@@ -240,6 +288,16 @@ Module Erc20.
240
288
M.Pure (Some (tt, state))
241
289
else
242
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
243
301
end ;
244
302
|}.
245
303
End Erc20.
@@ -257,10 +315,14 @@ Module NoStealing.
257
315
| Action.CreateTokenKind => True
258
316
(** Asking for the balance of a user is safe (all data are public in a blockchain) *)
259
317
| Action.GetBalance _ _ => True
318
+ | Action.GetAllowance _ _ _ => True
260
319
(** Transferring tokens is only safe is the account from which we take the money is the same
261
320
as the user running the smart contract *)
262
321
| Action.Transfer token_kind from to value =>
263
322
from = sender
323
+ | Action.Approve _ user _ _ =>
324
+ user = sender
325
+ | Action.Mint token_kind account value => True
264
326
end .
265
327
End InAction.
266
328
@@ -331,6 +393,16 @@ Module Erc20IsSafe.
331
393
}
332
394
apply ActionTree.Forall.Pure.
333
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
+ }
334
406
{ (* Transfer *)
335
407
unfold NoStealing.InRun.t; cbn.
336
408
(* We have two cases, depending on whether the transfer succeeded or not. In both cases we
@@ -353,6 +425,35 @@ Module Erc20IsSafe.
353
425
apply ActionTree.Forall.Pure.
354
426
}
355
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
+ }
356
457
}
357
458
Qed .
358
459
End Erc20IsSafe.
0 commit comments