Source file adaptive_issuance_helpers.ml
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
module Tez = struct
include Protocol.Alpha_context.Tez
let ( + ) a b =
let open Lwt_result_wrap_syntax in
let*?@ s = a +? b in
return s
let ( - ) a b =
let open Lwt_result_wrap_syntax in
let*?@ s = a -? b in
return s
let of_mutez = of_mutez_exn
let ratio num den =
Q.make (Z.of_int64 (to_mutez num)) (Z.of_int64 (to_mutez den))
let mul_q tez portion =
let tez_z = to_mutez tez |> Z.of_int64 in
Q.(mul portion ~$$tez_z |> to_int64) |> of_mutez
end
type balance_breakdown = {
liquid : Tez.t;
bonds : Tez.t;
staked : Q.t;
unstaked_frozen : Tez.t;
unstaked_finalizable : Tez.t;
pool_tez : Tez.t;
pool_pseudo : Q.t;
}
let balance_pp fmt
{
liquid;
bonds;
staked;
unstaked_frozen;
unstaked_finalizable;
pool_tez;
pool_pseudo;
} =
Format.fprintf
fmt
"{@;\
@[<v 2> liquid : %a@;\
bonds : %a@;\
staked : %a@;\
unstaked_frozen : %a@;\
unstaked_finalizable : %a@;\
pool_tez : %a@;\
pool_pseudo : %a@]@;\
}@."
Tez.pp
liquid
Tez.pp
bonds
Q.pp_print
staked
Tez.pp
unstaked_frozen
Tez.pp
unstaked_finalizable
Tez.pp
pool_tez
Q.pp_print
pool_pseudo
let balance_update_pp fmt (a, b) =
Format.fprintf
fmt
"{@;\
@[<v 2> liquid : %a -> %a@;\
bonds : %a -> %a@;\
staked : %a -> %a@;\
unstaked_frozen : %a -> %a@;\
unstaked_finalizable : %a -> %a@;\
pool_tez : %a -> %a@;\
pool_pseudo : %a -> %a@]@;\
}@."
Tez.pp
a.liquid
Tez.pp
b.liquid
Tez.pp
a.bonds
Tez.pp
b.bonds
Q.pp_print
a.staked
Q.pp_print
b.staked
Tez.pp
a.unstaked_frozen
Tez.pp
b.unstaked_frozen
Tez.pp
a.unstaked_finalizable
Tez.pp
b.unstaked_finalizable
Tez.pp
a.pool_tez
Tez.pp
b.pool_tez
Q.pp_print
a.pool_pseudo
Q.pp_print
b.pool_pseudo
let assert_balance_equal ~loc a b =
let open Lwt_result_syntax in
let* () = Assert.equal_tez ~loc a.liquid a.liquid in
let* () = Assert.equal_tez ~loc a.bonds b.bonds in
let* () =
Assert.equal ~loc Q.equal "Assert equal staked" Q.pp_print a.staked b.staked
in
let* () = Assert.equal_tez ~loc a.unstaked_frozen b.unstaked_frozen in
let* () =
Assert.equal_tez ~loc a.unstaked_finalizable b.unstaked_finalizable
in
let* () = Assert.equal_tez ~loc a.pool_tez b.pool_tez in
let* () =
Assert.equal
~loc
Q.equal
"Assert equal pool pseudotokens"
Q.pp_print
a.pool_pseudo
b.pool_pseudo
in
return_unit
let balance_add bbd1 bbd2 =
let open Lwt_result_syntax in
let* liquid = Tez.(bbd1.liquid + bbd2.liquid) in
let* bonds = Tez.(bbd1.bonds + bbd2.bonds) in
let staked = Q.add bbd1.staked bbd2.staked in
let pool_pseudo = Q.add bbd1.pool_pseudo bbd2.pool_pseudo in
let* pool_tez = Tez.(bbd1.pool_tez + bbd2.pool_tez) in
let* unstaked_frozen = Tez.(bbd1.unstaked_frozen + bbd2.unstaked_frozen) in
let* unstaked_finalizable =
Tez.(bbd1.unstaked_finalizable + bbd2.unstaked_finalizable)
in
return
{
liquid;
bonds;
staked;
unstaked_frozen;
unstaked_finalizable;
pool_tez;
pool_pseudo;
}
let balance_sub bbd1 bbd2 =
let open Lwt_result_syntax in
let* liquid = Tez.(bbd1.liquid - bbd2.liquid) in
let* bonds = Tez.(bbd1.bonds - bbd2.bonds) in
let staked = Q.sub bbd1.staked bbd2.staked in
let pool_pseudo = Q.sub bbd1.pool_pseudo bbd2.pool_pseudo in
let* pool_tez = Tez.(bbd1.pool_tez - bbd2.pool_tez) in
let* unstaked_frozen = Tez.(bbd1.unstaked_frozen - bbd2.unstaked_frozen) in
let* unstaked_finalizable =
Tez.(bbd1.unstaked_finalizable - bbd2.unstaked_finalizable)
in
return
{
liquid;
bonds;
staked;
unstaked_frozen;
unstaked_finalizable;
pool_tez;
pool_pseudo;
}
let add_liquid_rewards amount bbd =
let open Lwt_result_syntax in
let* liquid = Tez.(bbd.liquid + amount) in
return {bbd with liquid}
let add_frozen_rewards amount bbd =
let open Lwt_result_syntax in
let* pool_tez = Tez.(bbd.pool_tez + amount) in
return {bbd with pool_tez}
let tez_of_staked ~pool_tez ~pool_pseudo staked =
if Q.(staked = zero) then Tez.zero
else if Q.(pool_pseudo = zero) then (
assert (Tez.(pool_tez = zero)) ;
Tez.zero)
else
let portion = Q.div staked pool_pseudo in
Tez.mul_q pool_tez portion
let staked_of_tez ~pool_tez ~pool_pseudo amount =
if Tez.(amount = zero) then Q.zero
else if Tez.(pool_tez = zero) then
if Q.(pool_pseudo = zero) then Q.one
else assert false
else
let portion = Tez.ratio amount pool_tez in
Q.mul portion pool_pseudo
let apply_transfer amount (bbd_src, bbd_dst) =
let open Lwt_result_syntax in
if Tez.(amount = zero) then return (bbd_src, bbd_dst)
else
let amount = Tez.min bbd_src.liquid amount in
let* liquid_src = Tez.(bbd_src.liquid - amount) in
let* liquid_dst = Tez.(bbd_dst.liquid + amount) in
return
({bbd_src with liquid = liquid_src}, {bbd_dst with liquid = liquid_dst})
let apply_stake amount (bbd_staker, bbd_delegate) =
let open Lwt_result_syntax in
if Tez.(amount = zero) then return (bbd_staker, bbd_delegate)
else
let amount = Tez.min bbd_staker.liquid amount in
let new_stake =
staked_of_tez
~pool_tez:bbd_delegate.pool_tez
~pool_pseudo:bbd_delegate.pool_pseudo
amount
in
let* liquid = Tez.(bbd_staker.liquid - amount) in
let staked = Q.(bbd_staker.staked + new_stake) in
let* pool_tez = Tez.(bbd_delegate.pool_tez + amount) in
let pool_pseudo = Q.(bbd_delegate.pool_pseudo + new_stake) in
return
( {bbd_staker with liquid; staked},
{bbd_delegate with pool_tez; pool_pseudo} )
let apply_self_stake amount bbd =
let open Lwt_result_syntax in
if Tez.(amount = zero) then return bbd
else
let* a, b = apply_stake amount (bbd, bbd) in
let* added = balance_add a b in
balance_sub added bbd
let apply_unstake amount (bbd_staker, bbd_delegate) =
let open Lwt_result_syntax in
if Tez.(amount = zero) then return (bbd_staker, bbd_delegate)
else
let amount = Tez.min bbd_delegate.pool_tez amount in
let to_unstake =
staked_of_tez
~pool_tez:bbd_delegate.pool_tez
~pool_pseudo:bbd_delegate.pool_pseudo
amount
in
let amount, to_unstake =
if Q.(to_unstake >= bbd_staker.staked) then
( tez_of_staked
~pool_tez:bbd_delegate.pool_tez
~pool_pseudo:bbd_delegate.pool_pseudo
bbd_staker.staked,
bbd_staker.staked )
else (amount, to_unstake)
in
let staked = Q.(bbd_staker.staked - to_unstake) in
let* unstaked_frozen = Tez.(bbd_staker.unstaked_frozen + amount) in
let pool_pseudo = Q.(bbd_delegate.pool_pseudo - to_unstake) in
let* pool_tez = Tez.(bbd_delegate.pool_tez - amount) in
return
( {bbd_staker with staked; unstaked_frozen},
{bbd_delegate with pool_pseudo; pool_tez} )
let apply_self_unstake amount bbd =
let open Lwt_result_syntax in
if Tez.(amount = zero) then return bbd
else
let* a, b = apply_unstake amount (bbd, bbd) in
let* added = balance_add a b in
balance_sub added bbd
let apply_unslashable amount bbd =
let open Lwt_result_syntax in
let* unstaked_frozen = Tez.(bbd.unstaked_frozen - amount) in
let* unstaked_finalizable = Tez.(bbd.unstaked_finalizable + amount) in
return {bbd with unstaked_frozen; unstaked_finalizable}
let apply_finalize bbd =
let open Lwt_result_syntax in
let unstaked_finalizable = Tez.zero in
let* liquid = Tez.(bbd.unstaked_finalizable + bbd.liquid) in
return {bbd with liquid; unstaked_finalizable}
let total_balance_of_breakdown
{liquid; bonds; staked; unstaked_frozen; unstaked_finalizable; _} ~pool_tez
~pool_pseudo =
let staked_tez = tez_of_staked staked ~pool_tez ~pool_pseudo in
Tez.(
liquid + bonds >>=? ( + ) staked_tez >>=? ( + ) unstaked_frozen
>>=? ( + ) unstaked_finalizable)
let get_balance_breakdown ctxt contract =
let open Lwt_result_syntax in
let* liquid = Context.Contract.balance ctxt contract in
let* bonds = Context.Contract.frozen_bonds ctxt contract in
let* staked_balance = Context.Contract.staked_balance ctxt contract in
let staked_balance = Option.value ~default:Tez.zero staked_balance in
let* unstaked_frozen =
Context.Contract.unstaked_frozen_balance ctxt contract
in
let unstaked_frozen = Option.value ~default:Tez.zero unstaked_frozen in
let* unstaked_finalizable =
Context.Contract.unstaked_finalizable_balance ctxt contract
in
let unstaked_finalizable =
Option.value ~default:Tez.zero unstaked_finalizable
in
let* total_balance = Context.Contract.full_balance ctxt contract in
let bd =
{
liquid;
bonds;
staked = Q.zero;
pool_tez = Tez.zero;
pool_pseudo = Q.zero;
unstaked_frozen;
unstaked_finalizable;
}
in
return (bd, staked_balance, total_balance)
let assert_balance_breakdown ~loc ctxt contract
({
liquid;
bonds;
staked;
unstaked_frozen;
unstaked_finalizable;
pool_tez = _;
pool_pseudo = _;
} as asserted_balance) ~pool_tez ~pool_pseudo =
let open Lwt_result_syntax in
let* bd, staked_balance, total_balance =
get_balance_breakdown ctxt contract
in
let asserted_staked_balance = tez_of_staked staked ~pool_tez ~pool_pseudo in
let* asserted_total_balance =
total_balance_of_breakdown asserted_balance ~pool_tez ~pool_pseudo
in
let* () = Assert.equal_tez ~loc bd.liquid liquid in
let* () = Assert.equal_tez ~loc bd.bonds bonds in
let* () = Assert.equal_tez ~loc staked_balance asserted_staked_balance in
let* () = Assert.equal_tez ~loc total_balance asserted_total_balance in
let* () = Assert.equal_tez ~loc bd.unstaked_frozen unstaked_frozen in
let* () =
Assert.equal_tez ~loc bd.unstaked_finalizable unstaked_finalizable
in
return_unit
let get_launch_cycle ~loc blk =
let open Lwt_result_syntax in
let* launch_cycle_opt = Context.get_adaptive_issuance_launch_cycle (B blk) in
Assert.get_some ~loc launch_cycle_opt
let stake ctxt contract amount =
Op.transaction
ctxt
~entrypoint:Protocol.Alpha_context.Entrypoint.stake
~fee:Tez.zero
contract
contract
amount
let set_delegate_parameters ctxt delegate ~limit_of_staking_over_baking
~edge_of_baking_over_staking_billionth =
let entrypoint = Protocol.Alpha_context.Entrypoint.set_delegate_parameters in
let parameters =
Protocol.Alpha_context.Script.lazy_expr
(Expr.from_string
(Printf.sprintf
"Pair %d (Pair %d Unit)"
limit_of_staking_over_baking
edge_of_baking_over_staking_billionth))
in
Op.transaction
ctxt
~entrypoint
~parameters
~fee:Tez.zero
delegate
delegate
Tez.zero
let unstake ctxt contract amount =
let parameters =
Protocol.Alpha_context.Script.lazy_expr
(Expr.from_string (Printf.sprintf "%Ld" (Tez.to_mutez amount)))
in
Op.transaction
ctxt
~entrypoint:Protocol.Alpha_context.Entrypoint.unstake
~parameters
~fee:Tez.zero
contract
contract
Tez.zero
let finalize_unstake ctxt ?(amount = Tez.zero) contract =
Op.transaction
ctxt
~entrypoint:Protocol.Alpha_context.Entrypoint.finalize_unstake
~fee:Tez.zero
contract
contract
amount