Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 48 additions & 22 deletions programs/invariant/src/instructions/swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,19 @@ impl<'info> Swap<'info> {
};

// limit is on the right side of price
if x_to_y {
require!(
{ pool.sqrt_price } > sqrt_price_limit
&& sqrt_price_limit <= Price::new(MAX_SQRT_PRICE),
WrongLimit
);
} else {
require!(
{ pool.sqrt_price } < sqrt_price_limit
&& sqrt_price_limit >= Price::new(MIN_SQRT_PRICE),
WrongLimit
);
}
// if x_to_y {
// require!(
// { pool.sqrt_price } > sqrt_price_limit
// && sqrt_price_limit <= Price::new(MAX_SQRT_PRICE),
// WrongLimit
// );
// } else {
// require!(
// { pool.sqrt_price } < sqrt_price_limit
// && sqrt_price_limit >= Price::new(MIN_SQRT_PRICE),
// WrongLimit
// );
// }

let mut remaining_amount = TokenAmount(amount);

Expand All @@ -186,13 +186,16 @@ impl<'info> Swap<'info> {
let mut total_amount_referral = TokenAmount(0);

while !remaining_amount.is_zero() {
// HERE sqrt_price_limit used
let (swap_limit, limiting_tick) = get_closer_limit(
sqrt_price_limit,
x_to_y,
pool.current_tick_index,
pool.tick_spacing,
&tickmap,
)?;
msg!("swap_limit = {:?}", swap_limit);
msg!("limiting_tick = {:?}", limiting_tick);

let result = compute_swap_step(
pool.sqrt_price,
Expand All @@ -203,11 +206,13 @@ impl<'info> Swap<'info> {
pool.fee,
);
// make remaining amount smaller
msg!("remaining_amount before = {:?}", remaining_amount);
if by_amount_in {
remaining_amount -= result.amount_in + result.fee_amount;
} else {
remaining_amount -= result.amount_out;
}
msg!("remaining_amount after = {:?}", remaining_amount);

total_amount_referral += match ref_account.is_some() {
true => pool.add_fee(result.fee_amount, FixedPoint::from_scale(2, 1), x_to_y),
Expand All @@ -219,24 +224,33 @@ impl<'info> Swap<'info> {
total_amount_in += result.amount_in + result.fee_amount;
total_amount_out += result.amount_out;

let is_enough_amount_to_cross = is_enough_amount_to_push_price(
remaining_amount,
result.next_price_sqrt,
pool.liquidity,
pool.fee,
by_amount_in,
x_to_y,
);

// Fail if price would go over swap limit
if { pool.sqrt_price } == sqrt_price_limit && !remaining_amount.is_zero() {
if { pool.sqrt_price } == sqrt_price_limit
&& !remaining_amount.is_zero()
&& is_enough_amount_to_cross
{
return Err(ErrorCode::PriceLimitReached.into());
}
msg!("pool.sqrt_price = {:?}", { pool.sqrt_price });
// msg!("remaining_amount = {:?}", { remaining_amount });

// crossing tick
// trunk-ignore(clippy/unnecessary_unwrap)
if result.next_price_sqrt == swap_limit && limiting_tick.is_some() {
let (tick_index, initialized) = limiting_tick.unwrap();

let is_enough_amount_to_cross = is_enough_amount_to_push_price(
remaining_amount,
result.next_price_sqrt,
pool.liquidity,
pool.fee,
by_amount_in,
x_to_y,
);
msg!("is_enough_amount_to_cross = {:?}", {
is_enough_amount_to_cross
});

if initialized {
// Calculating address of the crossed tick
Expand Down Expand Up @@ -269,6 +283,7 @@ impl<'info> Swap<'info> {
pool.add_fee(remaining_amount, FixedPoint::from_integer(0), x_to_y);
total_amount_in += remaining_amount;
}
msg!("consume tokens");
remaining_amount = TokenAmount(0);
}
}
Expand All @@ -288,7 +303,14 @@ impl<'info> Swap<'info> {
);
pool.current_tick_index =
get_tick_at_sqrt_price(result.next_price_sqrt, pool.tick_spacing);
msg!("new tick index = {:?}", { pool.current_tick_index });
}

msg!("remaining_amount = {:?}", remaining_amount);
msg!("sqrt_price_limit = {:?}", sqrt_price_limit);
msg!("pool.sqrt_price = {:?}", { pool.sqrt_price });
// TO REMOVE
// remaining_amount = TokenAmount(0);
}

if total_amount_out.0 == 0 {
Expand All @@ -304,6 +326,10 @@ impl<'info> Swap<'info> {
let signer: &[&[&[u8]]] = get_signer!(state.nonce);
token::transfer(send_ctx.with_signer(signer), total_amount_out.0)?;

msg!("total_amount_in = {:?}", { total_amount_in.0 });
msg!("total_amount_out = {:?}", { total_amount_out.0 });
msg!("price after calculation = {:?}", { pool.sqrt_price });

match ref_account.is_some() && !total_amount_referral.is_zero() {
true => {
let take_ref_ctx = match x_to_y {
Expand Down
2 changes: 2 additions & 0 deletions programs/invariant/src/structs/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ impl Pool {
ref_percentage: FixedPoint,
in_x: bool,
) -> TokenAmount {
msg!("add fee to pool = {:?}", amount);
let protocol_fee = TokenAmount::from_decimal_up(amount.big_mul_up(self.protocol_fee));
let ref_fee = match ref_percentage.is_zero() {
true => TokenAmount(0),
false => TokenAmount::from_decimal(amount.big_mul(ref_percentage)),
};
let pool_fee = amount - protocol_fee - ref_fee;
msg!("pool_fee = {:?}", pool_fee);

if (pool_fee.is_zero() && protocol_fee.is_zero()) || self.liquidity.is_zero() {
return ref_fee;
Expand Down
6 changes: 6 additions & 0 deletions programs/invariant/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub fn get_closer_limit(
} else {
tickmap.next_initialized(current_tick, tick_spacing)
};
msg!("closes_tick_index = {:?}", closes_tick_index);

match closes_tick_index {
Some(index) => {
Expand All @@ -69,14 +70,19 @@ pub fn get_closer_limit(
let index = get_search_limit(current_tick, tick_spacing, !x_to_y);
let price = calculate_price_sqrt(index);

msg!("index = {:?}", index);
msg!("price = {:?}", price);

require!(current_tick != index, LimitReached);

// trunk-ignore(clippy/if_same_then_else)
if x_to_y && price > sqrt_price_limit {
msg!("xToY swap");
Ok((price, Some((index, false))))
} else if !x_to_y && price < sqrt_price_limit {
Ok((price, Some((index, false))))
} else {
msg!("return sqrt_price_limit");
Ok((sqrt_price_limit, None))
}
}
Expand Down
57 changes: 44 additions & 13 deletions sdk/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,19 +423,26 @@ export const getCloserLimit = (closerLimit: CloserLimit): CloserLimitResult => {
let sqrtPrice: Decimal
let init: boolean

console.log(`index = ${index}`)

if (index !== null) {
sqrtPrice = calculatePriceSqrt(index)
init = true
} else {
index = getSearchLimit(new BN(currentTick), new BN(tickSpacing), !xToY).toNumber()
sqrtPrice = calculatePriceSqrt(index as number)
init = false
console.log(`calculated index = ${index}`)
console.log(`calculated sqrtPrice = ${sqrtPrice.v.toString()}`)
console.log(`sqrtPriceLimit = ${sqrtPriceLimit.v.toString()}`)
}
if (xToY && sqrtPrice.v.gt(sqrtPriceLimit.v) && index !== null) {
console.log('xToY swap')
return { swapLimit: sqrtPrice, limitingTick: { index, initialized: init } }
} else if (!xToY && sqrtPrice.v.lt(sqrtPriceLimit.v) && index !== null) {
return { swapLimit: sqrtPrice, limitingTick: { index, initialized: init } }
} else {
console.log('tick not found')
return { swapLimit: sqrtPriceLimit, limitingTick: null }
}
}
Expand Down Expand Up @@ -510,8 +517,10 @@ export const simulateSwap = (swapParameters: SimulateSwapInterface): SimulationR
let previousTickIndex = MAX_TICK + 1
const amountPerTick: BN[] = []
const crossedTicks: number[] = []
console.log(`optionalPriceLimit = ${optionalPriceLimit?.v.toString()}`)
const priceLimit =
optionalPriceLimit ?? xToY ? calculatePriceSqrt(MIN_TICK) : calculatePriceSqrt(MAX_TICK)
optionalPriceLimit ?? (xToY ? calculatePriceSqrt(MIN_TICK) : calculatePriceSqrt(MAX_TICK))
console.log(`[PRE] priceLimit = ${priceLimit.v.toString()}`)
let accumulatedAmount: BN = new BN(0)
let accumulatedAmountOut: BN = new BN(0)
let accumulatedAmountIn: BN = new BN(0)
Expand Down Expand Up @@ -543,6 +552,8 @@ export const simulateSwap = (swapParameters: SimulateSwapInterface): SimulationR
}

const { swapLimit, limitingTick } = getCloserLimit(closerLimit)
console.log(`swap_limit = ${swapLimit.v.toString()}`)
console.log(`limitingTick = ${limitingTick}`)
const result = calculateSwapStep(
sqrtPrice,
swapLimit,
Expand All @@ -564,37 +575,44 @@ export const simulateSwap = (swapParameters: SimulateSwapInterface): SimulationR
amountDiff = result.amountOut
}

console.log(`remaining_amount before = ${remainingAmount.toString()}`)
remainingAmount = remainingAmount.sub(amountDiff)
console.log(`remaining_amount after = ${remainingAmount.toString()}`)
sqrtPrice = result.nextPrice
console.log(`sqrtPrice = ${sqrtPrice.v.toString()}`)

const isEnoughAmountToCrossTick = isEnoughAmountToPushPrice(
remainingAmount,
result.nextPrice,
pool.liquidity,
pool.fee,
byAmountIn,
xToY
)

// remainingAmount === 0 && isEnoughAmountToCrossTick

if (sqrtPrice.v.eq(priceLimitAfterSlippage.v) && remainingAmount.gt(new BN(0))) {
// throw new Error(SimulationErrors.PriceLimitReached)
status = SimulationStatus.PriceLimitReached
break
}

console.log(`isEnoughAmountToCrossTick = ${isEnoughAmountToCrossTick}`)

// crossing tick
if (result.nextPrice.v.eq(swapLimit.v) && limitingTick != null) {
const tickIndex: number = limitingTick.index
const initialized: boolean = limitingTick.initialized

const isEnoughAmountToCross = isEnoughAmountToPushPrice(
remainingAmount,
result.nextPrice,
pool.liquidity,
pool.fee,
byAmountIn,
xToY
)

// cross
if (initialized) {
if (!ticks.has(tickIndex)) {
throw new Error(SimulationStatus.TickNotFound)
}
const tick = ticks.get(tickIndex) as Tick

if (!xToY || isEnoughAmountToCross) {
if (!xToY || isEnoughAmountToPushPrice) {
// trunk-ignore(eslint/no-mixed-operators)
if (currentTickIndex >= tick.index !== tick.sign) {
liquidity = { v: liquidity.v.add(tick.liquidityChange.v) }
Expand All @@ -606,16 +624,18 @@ export const simulateSwap = (swapParameters: SimulateSwapInterface): SimulationR
if (byAmountIn) {
accumulatedAmountIn = accumulatedAmountIn.add(remainingAmount)
}
console.log('consume tokens')
remainingAmount = new BN(0)
}
}
if (xToY && isEnoughAmountToCross) {
if (xToY && isEnoughAmountToPushPrice) {
currentTickIndex = tickIndex - tickSpacing
} else {
currentTickIndex = tickIndex
}
} else {
currentTickIndex = getTickFromPrice(currentTickIndex, tickSpacing, result.nextPrice, xToY)
console.log(`new tick index = ${currentTickIndex}`)
}

// add amount to array if tick was initialized otherwise accumulate amount for next iteration
Expand All @@ -642,14 +662,25 @@ export const simulateSwap = (swapParameters: SimulateSwapInterface): SimulationR
} else {
previousTickIndex = currentTickIndex
}

console.log(`remaining_amount = ${remainingAmount.toString()}`)
console.log(`sqrt_price_limit = ${priceLimit.v.toString()}`)
console.log(`pool.sqrt_price = ${sqrtPrice.v.toString()}`)
}

if (accumulatedAmountOut.isZero() && status === SimulationStatus.Ok) {
// throw new Error(SimulationErrors.NoGainSwap)
status = SimulationStatus.NoGainSwap
}

const priceAfterSwap: BN = sqrtPrice.v
let priceAfterSwap: BN = sqrtPrice.v
if (xToY) {
priceAfterSwap = priceAfterSwap.subn(1)
} else {
priceAfterSwap = priceAfterSwap.addn(1)
}

console.log(`priceAfterSwap = ${priceAfterSwap.toString()}`)
const priceImpact = calculatePriceImpact(startingSqrtPrice, priceAfterSwap)

let minReceived: BN
Expand Down
Loading