Skip to content

Commit

Permalink
swap
Browse files Browse the repository at this point in the history
  • Loading branch information
dorin-iancu committed Jan 25, 2024
1 parent 8f8075a commit a9016e5
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 271 deletions.
5 changes: 2 additions & 3 deletions dex/fuzz/src/fuzz_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ pub mod fuzz_pair_test {
use rand::prelude::*;

use crate::fuzz_data::fuzz_data_tests::*;
use pair::{
pair_actions::{add_liq::AddLiquidityModule, remove_liq::RemoveLiquidityModule},
*,
use pair::pair_actions::{
add_liq::AddLiquidityModule, remove_liq::RemoveLiquidityModule, swap::SwapModule,
};

pub fn add_liquidity<PairObjBuilder, FarmObjBuilder, FactoryObjBuilder, PriceDiscObjBuilder>(
Expand Down
259 changes: 1 addition & 258 deletions dex/pair/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ pub mod safe_price_view;
use crate::errors::*;

use contexts::base::*;
use contexts::swap::SwapContext;
use pair_actions::common_result_types::{
AddLiquidityResultType, RemoveLiquidityResultType, SwapTokensFixedInputResultType,
SwapTokensFixedOutputResultType,
Expand All @@ -43,6 +42,7 @@ pub trait Pair<ContractReader>:
+ pair_actions::initial_liq::InitialLiquidityModule
+ pair_actions::add_liq::AddLiquidityModule
+ pair_actions::remove_liq::RemoveLiquidityModule
+ pair_actions::swap::SwapModule
+ pair_actions::common_methods::CommonMethodsModule
{
#[init]
Expand Down Expand Up @@ -100,191 +100,6 @@ pub trait Pair<ContractReader>:
#[endpoint]
fn upgrade(&self) {}

#[payable("*")]
#[endpoint(swapNoFeeAndForward)]
fn swap_no_fee(&self, token_out: TokenIdentifier, destination_address: ManagedAddress) {
let caller = self.blockchain().get_caller();
require!(self.whitelist().contains(&caller), ERROR_NOT_WHITELISTED);

let mut storage_cache = StorageCache::new(self);
let (token_in, _, amount_in) = self.call_value().single_esdt().into_tuple();
let swap_tokens_order = storage_cache.get_swap_tokens_order(&token_in, &token_out);

require!(
self.can_swap(storage_cache.contract_state),
ERROR_SWAP_NOT_ENABLED
);

self.update_safe_price(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);

let initial_k = self.calculate_k_constant(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);

let mut swap_context = SwapContext::new(
token_in,
amount_in.clone(),
token_out,
BigUint::from(1u32),
swap_tokens_order,
);
swap_context.final_input_amount = amount_in;

let amount_out = self.swap_safe_no_fee(
&mut storage_cache,
swap_context.swap_tokens_order,
&swap_context.final_input_amount,
);
require!(amount_out > 0u64, ERROR_ZERO_AMOUNT);

swap_context.final_output_amount = amount_out;

let new_k = self.calculate_k_constant(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);
require!(initial_k <= new_k, ERROR_K_INVARIANT_FAILED);

self.burn(
&swap_context.output_token_id,
&swap_context.final_output_amount,
);

self.emit_swap_no_fee_and_forward_event(swap_context, destination_address);
}

#[payable("*")]
#[endpoint(swapTokensFixedInput)]
fn swap_tokens_fixed_input(
&self,
token_out: TokenIdentifier,
amount_out_min: BigUint,
) -> SwapTokensFixedInputResultType<Self::Api> {
require!(amount_out_min > 0, ERROR_INVALID_ARGS);

let mut storage_cache = StorageCache::new(self);
let (token_in, _, amount_in) = self.call_value().single_esdt().into_tuple();
let swap_tokens_order = storage_cache.get_swap_tokens_order(&token_in, &token_out);

require!(
self.can_swap(storage_cache.contract_state),
ERROR_SWAP_NOT_ENABLED
);

let reserve_out = storage_cache.get_mut_reserve_out(swap_tokens_order);
require!(*reserve_out > amount_out_min, ERROR_NOT_ENOUGH_RESERVE);

self.update_safe_price(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);

let initial_k = self.calculate_k_constant(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);

let mut swap_context = SwapContext::new(
token_in,
amount_in,
token_out,
amount_out_min,
swap_tokens_order,
);
self.perform_swap_fixed_input(&mut swap_context, &mut storage_cache);

let new_k = self.calculate_k_constant(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);
require!(initial_k <= new_k, ERROR_K_INVARIANT_FAILED);

if swap_context.fee_amount > 0 {
self.send_fee(
&mut storage_cache,
swap_context.swap_tokens_order,
&swap_context.input_token_id,
&swap_context.fee_amount,
);
}

let caller = self.blockchain().get_caller();
let output_payments = self.build_swap_output_payments(&swap_context);
self.send_multiple_tokens_if_not_zero(&caller, &output_payments);

self.emit_swap_event(&storage_cache, swap_context);

self.build_swap_fixed_input_results(output_payments)
}

#[payable("*")]
#[endpoint(swapTokensFixedOutput)]
fn swap_tokens_fixed_output(
&self,
token_out: TokenIdentifier,
amount_out: BigUint,
) -> SwapTokensFixedOutputResultType<Self::Api> {
require!(amount_out > 0, ERROR_INVALID_ARGS);

let mut storage_cache = StorageCache::new(self);
let (token_in, _, amount_in_max) = self.call_value().single_esdt().into_tuple();
let swap_tokens_order = storage_cache.get_swap_tokens_order(&token_in, &token_out);

require!(
self.can_swap(storage_cache.contract_state),
ERROR_SWAP_NOT_ENABLED
);

let reserve_out = storage_cache.get_mut_reserve_out(swap_tokens_order);
require!(*reserve_out > amount_out, ERROR_NOT_ENOUGH_RESERVE);

self.update_safe_price(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);

let initial_k = self.calculate_k_constant(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);

let mut swap_context = SwapContext::new(
token_in,
amount_in_max,
token_out,
amount_out,
swap_tokens_order,
);
self.perform_swap_fixed_output(&mut swap_context, &mut storage_cache);

let new_k = self.calculate_k_constant(
&storage_cache.first_token_reserve,
&storage_cache.second_token_reserve,
);
require!(initial_k <= new_k, ERROR_K_INVARIANT_FAILED);

if swap_context.fee_amount > 0 {
self.send_fee(
&mut storage_cache,
swap_context.swap_tokens_order,
&swap_context.input_token_id,
&swap_context.fee_amount,
);
}

let caller = self.blockchain().get_caller();
let output_payments = self.build_swap_output_payments(&swap_context);
self.send_multiple_tokens_if_not_zero(&caller, &output_payments);

self.emit_swap_event(&storage_cache, swap_context);

self.build_swap_fixed_output_results(output_payments)
}

#[endpoint(setLpTokenIdentifier)]
fn set_lp_token_identifier(&self, token_identifier: TokenIdentifier) {
self.require_caller_has_owner_permissions();
Expand Down Expand Up @@ -398,76 +213,4 @@ pub trait Pair<ContractReader>:
sc_panic!(ERROR_UNKNOWN_TOKEN);
}
}

#[inline]
fn can_swap(&self, state: State) -> bool {
state == State::Active
}

fn perform_swap_fixed_input(
&self,
context: &mut SwapContext<Self::Api>,
storage_cache: &mut StorageCache<Self>,
) {
context.final_input_amount = context.input_token_amount.clone();

let reserve_in = storage_cache.get_reserve_in(context.swap_tokens_order);
let reserve_out = storage_cache.get_reserve_out(context.swap_tokens_order);

let amount_out_optimal =
self.get_amount_out(&context.input_token_amount, reserve_in, reserve_out);
require!(
amount_out_optimal >= context.output_token_amount,
ERROR_SLIPPAGE_EXCEEDED
);
require!(*reserve_out > amount_out_optimal, ERROR_NOT_ENOUGH_RESERVE);
require!(amount_out_optimal != 0u64, ERROR_ZERO_AMOUNT);

context.final_output_amount = amount_out_optimal;

let mut amount_in_after_fee = context.input_token_amount.clone();
if self.is_fee_enabled() {
let fee_amount = self.get_special_fee_from_input(&amount_in_after_fee);
amount_in_after_fee -= &fee_amount;

context.fee_amount = fee_amount;
}

*storage_cache.get_mut_reserve_in(context.swap_tokens_order) += amount_in_after_fee;
*storage_cache.get_mut_reserve_out(context.swap_tokens_order) -=
&context.final_output_amount;
}

fn perform_swap_fixed_output(
&self,
context: &mut SwapContext<Self::Api>,
storage_cache: &mut StorageCache<Self>,
) {
context.final_output_amount = context.output_token_amount.clone();

let reserve_in = storage_cache.get_reserve_in(context.swap_tokens_order);
let reserve_out = storage_cache.get_reserve_out(context.swap_tokens_order);

let amount_in_optimal =
self.get_amount_in(&context.output_token_amount, reserve_in, reserve_out);
require!(
amount_in_optimal <= context.input_token_amount,
ERROR_SLIPPAGE_EXCEEDED
);
require!(amount_in_optimal != 0, ERROR_ZERO_AMOUNT);

context.final_input_amount = amount_in_optimal.clone();

let mut amount_in_optimal_after_fee = amount_in_optimal;
if self.is_fee_enabled() {
let fee_amount = self.get_special_fee_from_input(&amount_in_optimal_after_fee);
amount_in_optimal_after_fee -= &fee_amount;

context.fee_amount = fee_amount;
}

*storage_cache.get_mut_reserve_in(context.swap_tokens_order) += amount_in_optimal_after_fee;
*storage_cache.get_mut_reserve_out(context.swap_tokens_order) -=
&context.final_output_amount;
}
}
5 changes: 5 additions & 0 deletions dex/pair/src/pair_actions/common_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ pub trait CommonMethodsModule {
fn is_state_active(&self, state: State) -> bool {
state == State::Active || state == State::PartialActive
}

#[inline]
fn can_swap(&self, state: State) -> bool {
state == State::Active
}
}
1 change: 1 addition & 0 deletions dex/pair/src/pair_actions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod common_methods;
pub mod common_result_types;
pub mod initial_liq;
pub mod remove_liq;
pub mod swap;
Loading

0 comments on commit a9016e5

Please sign in to comment.