-
Notifications
You must be signed in to change notification settings - Fork 18
/
Dexter2CPMM.v
618 lines (532 loc) · 28.4 KB
/
Dexter2CPMM.v
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
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
(** * Dexter 2 CPMM contract *)
(** This file contains an implementation of the Dexter2 CPMM contract
https://gitlab.com/dexter2tz/dexter2tz/-/blob/1cec9d9333eba756603d6cd90ea9c70d482a5d3d/dexter.mligo
In addition this file contains proof of functional correctness w.r.t the
informal specification https://gitlab.com/dexter2tz/dexter2tz/-/blob/1cec9d9333eba756603d6cd90ea9c70d482a5d3d/docs/informal-spec/dexter2-cpmm.md
This contract is an implementation of a Constant Product Market Maker (CPMM).
When paired with a FA1.2 or FA2 token contract and a Dexter2 liquidity contract,
this contract serves as a decentralized exchange allowing users to trade between
XTZ and tokens. Additionally, users can also add or withdraw funds from the
exchanges trading reserves. Traders pay a 0.3% fee, the fee goes to the owners
of the trading reserves, this way user are incentivized to add funds to the reserves.
*)
From ConCert.Utils Require Import RecordUpdate.
From ConCert.Execution Require Import Blockchain.
From ConCert.Execution Require Import Monad.
From ConCert.Execution Require Import ResultMonad.
From ConCert.Execution Require Import Serializable.
From ConCert.Execution Require Import ContractCommon.
From ConCert.Examples.FA2 Require Import FA2Token.
From ConCert.Examples.FA2 Require Import FA2LegacyInterface.
From ConCert.Examples.Dexter2 Require Import Dexter2FA12.
From Coq Require Import ZArith_base.
From Coq Require Import List. Import ListNotations.
(** * Contract types *)
Section DexterTypes.
Context {BaseTypes : ChainBase}.
Set Primitive Projections.
Set Nonrecursive Elimination Schemes.
Open Scope N_scope.
(** ** Type synonyms *)
Definition update_token_pool_internal_ := list FA2LegacyInterface.balance_of_response.
Definition token_id := FA2LegacyInterface.token_id.
Definition token_contract_transfer := FA2LegacyInterface.transfer.
Definition balance_of := FA2LegacyInterface.balance_of_response.
Definition mintOrBurn := Dexter2FA12.mintOrBurn_param.
Definition baker_address := option Address.
(** ** Entrypoint types *)
Record add_liquidity_param :=
build_add_liquidity_param {
owner : Address;
minLqtMinted : N;
maxTokensDeposited : N;
add_deadline : nat
}.
Record remove_liquidity_param :=
build_remove_liquidity_param {
liquidity_to : Address;
lqtBurned : N;
minXtzWithdrawn : N;
minTokensWithdrawn : N;
remove_deadline : nat
}.
Record xtz_to_token_param :=
build_xtz_to_token_param {
tokens_to : Address;
minTokensBought : N;
xtt_deadline : nat
}.
Record token_to_xtz_param :=
build_token_to_xtz_param {
xtz_to : Address;
tokensSold : N;
minXtzBought : N;
ttx_deadline : nat
}.
Record token_to_token_param :=
build_token_to_token_param {
outputDexterContract : Address;
to_ : Address;
minTokensBought_ : N;
tokensSold_ : N;
ttt_deadline : nat
}.
Record set_baker_param :=
build_set_baker_param {
baker : baker_address;
freezeBaker_ : bool
}.
Inductive DexterMsg :=
| AddLiquidity : add_liquidity_param -> DexterMsg
| RemoveLiquidity : remove_liquidity_param -> DexterMsg
| XtzToToken : xtz_to_token_param -> DexterMsg
| TokenToXtz : token_to_xtz_param -> DexterMsg
| SetBaker : set_baker_param -> DexterMsg
| SetManager : Address -> DexterMsg
| SetLqtAddress : Address -> DexterMsg
| UpdateTokenPool : DexterMsg
| TokenToToken : token_to_token_param -> DexterMsg.
Definition Msg := @FA2Token.FA2ReceiverMsg _ DexterMsg.
(** ** Storage types *)
Record State :=
build_state {
tokenPool : N;
xtzPool : N;
lqtTotal : N;
selfIsUpdatingTokenPool : bool;
freezeBaker : bool;
manager : Address;
tokenAddress : Address;
tokenId : token_id;
lqtAddress : Address
}.
Record Setup :=
build_setup {
lqtTotal_ : N;
manager_ : Address;
tokenAddress_ : Address;
tokenId_ : token_id
}.
Definition Error : Type := nat.
Definition default_error : Error := 1%nat.
(* begin hide *)
MetaCoq Run (make_setters State).
MetaCoq Run (make_setters Setup).
(* end hide *)
End DexterTypes.
Module Type Dexter2Serializable.
Section DS.
Context `{ChainBase}.
Axiom add_liquidity_param_serializable : Serializable add_liquidity_param.
Existing Instance add_liquidity_param_serializable.
Axiom remove_liquidity_param_serializable : Serializable remove_liquidity_param.
Existing Instance remove_liquidity_param_serializable.
Axiom xtz_to_token_param_serializable : Serializable xtz_to_token_param.
Existing Instance xtz_to_token_param_serializable.
Axiom token_to_xtz_param_serializable : Serializable token_to_xtz_param.
Existing Instance token_to_xtz_param_serializable.
Axiom set_baker_param_serializable : Serializable set_baker_param.
Existing Instance set_baker_param_serializable.
Axiom token_to_token_param_serializable : Serializable token_to_token_param.
Existing Instance token_to_token_param_serializable.
Axiom DexterMsg_serializable : Serializable DexterMsg.
Existing Instance DexterMsg_serializable.
Axiom Dexter2FA12_Msg_serialize : Serializable Dexter2FA12.Msg.
Existing Instance Dexter2FA12_Msg_serialize.
Axiom setup_serializable : Serializable Setup.
Existing Instance setup_serializable.
Axiom ClientMsg_serializable : Serializable (@FA2Token.FA2ReceiverMsg _ DexterMsg).
Existing Instance ClientMsg_serializable.
Axiom state_serializable : Serializable State.
Existing Instance state_serializable.
Axiom FA2Token_Msg_serializable : Serializable FA2Token.Msg.
Existing Instance FA2Token_Msg_serializable.
End DS.
End Dexter2Serializable.
Module Type NullAddress.
Section NullAddress.
Parameter BaseTypes : ChainBase.
Existing Instance BaseTypes.
(** Null address that will newer contain contracts *)
Parameter null_address : Address.
(** Placeholder for Tezos set delegate operation *)
Parameter set_delegate_call : baker_address -> list ActionBody.
Axiom delegate_call : forall addr, Forall (fun action =>
match action with
| act_transfer _ _ => False
| act_call _ _ _ => False
| act_deploy _ _ _ => False
end) (set_delegate_call addr).
End NullAddress.
End NullAddress.
(** * Contract functions *)
Module Dexter2 (SI : Dexter2Serializable) (NAddr : NullAddress).
Import SI.
Export NAddr.
(* begin hide *)
#[export] Existing Instance add_liquidity_param_serializable.
#[export] Existing Instance remove_liquidity_param_serializable.
#[export] Existing Instance xtz_to_token_param_serializable.
#[export] Existing Instance token_to_xtz_param_serializable.
#[export] Existing Instance set_baker_param_serializable.
#[export] Existing Instance token_to_token_param_serializable.
#[export] Existing Instance DexterMsg_serializable.
#[export] Existing Instance Dexter2FA12_Msg_serialize.
#[export] Existing Instance setup_serializable.
#[export] Existing Instance ClientMsg_serializable.
#[export] Existing Instance state_serializable.
#[export] Existing Instance FA2Token_Msg_serializable.
#[export] Existing Instance BaseTypes.
(* end hide *)
Section DexterDefs.
Open Scope N_scope.
(** ** Helper functions *)
(** [Amount] is defined as an alias to [Z]. We use these conversion functions to mark
the places explicitly where the conversion from amounts happens. *)
Definition amount_to_N : Amount -> N := Z.to_N.
Definition N_to_amount : N -> Amount := Z.of_N.
Definition Result : Type := result (State * list ActionBody) Error.
Definition sub (n m : N) : result N Error :=
do _ <- throwIf (n <? m) default_error; Ok (n - m).
Definition div (n m : N) : result N Error :=
do _ <- throwIf (m =? 0) default_error; Ok (n / m).
Definition ceildiv (n m : N) : result N Error :=
if N.modulo n m =? 0
then div n m
else do res <- div n m ; Ok (res + 1).
Definition ceildiv_ (n m : N) : N :=
if N.modulo n m =? 0
then n / m
else (n / m) + 1.
Opaque ceildiv.
Opaque ceildiv_.
Opaque div.
Opaque sub.
Definition non_zero_amount (amt : Z) : bool := (0 <? amt)%Z.
Global Arguments non_zero_amount _ /. (* always unfold, if applied *)
Definition call_liquidity_token (addr : Address)
(amt : N)
(msg : Dexter2FA12.Msg)
: ActionBody :=
act_call addr (N_to_amount amt) (serialize msg).
(** Note that [quantity] is allowed to be negative. In this case it corresponds to burning *)
Definition mint_or_burn (state : State)
(target : Address)
(quantitiy : Z)
: result ActionBody Error :=
do _ <- throwIf (address_eqb state.(lqtAddress) null_address) default_error; (* error lqtAddress not set *)
Ok (call_liquidity_token state.(lqtAddress)
0
(Dexter2FA12.msg_mint_or_burn
(Dexter2FA12.build_mintOrBurn_param quantitiy target))).
Definition call_to_token (token_addr : Address)
(amt : N)
(msg : FA2Token.Msg)
: ActionBody :=
act_call token_addr (N_to_amount amt) (serialize msg).
Definition token_transfer (state : State)
(from to : Address)
(amount : N)
: ActionBody :=
call_to_token state.(tokenAddress)
0
(FA2Token.msg_transfer
[FA2LegacyInterface.build_transfer from
[FA2LegacyInterface.build_transfer_destination to state.(tokenId) amount] None]).
Definition xtz_transfer (to : Address)
(amount : N)
: result ActionBody Error :=
if address_is_contract to
then Err default_error (* error_INVALID_TO_ADDRESS *)
else Ok (act_transfer to (N_to_amount amount)).
(** ** Add liquidity *)
Definition add_liquidity (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(param : add_liquidity_param)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (param.(add_deadline) <=? chain.(current_slot))%nat default_error; (* error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE *)
do lqt_minted <- div ((amount_to_N ctx.(ctx_amount)) * state.(lqtTotal)) state.(xtzPool) ; (* error_DIV_by_0 *)
do tokens_deposited <- ceildiv ((amount_to_N ctx.(ctx_amount)) * state.(tokenPool)) state.(xtzPool) ; (* error_DIV_by_0 *)
do _ <- throwIf (param.(maxTokensDeposited) <? tokens_deposited) default_error; (* error_MAX_TOKENS_DEPOSITED_MUST_BE_GREATER_THAN_OR_EQUAL_TO_TOKENS_DEPOSITED *)
do _ <- throwIf (lqt_minted <? param.(minLqtMinted)) default_error; (* error_LQT_MINTED_MUST_BE_GREATER_THAN_MIN_LQT_MINTED *)
let new_state := state<| lqtTotal := state.(lqtTotal) + lqt_minted |>
<| tokenPool := state.(tokenPool) + tokens_deposited |>
<| xtzPool := state.(xtzPool) + (amount_to_N ctx.(ctx_amount))|> in
let op_token := token_transfer state ctx.(ctx_from) ctx.(ctx_contract_address) tokens_deposited in
do op_lqt <- mint_or_burn state param.(owner) (Z.of_N lqt_minted) ;
Ok (new_state, [op_token; op_lqt]).
(** ** Remove liquidity *)
Definition remove_liquidity (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(param : remove_liquidity_param)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (param.(remove_deadline) <=? chain.(current_slot))%nat default_error; (* error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do xtz_withdrawn <- div (param.(lqtBurned) * state.(xtzPool)) state.(lqtTotal) ; (* error_DIV_by_0 *)
do tokens_withdrawn <- div (param.(lqtBurned) * state.(tokenPool)) state.(lqtTotal) ; (* error_DIV_by_0 *)
do _ <- throwIf (xtz_withdrawn <? param.(minXtzWithdrawn))default_error ; (* error_THE_AMOUNT_OF_XTZ_WITHDRAWN_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_XTZ_WITHDRAWN *)
do _ <- throwIf (tokens_withdrawn <? param.(minTokensWithdrawn)) default_error; (* error_THE_AMOUNT_OF_TOKENS_WITHDRAWN_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_TOKENS_WITHDRAWN *)
do new_lqtPool <- sub state.(lqtTotal) param.(lqtBurned) ; (* error_CANNOT_BURN_MORE_THAN_THE_TOTAL_AMOUNT_OF_LQT *)
do new_tokenPool <- sub state.(tokenPool) tokens_withdrawn ; (* error_TOKEN_POOL_MINUS_TOKENS_WITHDRAWN_IS_NEGATIVE *)
do new_xtzPool <- sub state.(xtzPool) xtz_withdrawn ; (* mutez subtraction run time error *)
do op_lqt <- mint_or_burn state ctx.(ctx_from) (0 - (Z.of_N param.(lqtBurned)))%Z ;
let op_token := token_transfer state ctx.(ctx_contract_address) param.(liquidity_to) tokens_withdrawn in
do opt_xtz <- xtz_transfer param.(liquidity_to) xtz_withdrawn ;
let new_state :=
{| tokenPool := new_tokenPool;
xtzPool := new_xtzPool;
lqtTotal := new_lqtPool;
selfIsUpdatingTokenPool := state.(selfIsUpdatingTokenPool);
freezeBaker := state.(freezeBaker);
manager := state.(manager);
tokenAddress := state.(tokenAddress);
tokenId := state.(tokenId);
lqtAddress := state.(lqtAddress) |} in
Ok (new_state, [op_lqt; op_token; opt_xtz]).
(** ** XTZ to tokens *)
Definition xtz_to_token (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(param : xtz_to_token_param)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (param.(xtt_deadline) <=? chain.(current_slot))%nat default_error; (* error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE *)
do tokens_bought <- div
((amount_to_N ctx.(ctx_amount)) * 997 * state.(tokenPool))
(state.(xtzPool) * 1000 + ((amount_to_N ctx.(ctx_amount)) * 997)) ; (* error_DIV_by_0 *)
do _ <- throwIf (tokens_bought <? param.(minTokensBought)) default_error; (* error_TOKENS_BOUGHT_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_TOKENS_BOUGHT *)
do new_tokenPool <- sub state.(tokenPool) tokens_bought ; (* error_TOKEN_POOL_MINUS_TOKENS_BOUGHT_IS_NEGATIVE *)
let new_state := state<| xtzPool := state.(xtzPool) + (amount_to_N ctx.(ctx_amount)) |>
<| tokenPool := new_tokenPool |> in
let op := token_transfer state ctx.(ctx_contract_address) param.(tokens_to) tokens_bought in
Ok (new_state, [op]).
(** ** Tokes to XTZ *)
Definition token_to_xtz (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(param : token_to_xtz_param)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (param.(ttx_deadline) <=? chain.(current_slot))%nat default_error; (* error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do xtz_bought <- div
(param.(tokensSold) * 997 * state.(xtzPool))
(state.(tokenPool) * 1000 + (param.(tokensSold) * 997)) ; (* error_DIV_by_0 *)
do _ <- throwIf (xtz_bought <? param.(minXtzBought)) default_error; (* error_XTZ_BOUGHT_MUST_BE_GREATER_THAN_OR_EQUAL_TO_MIN_XTZ_BOUGHT *)
do new_xtzPool <- sub state.(xtzPool) xtz_bought ; (* mutez subtraction run time error *)
let op_token := token_transfer state ctx.(ctx_from) ctx.(ctx_contract_address) param.(tokensSold) in
do op_tez <- xtz_transfer param.(xtz_to) xtz_bought ;
let new_state := state<| tokenPool := state.(tokenPool) + param.(tokensSold) |>
<| xtzPool := new_xtzPool |> in
Ok (new_state, [op_token; op_tez]).
(** ** Default entrypoint *)
Definition default_ (chain : Chain)
(ctx : ContractCallContext)
(state : State)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
let new_state := state<| xtzPool := state.(xtzPool) + amount_to_N ctx.(ctx_amount) |> in
Ok (new_state, []).
(** ** Set baker *)
Definition set_baker (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(param : set_baker_param)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do _ <- throwIf (address_neqb ctx.(ctx_from) state.(manager)) default_error; (* error_ONLY_MANAGER_CAN_SET_BAKER *)
do _ <- throwIf (state.(freezeBaker)) default_error; (* error_BAKER_PERMANENTLY_FROZEN *)
Ok (state<| freezeBaker := param.(freezeBaker_) |>, set_delegate_call param.(baker)).
(** ** Set manager *)
Definition set_manager (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(new_manager : Address)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do _ <- throwIf (address_neqb ctx.(ctx_from) state.(manager)) default_error; (* error_ONLY_MANAGER_CAN_SET_MANAGER *)
Ok (state<| manager := new_manager |>, []).
(** ** Set liquidity address *)
Definition set_lqt_address (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(new_lqt_address : Address)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do _ <- throwIf (address_neqb ctx.(ctx_from) state.(manager)) default_error; (* error_ONLY_MANAGER_CAN_SET_LQT_ADRESS *)
do _ <- throwIf (address_neqb state.(lqtAddress) null_address) default_error; (* error_LQT_ADDRESS_ALREADY_SET *)
Ok (state<| lqtAddress := new_lqt_address |>, []).
(** ** Update token pool *)
Definition update_token_pool (chain : Chain)
(ctx : ContractCallContext)
(state : State)
: Result :=
do _ <- throwIf (address_neqb ctx.(ctx_from) ctx.(ctx_origin)) default_error; (* error_CALL_NOT_FROM_AN_IMPLICIT_ACCOUNT *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_UNEXPECTED_REENTRANCE_IN_UPDATE_TOKEN_POOL *)
let balance_of_request :=
FA2LegacyInterface.Build_balance_of_request ctx.(ctx_contract_address) state.(tokenId) in
let balance_of_param :=
FA2LegacyInterface.Build_balance_of_param [balance_of_request] (FA2LegacyInterface.Build_callback _ None ctx.(ctx_contract_address)) in
let op := call_to_token state.(tokenAddress) 0 (FA2Token.msg_balance_of balance_of_param) in
Ok (state<| selfIsUpdatingTokenPool := true |>, [op]).
(** ** Update token pool internal *)
Definition update_token_pool_internal (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(token_pool : update_token_pool_internal_)
: Result :=
do _ <- throwIf ((negb state.(selfIsUpdatingTokenPool)) ||
(address_neqb ctx.(ctx_from) state.(tokenAddress))) default_error; (* error_THIS_ENTRYPOINT_MAY_ONLY_BE_CALLED_BY_GETBALANCE_OF_TOKENADDRESS *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do token_pool <-
match token_pool with
| [] => Err default_error (* error_INVALID_FA2_BALANCE_RESPONSE *)
| x :: xs => Ok x.(balance)
end ;
let new_state := state<| tokenPool := token_pool |>
<| selfIsUpdatingTokenPool := false |> in
Ok (new_state, []).
Definition call_to_other_token (token_addr : Address)
(amount : N)
(msg : @FA2Token.FA2ReceiverMsg _ DexterMsg)
: ActionBody :=
act_call token_addr (N_to_amount amount) (serialize msg).
(** ** Tokens to tokens *)
Definition token_to_token (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(param : token_to_token_param)
: Result :=
do _ <- throwIf state.(selfIsUpdatingTokenPool) default_error; (* error_SELF_IS_UPDATING_TOKEN_POOL_MUST_BE_FALSE *)
do _ <- throwIf (non_zero_amount ctx.(ctx_amount)) default_error; (* error_AMOUNT_MUST_BE_ZERO *)
do _ <- throwIf (param.(ttt_deadline) <=? chain.(current_slot))%nat default_error; (* error_THE_CURRENT_TIME_MUST_BE_LESS_THAN_THE_DEADLINE *)
do xtz_bought <- div
(param.(tokensSold_) * 997 * state.(xtzPool))
(state.(tokenPool) * 1000 + (param.(tokensSold_) * 997)) ; (* error_DIV_by_0 *)
do new_xtzPool <- sub state.(xtzPool) xtz_bought ; (* mutez subtraction run time error *)
let new_state := state<| tokenPool := state.(tokenPool) + param.(tokensSold_) |>
<| xtzPool := new_xtzPool |> in
let op1 := token_transfer state ctx.(ctx_from) ctx.(ctx_contract_address) param.(tokensSold_) in
let op2 := call_to_other_token
param.(outputDexterContract)
xtz_bought
(FA2Token.other_msg (XtzToToken {|
tokens_to := param.(to_);
minTokensBought := param.(minTokensBought_);
xtt_deadline := param.(ttt_deadline)
|})) in
Ok (new_state, [op1; op2]).
(** ** Receive *)
Definition receive_cpmm (chain : Chain)
(ctx : ContractCallContext)
(state : State)
(maybe_msg : option Msg)
: Result :=
match maybe_msg with
| Some (FA2Token.other_msg (AddLiquidity param)) =>
add_liquidity chain ctx state param
| Some (FA2Token.other_msg (RemoveLiquidity param)) =>
remove_liquidity chain ctx state param
| Some (FA2Token.other_msg (SetBaker param)) =>
set_baker chain ctx state param
| Some (FA2Token.other_msg (SetManager param)) =>
set_manager chain ctx state param
| Some (FA2Token.other_msg (SetLqtAddress param)) =>
set_lqt_address chain ctx state param
| None =>
default_ chain ctx state
| Some (FA2Token.other_msg UpdateTokenPool) =>
update_token_pool chain ctx state
| Some (FA2Token.other_msg (XtzToToken param)) =>
xtz_to_token chain ctx state param
| Some (FA2Token.other_msg (TokenToXtz param)) =>
token_to_xtz chain ctx state param
| Some (FA2Token.other_msg (TokenToToken param)) =>
token_to_token chain ctx state param
| Some (FA2Token.receive_balance_of_param responses) =>
update_token_pool_internal chain ctx state responses
| _ => Err default_error
end.
(** ** Init *)
Definition init_cpmm (chain : Chain)
(ctx : ContractCallContext)
(setup : Setup)
: result State Error :=
Ok {|
tokenPool := 0;
xtzPool := 0;
lqtTotal := setup.(lqtTotal_);
selfIsUpdatingTokenPool := false;
freezeBaker := false;
manager := setup.(manager_);
tokenAddress := setup.(tokenAddress_);
tokenId := setup.(tokenId_);
lqtAddress := null_address
|}.
Definition contract : Contract Setup Msg State Error :=
build_contract init_cpmm receive_cpmm.
End DexterDefs.
End Dexter2.
Module DSInstances <: Dexter2Serializable.
(* Serialization instances (omitted).
NOTE: we use [<:] to make the definitions transparent, so the
implementation details can be revealed, if needed *)
(* begin hide *)
Global Instance add_liquidity_param_serializable `{ChainBase} : Serializable add_liquidity_param :=
Derive Serializable add_liquidity_param_rect <build_add_liquidity_param>.
Global Instance remove_liquidity_param_serializable `{ChainBase} : Serializable remove_liquidity_param :=
Derive Serializable remove_liquidity_param_rect <build_remove_liquidity_param>.
Global Instance xtz_to_token_param_serializable `{ChainBase} : Serializable xtz_to_token_param :=
Derive Serializable xtz_to_token_param_rect <build_xtz_to_token_param>.
Global Instance token_to_xtz_param_serializable `{ChainBase} : Serializable token_to_xtz_param :=
Derive Serializable token_to_xtz_param_rect <build_token_to_xtz_param>.
Global Instance set_baker_param_serializable `{ChainBase} : Serializable set_baker_param :=
Derive Serializable set_baker_param_rect <build_set_baker_param>.
Global Instance token_to_token_param_serializable `{ChainBase} : Serializable token_to_token_param :=
Derive Serializable token_to_token_param_rect <build_token_to_token_param>.
Global Instance DexterMsg_serializable `{ChainBase} : Serializable DexterMsg :=
Derive Serializable DexterMsg_rect <AddLiquidity,
RemoveLiquidity,
XtzToToken,
TokenToXtz,
SetBaker,
SetManager,
SetLqtAddress,
UpdateTokenPool,
TokenToToken>.
Global Instance Dexter2FA12_Msg_serialize `{ChainBase} : Serializable Dexter2FA12.Msg :=
D2LqtSInstances.msg_serializable.
Global Instance setup_serializable `{ChainBase} : Serializable Setup :=
Derive Serializable Setup_rect <build_setup>.
Global Instance ClientMsg_serializable `{ChainBase} : Serializable (@FA2Token.FA2ReceiverMsg _ DexterMsg) :=
@FA2Token.FA2ReceiverMsg_serializable _ _ _.
Global Instance state_serializable `{ChainBase} : Serializable State :=
Derive Serializable State_rect <build_state>.
Global Instance FA2Token_Msg_serializable `{ChainBase} : Serializable FA2Token.Msg :=
FA2Token.msg_serializable.
(* end hide *)
End DSInstances.
Module NullAddressAxiom <: NullAddress.
Section NAddr.
Parameter BaseTypes : ChainBase.
Existing Instance BaseTypes.
Parameter null_address : Address.
Parameter set_delegate_call : baker_address -> list ActionBody.
Axiom delegate_call : forall addr, Forall (fun action =>
match action with
| act_transfer _ _ => False
| act_call _ _ _ => False
| act_deploy _ _ _ => False
end) (set_delegate_call addr).
End NAddr.
End NullAddressAxiom.
(** Instantiating the implementaion with required instances for serialisation/deserialisation *)
Module DEX2 := Dexter2 DSInstances NullAddressAxiom.