public fun swap<X, Y, Curve>(
x_in: Coin<X>,
x_out: u64,
y_in: Coin<Y>,
y_out: u64
): (Coin<X>, Coin<Y>) acquires LiquidityPool, EventsStore {
assert_no_emergency();
assert!(coin_helper::is_sorted<X, Y>(), ERR_WRONG_PAIR_ORDERING);
assert!(exists<LiquidityPool<X, Y, Curve>>(@liquidswap_pool_account), ERR_POOL_DOES_NOT_EXIST);
assert_pool_unlocked<X, Y, Curve>();
let x_in_val = coin::value(&x_in);
let y_in_val = coin::value(&y_in);
assert!(x_in_val > 0 || y_in_val > 0, ERR_EMPTY_COIN_IN);
let pool = borrow_global_mut<LiquidityPool<X, Y, Curve>>(@liquidswap_pool_account);
let x_reserve_size = coin::value(&pool.coin_x_reserve);
let y_reserve_size = coin::value(&pool.coin_y_reserve);
coin::merge(&mut pool.coin_x_reserve, x_in);
coin::merge(&mut pool.coin_y_reserve, y_in);
let x_swapped = coin::extract(&mut pool.coin_x_reserve, x_out);
let y_swapped = coin::extract(&mut pool.coin_y_reserve, y_out);
let (x_res_new_after_fee, y_res_new_after_fee) =
new_reserves_after_fees_scaled<Curve>(
coin::value(&pool.coin_x_reserve),
coin::value(&pool.coin_y_reserve),
x_in_val,
y_in_val,
pool.fee
);
assert_lp_value_is_increased<Curve>(
pool.x_scale,
pool.y_scale,
(x_reserve_size as u128),
(y_reserve_size as u128),
(x_res_new_after_fee as u128),
(y_res_new_after_fee as u128),
);
split_fee_to_dao(pool, x_in_val, y_in_val);
update_oracle<X, Y, Curve>(pool, x_reserve_size, y_reserve_size);
let events_store = borrow_global_mut<EventsStore<X, Y, Curve>>(@liquidswap_pool_account);
event::emit_event(
&mut events_store.swap_handle,
SwapEvent<X, Y, Curve> {
x_in: x_in_val,
y_in: y_in_val,
x_out,
y_out,
});
(x_swapped, y_swapped)
}