forked from tezos-checker/ctez
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fa12.mligo
164 lines (146 loc) · 5.04 KB
/
fa12.mligo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
type transfer =
[@layout:comb]
{ [@annot:from] address_from : address;
[@annot:to] address_to : address;
value : nat }
type approve =
[@layout:comb]
{ spender : address;
value : nat }
type mintOrBurn =
[@layout:comb]
{ quantity : int ;
target : address }
type allowance_key =
[@layout:comb]
{ owner : address;
spender : address }
type getAllowance =
[@layout:comb]
{ request : allowance_key;
callback : nat contract }
type getBalance =
[@layout:comb]
{ owner : address;
callback : nat contract }
type getTotalSupply =
[@layout:comb]
{ request : unit ;
callback : nat contract }
type tokens = (address, nat) big_map
type allowances = (allowance_key, nat) big_map
type storage =
[@layout:comb]
{ tokens : tokens;
allowances : allowances;
admin : address;
total_supply : nat;
}
type parameter =
| Transfer of transfer
| Approve of approve
| MintOrBurn of mintOrBurn
| GetAllowance of getAllowance
| GetBalance of getBalance
| GetTotalSupply of getTotalSupply
type result = operation list * storage
[@inline]
let maybe (n : nat) : nat option =
if n = 0n
then (None : nat option)
else Some n
let transfer (param : transfer) (storage : storage) : result =
let allowances = storage.allowances in
let tokens = storage.tokens in
let allowances =
if Tezos.sender = param.address_from
then allowances
else
let allowance_key = { owner = param.address_from ; spender = Tezos.sender } in
let authorized_value =
match Big_map.find_opt allowance_key allowances with
| Some value -> value
| None -> 0n in
let authorized_value =
match is_nat (authorized_value - param.value) with
| None -> (failwith "NotEnoughAllowance" : nat)
| Some authorized_value -> authorized_value in
Big_map.update allowance_key (maybe authorized_value) allowances in
let tokens =
let from_balance =
match Big_map.find_opt param.address_from tokens with
| Some value -> value
| None -> 0n in
let from_balance =
match is_nat (from_balance - param.value) with
| None -> (failwith "NotEnoughBalance" : nat)
| Some from_balance -> from_balance in
Big_map.update param.address_from (maybe from_balance) tokens in
let tokens =
let to_balance =
match Big_map.find_opt param.address_to tokens with
| Some value -> value
| None -> 0n in
let to_balance = to_balance + param.value in
Big_map.update param.address_to (maybe to_balance) tokens in
(([] : operation list), { storage with tokens = tokens; allowances = allowances })
let approve (param : approve) (storage : storage) : result =
let allowances = storage.allowances in
let allowance_key = { owner = Tezos.sender ; spender = param.spender } in
let previous_value =
match Big_map.find_opt allowance_key allowances with
| Some value -> value
| None -> 0n in
begin
if previous_value > 0n && param.value > 0n
then (failwith "UnsafeAllowanceChange")
else ();
let allowances = Big_map.update allowance_key (maybe param.value) allowances in
(([] : operation list), { storage with allowances = allowances })
end
let mintOrBurn (param : mintOrBurn) (storage : storage) : result =
begin
if Tezos.sender <> storage.admin
then failwith "OnlyAdmin"
else ();
let tokens = storage.tokens in
let old_balance =
match Big_map.find_opt param.target tokens with
| None -> 0n
| Some bal -> bal in
let new_balance =
match is_nat (old_balance + param.quantity) with
| None -> (failwith "Cannot burn more than the target's balance." : nat)
| Some bal -> bal in
let tokens = Big_map.update param.target (maybe new_balance) storage.tokens in
let total_supply = abs (storage.total_supply + param.quantity) in
(([] : operation list), { storage with tokens = tokens ; total_supply = total_supply })
end
let getAllowance (param : getAllowance) (storage : storage) : operation list =
let value =
match Big_map.find_opt param.request storage.allowances with
| Some value -> value
| None -> 0n in
[Tezos.transaction value 0mutez param.callback]
let getBalance (param : getBalance) (storage : storage) : operation list =
let value =
match Big_map.find_opt param.owner storage.tokens with
| Some value -> value
| None -> 0n in
[Tezos.transaction value 0mutez param.callback]
let getTotalSupply (param : getTotalSupply) (storage : storage) : operation list =
let total = storage.total_supply in
[Tezos.transaction total 0mutez param.callback]
let main (param, storage : parameter * storage) : result =
begin
if Tezos.amount <> 0mutez
then failwith "DontSendTez"
else ();
match param with
| Transfer param -> transfer param storage
| Approve param -> approve param storage
| MintOrBurn param -> mintOrBurn param storage
| GetAllowance param -> (getAllowance param storage, storage)
| GetBalance param -> (getBalance param storage, storage)
| GetTotalSupply param -> (getTotalSupply param storage, storage)
end