diff --git a/contracts/main/TTDex.ligo b/contracts/main/TTDex.ligo index 691ff562..f6bf038b 100644 --- a/contracts/main/TTDex.ligo +++ b/contracts/main/TTDex.ligo @@ -1,7 +1,8 @@ #define FA2_STANDARD_ENABLED #define TOKEN_TO_TOKEN_ENABLED -#include "../partials/TTDex.ligo" +#include "../partials/ITTDex.ligo" #include "../partials/TTMethodDex.ligo" +#include "../partials/TTDex.ligo" (* DexFA2 - Contract for exchanges for XTZ - FA2 token pair *) function main (const p : full_action; const s : full_dex_storage) : full_return is @@ -14,6 +15,6 @@ function main (const p : full_action; const s : full_dex_storage) : full_return | Update_operators(params) -> call_token(IUpdate_operators(params), this, 1n, s) | Get_reserves(params) -> get_reserves(params, s) | Close -> ((nil:list(operation)), close(s)) - | SetDexFunction(params) -> ((nil:list(operation)), if params.index > 4n then (failwith("Dex/wrong-index") : full_dex_storage) else set_dex_function(params.index, params.func, s)) + | SetDexFunction(params) -> ((nil:list(operation)), if params.index > 3n then (failwith("Dex/wrong-index") : full_dex_storage) else set_dex_function(params.index, params.func, s)) | SetTokenFunction(params) -> ((nil:list(operation)), if params.index > 2n then (failwith("Dex/wrong-index") : full_dex_storage) else set_token_function(params.index, params.func, s)) end diff --git a/contracts/partials/ITTDex.ligo b/contracts/partials/ITTDex.ligo index 96954cd8..d6e291f0 100644 --- a/contracts/partials/ITTDex.ligo +++ b/contracts/partials/ITTDex.ligo @@ -4,7 +4,7 @@ (* record that represents account shares *) type account_info is record [ - balance : nat; (* liquid tokens *) + balance : nat; (* LP tokens *) allowances : set (address); (* accounts allowed to act on behalf of the user *) ] @@ -23,109 +23,100 @@ type token_type is | Fa2 type pair_info is record [ - token_a_pool : nat; (* tez reserves in the pool *) - token_b_pool : nat; (* token reserves in the pool *) + token_a_pool : nat; (* token A reserves in the pool *) + token_b_pool : nat; (* token B reserves in the pool *) total_supply : nat; (* total shares count *) ] type tokens_info is record [ - token_a_address : address; - token_b_address : address; - token_a_id : nat; - token_b_id : nat; - token_a_type : token_type; - token_b_type : token_type; + token_a_address : address; (* token A address *) + token_b_address : address; (* token B address *) + token_a_id : nat; (* token A identifier *) + token_b_id : nat; (* token B identifier *) + token_a_type : token_type; (* token A standard *) + token_b_type : token_type; (* token B standard *) ] type token_pair is bytes (* record for the dex storage *) type dex_storage is record [ - entered : bool; + entered : bool; (* reentrancy protection *) pairs_count : nat; (* total shares count *) tokens : big_map(nat, tokens_info); (* all the tokens list *) token_to_id : big_map(token_pair, nat); (* all the tokens list *) pairs : big_map(nat, pair_info); (* account info per address *) ledger : big_map((address * nat), account_info); (* account info per address *) ] -type swap_type is Buy | Sell +(* operation type *) +type swap_type is +| Sell (* exchange token A to token B *) +| Buy (* exchange token B to token A *) type swap_slice_type is record [ - pair : tokens_info; - operation : swap_type; + pair : tokens_info; (* exchange pair info *) + operation : swap_type; (* exchange operation *) ] type swap_side is record [ - pool : nat; - token : address; - id: nat; - standard: token_type; + pool : nat; (* pair identifier*) + token : address; (* token address*) + id : nat; (* token aidentifier *) + standard : token_type; (* token standard *) ] type swap_data is record [ - to_: swap_side; - from_: swap_side; + to_ : swap_side; (* info about sold asset *) + from_ : swap_side; (* info about bought asset *) ] type internal_swap_type is record [ - s : dex_storage; - amount_in : nat; - token_address_in : address; - token_id_in : nat; - operation : option(operation); - sender : address; - receiver : address; + s : dex_storage; (* storage state *) + amount_in : nat; (* amount of tokens to be sold *) + token_address_in : address; (* address of sold token *) + token_id_in : nat; (* identifier of sold token *) + operation : option(operation); (* exchange operation type *) + sender : address; (* address of the sender *) + receiver : address; (* address of the receiver *) ] (* Entrypoint arguments *) type token_to_token_route_params is [@layout:comb] record [ - swaps : list(swap_slice_type); + swaps : list(swap_slice_type); (* swap operations list*) amount_in : nat; (* amount of tokens to be exchanged *) - min_amount_out : nat; (* min amount of XTZ received to accept exchange *) - receiver : address; (* tokens receiver *) - ] - -(* Entrypoint arguments *) -type token_to_token_payment_params is - [@layout:comb] - record [ - pair : tokens_info; - operation : swap_type; - amount_in : nat; (* amount of tokens to be exchanged *) - min_amount_out : nat; (* min amount of XTZ received to accept exchange *) + min_amount_out : nat; (* min amount of tokens received to accept exchange *) receiver : address; (* tokens receiver *) ] type invest_liquidity_params is [@layout:comb] record [ - pair : tokens_info; - token_a_in : nat; (* min amount of XTZ received to accept the divestment *) - token_b_in : nat; (* min amount of tokens received to accept the divestment *) + pair : tokens_info; (* exchange pair info *) + token_a_in : nat; (* min amount of tokens A invested *) + token_b_in : nat; (* min amount of tokens B invested *) ] type divest_liquidity_params is [@layout:comb] record [ - pair : tokens_info; - min_token_a_out : nat; (* min amount of XTZ received to accept the divestment *) - min_token_b_out : nat; (* min amount of tokens received to accept the divestment *) + pair : tokens_info; (* exchange pair info *) + min_token_a_out : nat; (* min amount of tokens A received to accept the divestment *) + min_token_b_out : nat; (* min amount of tokens B received to accept the divestment *) shares : nat; (* amount of shares to be burnt *) ] type dex_action is -| InitializeExchange of invest_liquidity_params (* sets initial liquidity *) -| TokenToTokenRoutePayment of token_to_token_route_params (* exchanges XTZ to tokens and sends them to receiver *) -| TokenToTokenPayment of token_to_token_payment_params (* exchanges XTZ to tokens and sends them to receiver *) -| InvestLiquidity of invest_liquidity_params (* mints min shares after investing tokens and XTZ *) -| DivestLiquidity of divest_liquidity_params (* burns shares and sends tokens and XTZ to the owner *) +| AddPair of invest_liquidity_params (* sets initial liquidity *) +| Swap of token_to_token_route_params (* exchanges token to another token and sends them to receiver *) +| Invest of invest_liquidity_params (* mints min shares after investing tokens *) +| Divest of divest_liquidity_params (* burns shares and sends tokens to the owner *) type use_params is dex_action type get_reserves_params is record [ - receiver : contract(nat * nat); - token_id : nat; + receiver : contract(nat * nat); (* response receiver *) + pair_id : nat; (* pair identifier *) ] (* Main function parameter types specific for FA2 standard*) @@ -133,9 +124,9 @@ type transfer_params is list (transfer_param) type update_operator_params is list (update_operator_param) type token_action is -| ITransfer of transfer_params -| IBalance_of of balance_params -| IUpdate_operators of update_operator_params +| ITransfer of transfer_params (* transfer asset from one account to another *) +| IBalance_of of balance_params (* returns the balance of the account *) +| IUpdate_operators of update_operator_params (* updates the token operators *) type return is list (operation) * dex_storage type dex_func is (dex_action * dex_storage * address) -> return @@ -151,19 +142,20 @@ type set_dex_function_params is record [ index : nat; (* the key in functions map *) ] +(* full list of dex entrypoints *) type full_action is | Use of use_params -| Transfer of transfer_params -| Balance_of of balance_params -| Update_operators of update_operator_params -| Get_reserves of get_reserves_params -| Close of unit +| Transfer of transfer_params (* transfer asset from one account to another *) +| Balance_of of balance_params (* returns the balance of the account *) +| Update_operators of update_operator_params (* updates the token operators *) +| Get_reserves of get_reserves_params (* returns the underlying token reserves *) +| Close of unit (* entrypoint to prevent reentrancy *) | SetDexFunction of set_dex_function_params (* sets the dex specific function. Is used before the whole system is launched *) | SetTokenFunction of set_token_function_params (* sets the FA function, is used before the whole system is launched *) (* real dex storage *) type full_dex_storage is record - storage : dex_storage; + storage : dex_storage; (* real dex storage *) metadata : big_map(string, bytes); (* metadata storage according to TZIP-016 *) dex_lambdas : big_map(nat, dex_func); (* map with exchange-related functions code *) token_lambdas : big_map(nat, token_func); (* map with token-related functions code *) @@ -173,5 +165,3 @@ type full_return is list (operation) * full_dex_storage const fee_rate : nat = 333n; (* exchange fee rate distributed among the liquidity providers *) -const token_func_count : nat = 2n; - diff --git a/contracts/partials/TTDex.ligo b/contracts/partials/TTDex.ligo index 1c74ef70..7f0de231 100644 --- a/contracts/partials/TTDex.ligo +++ b/contracts/partials/TTDex.ligo @@ -1,5 +1,3 @@ -#include "./ITTDex.ligo" - (* Route exchange-specific action Due to the fabulous storage, gas and operation size limits @@ -11,20 +9,26 @@ The function is responsible for fiding the appropriate method based on the argument type. *) -[@inline] function call_dex (const p : dex_action; const this : address; const s : full_dex_storage) : full_return is +[@inline] function call_dex( + const p : dex_action; + const this : address; + const s : full_dex_storage) : full_return is block { const idx : nat = case p of - | InitializeExchange(n) -> 0n - | TokenToTokenPayment(n) -> 1n - | TokenToTokenRoutePayment(n) -> 2n - | InvestLiquidity(n) -> 3n - | DivestLiquidity(n) -> 4n + | AddPair(n) -> 0n + | Swap(n) -> 1n + | Invest(n) -> 2n + | Divest(n) -> 3n end; const res : return = case s.dex_lambdas[idx] of Some(f) -> f(p, s.storage, this) | None -> (failwith("Dex/function-not-set") : return) end; s.storage := res.1; + res.0 := Tezos.transaction( + unit, + 0mutez, + get_close_entrypoint(this)) # res.0; } with (res.0, s) (* Route token-specific action @@ -38,7 +42,11 @@ The function is responsible for fiding the appropriate method based on the provided index. *) -[@inline] function call_token (const p : token_action; const this : address; const idx : nat; const s : full_dex_storage) : full_return is +[@inline] function call_token( + const p : token_action; + const this : address; + const idx : nat; + const s : full_dex_storage) : full_return is block { const res : return = case s.token_lambdas[idx] of Some(f) -> f(p, s.storage, this) @@ -59,9 +67,11 @@ block { } with s (* Return the reserves to the contracts. *) -[@inline] function get_reserves (const params : get_reserves_params; const s : full_dex_storage) : full_return is +[@inline] function get_reserves( + const params : get_reserves_params; + const s : full_dex_storage) : full_return is block { - const pair : pair_info = case s.storage.pairs[params.token_id] of + const pair : pair_info = case s.storage.pairs[params.pair_id] of None -> record [ token_a_pool = 0n; token_b_pool = 0n; @@ -78,7 +88,10 @@ block { ], s) (* Set the dex function code to factory storage *) -[@inline] function set_dex_function (const idx : nat; const f : dex_func; const s : full_dex_storage) : full_dex_storage is +[@inline] function set_dex_function( + const idx : nat; + const f : dex_func; + const s : full_dex_storage) : full_dex_storage is block { case s.dex_lambdas[idx] of Some(n) -> failwith("Dex/function-set") @@ -87,7 +100,10 @@ block { } with s (* Set the token function code to factory storage *) -[@inline] function set_token_function (const idx : nat; const f : token_func; const s : full_dex_storage) : full_dex_storage is +[@inline] function set_token_function( + const idx : nat; + const f : token_func; + const s : full_dex_storage) : full_dex_storage is block { case s.token_lambdas[idx] of Some(n) -> failwith("Dex/function-set") diff --git a/contracts/partials/TTMethodDex.ligo b/contracts/partials/TTMethodDex.ligo index a4dec575..2db8e171 100644 --- a/contracts/partials/TTMethodDex.ligo +++ b/contracts/partials/TTMethodDex.ligo @@ -102,7 +102,7 @@ function wrap_fa12_transfer_trx( const value : nat) : transfer_type_fa12 is TransferTypeFA12(owner, (receiver, value)) -(* Helper function to get token contract *) +(* Helper function to get fa2 token contract *) function get_fa2_token_contract( const token_address : address) : contract(transfer_type_fa2) is case (Tezos.get_entrypoint_opt( @@ -112,7 +112,7 @@ function get_fa2_token_contract( | None -> (failwith("Dex/not-token") : contract(transfer_type_fa2)) end; -(* Helper function to get token contract *) +(* Helper function to get fa1.2 token contract *) function get_fa12_token_contract( const token_address : address) : contract(transfer_type_fa12) is case (Tezos.get_entrypoint_opt( @@ -122,7 +122,7 @@ function get_fa12_token_contract( | None -> (failwith("Dex/not-token") : contract(transfer_type_fa12)) end; -(* Helper function to get self reentrancy entrypoint *) +(* Helper function to get the reentrancy entrypoint of the current contract *) function get_close_entrypoint( const contract_address : address) : contract(unit) is case (Tezos.get_entrypoint_opt( @@ -131,6 +131,7 @@ function get_close_entrypoint( | None -> (failwith("Dex/no-close-entrypoint") : contract(unit)) end; +(* Helper function to transfer fa2 tokens *) function transfer_fa2( const sender_ : address; const receiver : address; @@ -147,6 +148,7 @@ function transfer_fa2( get_fa2_token_contract(contract_address) ); +(* Helper function to transfer fa1.2 tokens *) function transfer_fa12( const sender_ : address; const receiver : address; @@ -161,6 +163,7 @@ function transfer_fa12( get_fa12_token_contract(contract_address) ); +(* Helper function to transfer the asset based on its standard *) function typed_transfer( const sender_ : address; const receiver : address; @@ -190,14 +193,9 @@ function initialize_exchange( const s : dex_storage; const this: address) : return is block { - var operations: list(operation) := list[ - Tezos.transaction( - unit, - 0mutez, - get_close_entrypoint(this) - )]; + var operations: list(operation) := list[]; case p of - InitializeExchange(params) -> { + AddPair(params) -> { if s.entered then failwith("Dex/reentrancy") else s.entered := True; @@ -209,7 +207,7 @@ function initialize_exchange( if params.pair.token_a_address > params.pair.token_b_address then failwith("Dex/wrong-pair") else skip; - (* get par info*) + (* read pair info*) const res : (pair_info * nat) = get_pair(params.pair, s); const pair : pair_info = res.0; const token_id : nat = res.1; @@ -225,9 +223,9 @@ function initialize_exchange( then failwith("Dex/non-zero-reserves") else skip; if pair.total_supply =/= 0n (* no shares owned *) then failwith("Dex/non-zero-shares") else skip; - if params.token_a_in < 1n (* XTZ provided *) + if params.token_a_in < 1n (* no token A invested *) then failwith("Dex/no-token-a") else skip; - if params.token_b_in < 1n (* XTZ provided *) + if params.token_b_in < 1n (* no token B invested *) then failwith("Dex/no-token-b") else skip; (* update pool reserves *) @@ -271,105 +269,12 @@ function initialize_exchange( params.pair.token_b_type ) # operations; } - | TokenToTokenPayment(n) -> skip - | TokenToTokenRoutePayment(n) -> skip - | InvestLiquidity(n) -> skip - | DivestLiquidity(n) -> skip + | Swap(n) -> skip + | Invest(n) -> skip + | Divest(n) -> skip end } with (operations, s) -(* Exchange tokens to tokens, -note: tokens should be approved before the operation *) -function token_to_token( - const p : dex_action; - const s : dex_storage; - const this : address) : return is - block { - var operations: list(operation) := list[ - Tezos.transaction( - unit, - 0mutez, - get_close_entrypoint(this) - )]; - case p of - InitializeExchange(n) -> skip - | TokenToTokenRoutePayment(n) -> skip - | TokenToTokenPayment(params) -> { - if s.entered - then failwith("Dex/reentrancy") - else s.entered := True; - - (* check preconditions *) - if params.pair.token_a_address = params.pair.token_b_address - and params.pair.token_a_id >= params.pair.token_b_id - then failwith("Dex/wrong-token-id") else skip; - if params.pair.token_a_address > params.pair.token_b_address - then failwith("Dex/wrong-pair") else skip; - - (* get par info*) - const res : (pair_info * nat) = get_pair(params.pair, s); - const pair : pair_info = res.0; - const token_id : nat = res.1; - - (* ensure there is liquidity *) - if pair.token_a_pool * pair.token_b_pool = 0n - then failwith("Dex/not-launched") else skip; - if params.amount_in = 0n (* non-zero amount of tokens exchanged *) - then failwith ("Dex/zero-amount-in") else skip; - if params.min_amount_out = 0n (* non-zero amount of tokens exchanged *) - then failwith ("Dex/zero-min-amount-out") else skip; - - - (* calculate amount out *) - const swap: swap_data = form_swap_data( - pair, - params.pair, - params.operation); - const from_in_with_fee : nat = params.amount_in * 997n; - const numerator : nat = from_in_with_fee * swap.to_.pool; - const denominator : nat = swap.from_.pool * 1000n + from_in_with_fee; - - (* calculate swapped token amount *) - const out : nat = numerator / denominator; - - (* ensure requirements *) - if out < params.min_amount_out (* minimal XTZ amount out is sutisfied *) - then failwith("Dex/wrong-min-out") else skip; - if out > swap.to_.pool / 3n (* the price impact isn't too high *) - then failwith("Dex/high-out") else skip; - - (* update XTZ pool *) - swap.to_.pool := abs(swap.to_.pool - out); - swap.from_.pool := swap.from_.pool + params.amount_in; - - const updated_pair : pair_info = form_pools( - swap.from_.pool, - swap.to_.pool, - pair.total_supply, - params.operation); - s.pairs[token_id] := updated_pair; - - (* prepare operations to withdraw user's tokens and transfer XTZ *) - operations := - (* from *) - typed_transfer(Tezos.sender, this, params.amount_in, - swap.from_.id, - swap.from_.token, - swap.from_.standard - ) # operations; - operations := - (* to *) - typed_transfer(this, params.receiver, out, - swap.to_.id, - swap.to_.token, - swap.to_.standard - ) # operations; - } - | InvestLiquidity(n) -> skip - | DivestLiquidity(n) -> skip - end - } with (operations, s) - (* Intrenal functions for swap hops *) function internal_token_to_token_swap( const tmp : internal_swap_type; @@ -382,7 +287,7 @@ function internal_token_to_token_swap( if params.pair.token_a_address > params.pair.token_b_address then failwith("Dex/wrong-pair") else skip; - (* get par info*) + (* get pair info*) const res : (pair_info * nat) = get_pair(params.pair, tmp.s); const pair : pair_info = res.0; const token_id : nat = res.1; @@ -393,6 +298,7 @@ function internal_token_to_token_swap( then failwith("Dex/not-launched") else skip; if tmp.amount_in = 0n (* non-zero amount of tokens exchanged *) then failwith ("Dex/zero-amount-in") else skip; + (* ensure the route is corresponding *) if swap.from_.token =/= tmp.token_address_in or swap.from_.id =/= tmp.token_id_in then failwith("Dex/wrong-route") else skip; @@ -405,8 +311,8 @@ function internal_token_to_token_swap( (* calculate swapped token amount *) const out : nat = numerator / denominator; - (* ensure requirements *) - if out > swap.to_.pool / 3n (* the price impact isn't too high *) + (* ensure the price impact isn't too high *) + if out > swap.to_.pool / 3n then failwith("Dex/high-out") else skip; (* update pools amounts *) @@ -442,28 +348,23 @@ function token_to_token_route( const s : dex_storage; const this : address) : return is block { - var operations: list(operation) := list[Tezos.transaction( - unit, - 0mutez, - get_close_entrypoint(this) - )]; + var operations: list(operation) := list[]; case p of - | InitializeExchange(n) -> skip - | TokenToTokenPayment(n) -> skip - | TokenToTokenRoutePayment(params) -> { + | AddPair(n) -> skip + | Swap(params) -> { if s.entered then failwith("Dex/reentrancy") else s.entered := True; (* validate input params *) - if List.size(params.swaps) < 2n (* non-zero amount of tokens exchanged *) + if List.size(params.swaps) < 1n (* the route is empty *) then failwith ("Dex/too-few-swaps") else skip; if params.amount_in = 0n (* non-zero amount of tokens exchanged *) then failwith ("Dex/zero-amount-in") else skip; - if params.min_amount_out = 0n (* non-zero amount of tokens exchanged *) + if params.min_amount_out = 0n (* non-zero amount of tokens to receive *) then failwith ("Dex/zero-min-amount-out") else skip; - (* collect the operations to execute *) + (* get the first exchange info *) const first_swap : swap_slice_type = case List.head_opt(params.swaps) of Some(swap) -> swap | None -> (failwith("Dex/zero-swaps") : swap_slice_type) @@ -523,15 +424,15 @@ function token_to_token_route( (* update storage*) s := tmp.s; - (* add token transfer to user's account *) + (* add token transfer to user's account to operations *) const last_operation : operation = case tmp.operation of Some(o) -> o | None -> (failwith("Dex/too-few-swaps") : operation) end; operations := last_operation # operations; } - | InvestLiquidity(n) -> skip - | DivestLiquidity(n) -> skip + | Invest(n) -> skip + | Divest(n) -> skip end } with (operations, s) @@ -542,16 +443,11 @@ function invest_liquidity( const s : dex_storage; const this: address) : return is block { - var operations: list(operation) := list[Tezos.transaction( - unit, - 0mutez, - get_close_entrypoint(this) - )]; + var operations: list(operation) := list[]; case p of - | InitializeExchange(n) -> skip - | TokenToTokenRoutePayment(n) -> skip - | TokenToTokenPayment(n) -> skip - | InvestLiquidity(params) -> { + | AddPair(n) -> skip + | Swap(n) -> skip + | Invest(params) -> { if s.entered then failwith("Dex/reentrancy") else s.entered := True; @@ -563,7 +459,7 @@ function invest_liquidity( if params.pair.token_a_address > params.pair.token_b_address then failwith("Dex/wrong-pair") else skip; - (* get par info*) + (* read pair info*) const res : (pair_info * nat) = get_pair(params.pair, s); const pair : pair_info = res.0; const token_id : nat = res.1; @@ -582,8 +478,8 @@ function invest_liquidity( then shares_a_purchased else shares_b_purchased; - (* ensure *) - if shares_purchased = 0n (* purchsed shares satisfy required minimum *) + (* ensure purchsed shares satisfy required minimum *) + if shares_purchased = 0n then failwith("Dex/wrong-params") else skip; (* calculate tokens to be withdrawn *) @@ -643,7 +539,7 @@ function invest_liquidity( params.pair.token_b_type ) # operations; } - | DivestLiquidity(n) -> skip + | Divest(n) -> skip end } with (operations, s) @@ -653,17 +549,12 @@ function divest_liquidity( const s : dex_storage; const this: address) : return is block { - var operations: list(operation) := list[Tezos.transaction( - unit, - 0mutez, - get_close_entrypoint(this) - )]; + var operations: list(operation) := list[]; case p of - | InitializeExchange(token_amount) -> skip - | TokenToTokenPayment(n) -> skip - | TokenToTokenRoutePayment(n) -> skip - | InvestLiquidity(n) -> skip - | DivestLiquidity(params) -> { + | AddPair(token_amount) -> skip + | Swap(n) -> skip + | Invest(n) -> skip + | Divest(params) -> { if s.entered then failwith("Dex/reentrancy") else s.entered := True; @@ -675,7 +566,7 @@ function divest_liquidity( if params.pair.token_a_address > params.pair.token_b_address then failwith("Dex/wrong-pair") else skip; - (* get par info*) + (* read pair info*) const res : (pair_info * nat) = get_pair(params.pair, s); const pair : pair_info = res.0; const token_id : nat = res.1; @@ -724,7 +615,7 @@ function divest_liquidity( (* update storage *) s.pairs[token_id] := pair; - (* prepare operations with XTZ and tokens to user *) + (* prepare operations with tokens to user *) operations := typed_transfer( this, diff --git a/migrations/2_deploy_token_to_token_dex.js b/migrations/2_deploy_token_to_token_dex.js index d435509e..9608a4dc 100644 --- a/migrations/2_deploy_token_to_token_dex.js +++ b/migrations/2_deploy_token_to_token_dex.js @@ -107,7 +107,7 @@ module.exports = async (deployer, network, accounts) => { operation = await dex.methods .use( - "initializeExchange", + "addPair", ordered ? token0Instance.address.toString() : token1Instance.address.toString(), @@ -154,7 +154,7 @@ module.exports = async (deployer, network, accounts) => { if (standard === "MIXED") { operation = await dex.methods .use( - "initializeExchange", + "addPair", ordered ? token0Instance.address.toString() : token1Instance.address.toString(), @@ -171,7 +171,7 @@ module.exports = async (deployer, network, accounts) => { } else { operation = await dex.methods .use( - "initializeExchange", + "addPair", ordered ? token0Instance.address.toString() : token1Instance.address.toString(), diff --git a/storage/TTFunctions.js b/storage/TTFunctions.js index 190c4807..104d256d 100644 --- a/storage/TTFunctions.js +++ b/storage/TTFunctions.js @@ -5,18 +5,14 @@ module.exports.dexFunctions = [ }, { index: 1, - name: "token_to_token", - }, - { - index: 2, name: "token_to_token_route", }, { - index: 3, + index: 2, name: "invest_liquidity", }, { - index: 4, + index: 3, name: "divest_liquidity", }, ]; diff --git a/test/InitializeTTExchangeTest.spec.ts b/test/InitializeTTExchangeTest.spec.ts index d60d4a59..a6283c48 100644 --- a/test/InitializeTTExchangeTest.spec.ts +++ b/test/InitializeTTExchangeTest.spec.ts @@ -15,7 +15,7 @@ contract("InitializeTTExchange()", function () { before(async () => { context = await TTContext.init([], false, "alice", false); await context.setDexFunction(0, "initialize_exchange"); - await context.setDexFunction(4, "divest_liquidity"); + await context.setDexFunction(3, "divest_liquidity"); }); it("should have an empty token list after deployment", async function () { diff --git a/test/helpers/ttdexFA2.ts b/test/helpers/ttdexFA2.ts index bd6c4f08..45d195cf 100644 --- a/test/helpers/ttdexFA2.ts +++ b/test/helpers/ttdexFA2.ts @@ -119,7 +119,7 @@ export class TTDex extends TokenFA2 { const operation = await this.contract.methods .use( - "initializeExchange", + "addPair", tokenAAddress, tokenAid, standard.toLowerCase() == "mixed" ? "fa2" : standard.toLowerCase(), @@ -177,7 +177,7 @@ export class TTDex extends TokenFA2 { } } const operation = await this.contract.methods - .use("tokenToTokenRoutePayment", swaps, amountIn, minAmountOut, receiver) + .use("swap", swaps, amountIn, minAmountOut, receiver) .send(); await confirmOperation(tezos, operation.hash); return operation; @@ -224,23 +224,29 @@ export class TTDex extends TokenFA2 { ); } } + const swaps = [ + { + pair: { + token_a_address: tokenAAddress, + token_b_address: tokenBAddress, + token_a_id: tokenAid, + token_b_id: tokenBid, + token_a_type: { + [standard.toLowerCase() == "mixed" + ? "fa2" + : standard.toLowerCase()]: null, + }, + token_b_type: { + [standard.toLowerCase() == "mixed" + ? "fa12" + : standard.toLowerCase()]: null, + }, + }, + operation: { [opType]: null }, + }, + ]; const operation = await this.contract.methods - .use( - "tokenToTokenPayment", - tokenAAddress, - tokenAid, - standard.toLowerCase() == "mixed" ? "fa2" : standard.toLowerCase(), - null, - tokenBAddress, - tokenBid, - standard.toLowerCase() == "mixed" ? "fa12" : standard.toLowerCase(), - null, - opType, - null, - amountIn, - minAmountOut, - receiver - ) + .use("swap", swaps, amountIn, minAmountOut, receiver) .send(); await confirmOperation(tezos, operation.hash); return operation; @@ -285,7 +291,7 @@ export class TTDex extends TokenFA2 { } const operation = await this.contract.methods .use( - "investLiquidity", + "invest", pair.token_a_address, pair.token_a_id, standard.toLowerCase() == "mixed" ? "fa2" : standard.toLowerCase(), @@ -313,7 +319,7 @@ export class TTDex extends TokenFA2 { let pair = this.storage.tokens[pairId]; const operation = await this.contract.methods .use( - "divestLiquidity", + "divest", pair.token_a_address, pair.token_a_id, standard.toLowerCase() == "mixed" ? "fa2" : standard.toLowerCase(), diff --git a/test/helpers/ttdexFA2FA12.ts b/test/helpers/ttdexFA2FA12.ts deleted file mode 100644 index ba7d8fc7..00000000 --- a/test/helpers/ttdexFA2FA12.ts +++ /dev/null @@ -1,280 +0,0 @@ -import { ContractAbstraction, ContractProvider } from "@taquito/taquito"; -import { BatchOperation } from "@taquito/taquito/dist/types/operations/batch-operation"; -import { TransactionOperation } from "@taquito/taquito/dist/types/operations/transaction-operation"; -import { BigNumber } from "bignumber.js"; -import { TokenFA2 } from "./tokenFA2"; -import { TTDexStorage } from "./types"; -import { getLigo } from "./utils"; -import { execSync } from "child_process"; -import { confirmOperation } from "./confirmation"; - -const standard = process.env.EXCHANGE_TOKEN_STANDARD; - -export class TTDex extends TokenFA2 { - public contract: ContractAbstraction; - public storage: TTDexStorage; - - constructor(contract: ContractAbstraction) { - super(contract); - } - - static async init(dexAddress: string): Promise { - return new TTDex(await tezos.contract.at(dexAddress)); - } - - async updateStorage( - maps: { - tokens?: string[]; - token_to_id?: string[]; - pairs?: string[]; - ledger?: any[]; - dex_lambdas?: number[]; - token_lambdas?: number[]; - } = {} - ): Promise { - const storage: any = await this.contract.storage(); - this.storage = { - pairs_count: storage.storage.pairs_count, - tokens: {}, - token_to_id: {}, - pairs: {}, - ledger: {}, - dex_lambdas: {}, - token_lambdas: {}, - }; - for (let key in maps) { - if (["dex_lambdas", "token_lambdas"].includes(key)) continue; - this.storage[key] = await maps[key].reduce(async (prev, current) => { - try { - return { - ...(await prev), - [key == "ledger" ? current[0] : current]: await storage.storage[ - key - ].get(current), - }; - } catch (ex) { - console.log(ex); - return { - ...(await prev), - }; - } - }, Promise.resolve({})); - } - for (let key in maps) { - if (!["dex_lambdas", "token_lambdas"].includes(key)) continue; - this[key] = await maps[key].reduce(async (prev, current) => { - try { - return { - ...(await prev), - [current]: await storage[key].get(current.toString()), - }; - } catch (ex) { - return { - ...(await prev), - }; - } - }, Promise.resolve({})); - } - } - - async initializeExchange( - tokenAAddress: string, - tokenBAddress: string, - tokenAAmount: number, - tokenBAmount: number, - tokenAid: BigNumber = new BigNumber(0), - approve: boolean = true - ): Promise { - if (approve) { - await this.approveFA2Token( - tokenAAddress, - tokenAid, - tokenAAmount, - this.contract.address - ); - await this.approveFA12Token( - tokenBAddress, - tokenBAmount, - this.contract.address - ); - } - const operation = await this.contract.methods - .use( - "initializeExchange", - tokenAAddress, - tokenAid, - tokenBAddress, - tokenAAmount, - tokenBAmount - ) - .send(); - await confirmOperation(tezos, operation.hash); - return operation; - } - - async tokenToTokenPayment( - tokenAAddress: string, - tokenBAddress: string, - opType: string, - amountIn: number, - minAmountOut: number, - receiver: string, - tokenAid: BigNumber = new BigNumber(0) - ): Promise { - if (opType == "buy") { - await this.approveFA12Token( - tokenBAddress, - amountIn, - this.contract.address - ); - } else { - await this.approveFA2Token( - tokenAAddress, - tokenAid, - amountIn, - this.contract.address - ); - } - const operation = await this.contract.methods - .use( - "tokenToTokenPayment", - tokenAAddress, - tokenAid, - tokenBAddress, - opType, - null, - amountIn, - minAmountOut, - receiver - ) - .send(); - await confirmOperation(tezos, operation.hash); - return operation; - } - - async investLiquidity( - pairId: string, - tokenAAmount: number, - tokenBAmount: number, - minShares: number - ): Promise { - await this.updateStorage({ tokens: [pairId] }); - let pair = this.storage.tokens[pairId]; - await this.approveFA2Token( - pair.token_a_address, - pair.token_a_id, - tokenAAmount, - this.contract.address - ); - await this.approveFA12Token( - pair.token_b_address, - tokenBAmount, - this.contract.address - ); - const operation = await this.contract.methods - .use( - "investLiquidity", - pair.token_a_address, - pair.token_a_id, - pair.token_b_address, - tokenAAmount, - tokenBAmount, - minShares - ) - .send(); - await confirmOperation(tezos, operation.hash); - return operation; - } - - async divestLiquidity( - pairId: string, - tokenAAmount: number, - tokenBAmount: number, - sharesBurned: number - ): Promise { - await this.updateStorage({ tokens: [pairId] }); - let pair = this.storage.tokens[pairId]; - const operation = await this.contract.methods - .use( - "divestLiquidity", - pair.token_a_address, - pair.token_a_id, - pair.token_b_address, - tokenAAmount, - tokenBAmount, - sharesBurned - ) - .send(); - await confirmOperation(tezos, operation.hash); - return operation; - } - - async approveFA2Token( - tokenAddress: string, - tokenId: BigNumber, - tokenAmount: number, - address: string - ): Promise { - await this.updateStorage(); - let token = await tezos.contract.at(tokenAddress); - let operation = await token.methods - .update_operators([ - { - [tokenAmount ? "add_operator" : "remove_operator"]: { - owner: await tezos.signer.publicKeyHash(), - operator: address, - token_id: tokenId, - }, - }, - ]) - .send(); - await confirmOperation(tezos, operation.hash); - return operation; - } - - async approveFA12Token( - tokenAddress: string, - tokenAmount: number, - address: string - ): Promise { - await this.updateStorage(); - let token = await tezos.contract.at(tokenAddress); - let operation = await token.methods.approve(address, tokenAmount).send(); - await confirmOperation(tezos, operation.hash); - return operation; - } - - async setDexFunction(index: number, lambdaName: string): Promise { - let ligo = getLigo(true); - const stdout = execSync( - `${ligo} compile-parameter --michelson-format=json $PWD/contracts/main/TTDex${standard}.ligo main 'SetDexFunction(record index =${index}n; func = ${lambdaName}; end)'`, - { maxBuffer: 1024 * 500 } - ); - const operation = await tezos.contract.transfer({ - to: this.contract.address, - amount: 0, - parameter: { - entrypoint: "setDexFunction", - value: JSON.parse(stdout.toString()).args[0].args[0].args[0], - }, - }); - await confirmOperation(tezos, operation.hash); - } - - async setTokenFunction(index: number, lambdaName: string): Promise { - let ligo = getLigo(true); - const stdout = execSync( - `${ligo} compile-parameter --michelson-format=json $PWD/contracts/main/TTDex${standard}.ligo main 'SetTokenFunction(record index =${index}n; func = ${lambdaName}; end)'`, - { maxBuffer: 1024 * 500 } - ); - const operation = await tezos.contract.transfer({ - to: this.contract.address, - amount: 0, - parameter: { - entrypoint: "setTokenFunction", - value: JSON.parse(stdout.toString()).args[0].args[0].args[0], - }, - }); - await confirmOperation(tezos, operation.hash); - } -} diff --git a/test/storage/TTFunctions.ts b/test/storage/TTFunctions.ts index 7aab2093..8cceb0f3 100644 --- a/test/storage/TTFunctions.ts +++ b/test/storage/TTFunctions.ts @@ -5,18 +5,14 @@ export let dexFunctions = [ }, { index: 1, - name: "token_to_token", - }, - { - index: 2, name: "token_to_token_route", }, { - index: 3, + index: 2, name: "invest_liquidity", }, { - index: 4, + index: 3, name: "divest_liquidity", }, ];