From 89895fe94fa547a7d589babb284a07c58f136bae Mon Sep 17 00:00:00 2001 From: Robert Zaranek <158298065+DevRozaDev@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:06:55 +0200 Subject: [PATCH] Expand SqrtPrice domain (#143) * expand sqrt price domain, adjust some of the tests * update tests to match new price limit * update max swap steps * fix simulate swap test --------- Co-authored-by: none00y --- contracts/constants.ral | 6 +- contracts/invariant.ral | 2 +- contracts/math/decimal.ral | 78 ++--- contracts/math/log.ral | 56 ++-- contracts/math/types.ral | 6 +- src/consts.ts | 3 +- src/math.ts | 124 +++---- test/contract/e2e/cross-both-side.test.ts | 2 +- test/contract/e2e/cross.test.ts | 2 +- test/contract/e2e/limits.test.ts | 44 ++- test/contract/e2e/max-tick-cross.test.ts | 102 +++--- test/contract/e2e/swap.test.ts | 5 +- test/contract/unit/clamm.test.ts | 319 +++++++++++-------- test/contract/unit/log.test.ts | 132 +++++--- test/contract/unit/tickmap.test.ts | 37 +-- test/sdk/e2e/get-tickmap.test.ts | 20 +- test/sdk/e2e/simulate-invariant-swap.test.ts | 4 +- test/sdk/unit/math-port.test.ts | 53 +-- test/sdk/unit/math.test.ts | 28 +- 19 files changed, 559 insertions(+), 464 deletions(-) diff --git a/contracts/constants.ral b/contracts/constants.ral index 00e61c9..6ebe96d 100644 --- a/contracts/constants.ral +++ b/contracts/constants.ral @@ -1,7 +1,7 @@ -const GLOBAL_MAX_TICK = 221818i -const GLOBAL_MIN_TICK = -221818i +const GLOBAL_MAX_TICK = 547_613i +const GLOBAL_MIN_TICK = -GLOBAL_MAX_TICK -const MAX_SWAP_STEPS = 6 +const MAX_SWAP_STEPS = 38 const MAX_U256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935 diff --git a/contracts/invariant.ral b/contracts/invariant.ral index 4cffb72..10424de 100644 --- a/contracts/invariant.ral +++ b/contracts/invariant.ral @@ -178,7 +178,7 @@ Contract Invariant( Liquidity{v: 0}, calculateSqrtPrice(index), feeGrowthOutsideX, - feeGrowthOutsideY, + feeGrowthOutsideY, 0 ) } diff --git a/contracts/math/decimal.ral b/contracts/math/decimal.ral index 99bd738..b620421 100644 --- a/contracts/math/decimal.ral +++ b/contracts/math/decimal.ral @@ -39,59 +39,65 @@ Abstract Contract Decimal() { assert!(tickIndexAbs <= toU256!(GLOBAL_MAX_TICK), DecimalError.TickOverBounds) - if (tickIndexAbs & 0x1 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1000049998750) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00001 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1000049998750062496094023) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x2 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1000100000000) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00002 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1000100000000000000000000) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x4 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1000200010000) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00004 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1000200010000000000000000) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x8 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1000400060004) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00008 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1000400060004000100000000) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x10 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1000800280056) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00010 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1000800280056007000560028) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x20 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1001601200560) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00020 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1001601200560182043688009) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x40 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1003204964963) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x000040 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1003204964963598014666528) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x80 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1006420201726) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00080 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1006420201727613920156533) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x100 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1012881622442) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00100 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1012881622445451097078095) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x200 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1025929181080) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00200 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1025929181087729343658708) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x400 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1052530684591) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00400 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1052530684607338948386589) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x800 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1107820842005) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x00800 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1107820842039993613899215) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x1000 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1227267017980) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x01000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1227267018058200482050503) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x2000 != 0) { - sqrtPrice.v = (sqrtPrice.v * 1506184333421) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x02000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 1506184333613467388107955) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x4000 != 0) { - sqrtPrice.v = (sqrtPrice.v * 2268591246242) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x04000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 2268591246822644826925609) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x8000 != 0) { - sqrtPrice.v = (sqrtPrice.v * 5146506242525) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x08000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 5146506245160322222537991) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x00010000 != 0) { - sqrtPrice.v = (sqrtPrice.v * 26486526504348) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x10000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 26486526531474198664033811) / FIXED_POINT_DENOMINATOR } - if (tickIndexAbs & 0x00020000 != 0) { - sqrtPrice.v = (sqrtPrice.v * 701536086265529) / FIXED_POINT_DENOMINATOR + if (tickIndexAbs & 0x20000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 701536087702486644953017488) / FIXED_POINT_DENOMINATOR + } + if (tickIndexAbs & 0x40000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 492152882348911033633683861778) / FIXED_POINT_DENOMINATOR + } + if (tickIndexAbs & 0x80000 != 0) { + sqrtPrice.v = (sqrtPrice.v * 242214459604341065650571799093539783) / FIXED_POINT_DENOMINATOR } if (tickIndex >= 0i) { diff --git a/contracts/math/log.ral b/contracts/math/log.ral index cb87466..77a09b4 100644 --- a/contracts/math/log.ral +++ b/contracts/math/log.ral @@ -1,43 +1,47 @@ Abstract Contract Log() extends Decimal() { - const LOG2_SCALE = 32 + const LOG2_SCALE = 64 const LOG2_DOUBLE_SCALE = LOG2_SCALE *2 - const LOG2_SQRT10001 = 309801 - const LOG2_NEGATIVE_MAX_LOSE = 300000 - const LOG2_MIN_BINARY_POSITION = 15 + const LOG2_SQRT10001 = 1330584781654116 + const LOG2_NEGATIVE_MAX_LOSE = 1330580000000000 * 7 / 9 + const LOG2_MIN_BINARY_POSITION = 46 const LOG2_ONE = 1 << LOG2_SCALE const LOG2_HALF = LOG2_ONE >> 1 const LOG2_TWO = LOG2_ONE << 1 const LOG2_DOUBLE_ONE = 1 << LOG2_DOUBLE_SCALE - const LOG2_ACCURACY = 1 << (31 - LOG2_MIN_BINARY_POSITION) + const LOG2_ACCURACY = 1 << (63 - LOG2_MIN_BINARY_POSITION) - fn sqrtPriceToX32(val: SqrtPrice) -> U256 { + fn sqrtPriceToX64(val: SqrtPrice) -> U256 { return val.v * LOG2_ONE / SQRT_PRICE_DENOMINATOR } - fn log2FloorX32( mut sqrtPriceX32: U256) -> U256 { + fn log2FloorX64( mut sqrtPriceX64: U256) -> U256 { let mut msb = 0 - if (sqrtPriceX32 >= 1 << 32) { - sqrtPriceX32 = sqrtPriceX32 >> 32 + if (sqrtPriceX64 >= 1 << 64) { + sqrtPriceX64 = sqrtPriceX64 >> 64 + msb = msb | 64 + } + if (sqrtPriceX64 >= 1 << 32) { + sqrtPriceX64 = sqrtPriceX64 >> 32 msb = msb | 32 } - if (sqrtPriceX32 >= 1 << 16) { - sqrtPriceX32 = sqrtPriceX32 >> 16 + if (sqrtPriceX64 >= 1 << 16) { + sqrtPriceX64 = sqrtPriceX64 >> 16 msb = msb | 16 } - if (sqrtPriceX32 >= 1 << 8) { - sqrtPriceX32 = sqrtPriceX32 >> 8 + if (sqrtPriceX64 >= 1 << 8) { + sqrtPriceX64 = sqrtPriceX64 >> 8 msb = msb | 8 } - if (sqrtPriceX32 >= 1 << 4) { - sqrtPriceX32 = sqrtPriceX32 >> 4 + if (sqrtPriceX64 >= 1 << 4) { + sqrtPriceX64 = sqrtPriceX64 >> 4 msb = msb | 4 } - if (sqrtPriceX32 >= 1 << 2) { - sqrtPriceX32 = sqrtPriceX32 >> 2 + if (sqrtPriceX64 >= 1 << 2) { + sqrtPriceX64 = sqrtPriceX64 >> 2 msb = msb | 2 } - if (sqrtPriceX32 >= 1 << 1) { + if (sqrtPriceX64 >= 1 << 1) { msb = msb | 1 } @@ -57,16 +61,16 @@ Abstract Contract Log() extends Decimal() { return accurateTick - substrahend } } - - fn log2IterativeApproximationX32(mut sqrtPriceX32: U256) -> (Bool, U256) { + + fn log2IterativeApproximationX64(mut sqrtPriceX64: U256) -> (Bool, U256) { let mut sign = true - if (sqrtPriceX32 < LOG2_ONE) { + if (sqrtPriceX64 < LOG2_ONE) { sign = false - sqrtPriceX32 = (LOG2_DOUBLE_ONE / (sqrtPriceX32 + 1)) + sqrtPriceX64 = (LOG2_DOUBLE_ONE / (sqrtPriceX64 + 1)) } - let log2Floor = log2FloorX32( sqrtPriceX32 >> LOG2_SCALE) + let log2Floor = log2FloorX64( sqrtPriceX64 >> LOG2_SCALE) let mut result = log2Floor << LOG2_SCALE - let mut y = sqrtPriceX32 >> log2Floor + let mut y = sqrtPriceX64 >> log2Floor if (y == LOG2_ONE) { return sign, result @@ -85,9 +89,9 @@ Abstract Contract Log() extends Decimal() { pub fn getTickAtSqrtPrice(sqrtPrice: SqrtPrice, tickSpacing: U256) -> I256 { assert!(sqrtPrice.v <= MAX_SQRT_PRICE && sqrtPrice.v >= MIN_SQRT_PRICE, LogError.SqrtPriceOutOfRange) - let sqrtPriceX32 = sqrtPriceToX32(sqrtPrice) + let sqrtPriceX64 = sqrtPriceToX64(sqrtPrice) - let (log2Sign, log2SqrtPrice) = log2IterativeApproximationX32(sqrtPriceX32) + let (log2Sign, log2SqrtPrice) = log2IterativeApproximationX64(sqrtPriceX64) let mut absFloorTick = 0 let mut nearerTick = 0i diff --git a/contracts/math/types.ral b/contracts/math/types.ral index a0c0182..9033e49 100644 --- a/contracts/math/types.ral +++ b/contracts/math/types.ral @@ -3,8 +3,8 @@ struct SqrtPrice{ } const SQRT_PRICE_SCALE = 24 const SQRT_PRICE_DENOMINATOR = 10**SQRT_PRICE_SCALE -const MAX_SQRT_PRICE = 65535383934512647000000000000 -const MIN_SQRT_PRICE = 15258932000000000000 +const MAX_SQRT_PRICE = 777446803530032965262892619622664451 +const MIN_SQRT_PRICE = 1286261639329 struct Liquidity{ mut v: U256 @@ -36,6 +36,6 @@ const TOKEN_AMOUNT_DENOMINATOR = 10**TOKEN_AMOUNT_SCALE struct FixedPoint{ mut v: U256 } -const FIXED_POINT_SCALE = 12 +const FIXED_POINT_SCALE = 24 const FIXED_POINT_DENOMINATOR = 10**FIXED_POINT_SCALE diff --git a/src/consts.ts b/src/consts.ts index 8878700..4a8a748 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -59,7 +59,8 @@ export enum VMError { ArithmeticError = 'ArithmeticError', OutOfGas = 'OutOfGas', NotEnoughBalance = 'Not enough approved balance for address', - MaxStoredAssets = 'max token number is 8' + MaxStoredAssets = 'max token number is 8', + VMExecutionError = 'VM execution error: Assertion Failed in Contract' } export const INVARIANT_ADDRESS = { diff --git a/src/math.ts b/src/math.ts index fcfdfe0..bee146c 100644 --- a/src/math.ts +++ b/src/math.ts @@ -56,59 +56,67 @@ export const calculateSqrtPrice = (tickIndex: bigint): SqrtPrice => { throw new Error(String(DecimalError.TickOverBounds)) } - if (tickIndexAbs & 0x1n) { - sqrtPrice = ((sqrtPrice * 1000049998750n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00001n) { + sqrtPrice = ((sqrtPrice * 1000049998750062496094023n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x2n) { - sqrtPrice = ((sqrtPrice * 1000100000000n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00002n) { + sqrtPrice = ((sqrtPrice * 1000100000000000000000000n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x4n) { - sqrtPrice = ((sqrtPrice * 1000200010000n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00004n) { + sqrtPrice = ((sqrtPrice * 1000200010000000000000000n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x8n) { - sqrtPrice = ((sqrtPrice * 1000400060004n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00008n) { + sqrtPrice = ((sqrtPrice * 1000400060004000100000000n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x10n) { - sqrtPrice = ((sqrtPrice * 1000800280056n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00010n) { + sqrtPrice = ((sqrtPrice * 1000800280056007000560028n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x20n) { - sqrtPrice = ((sqrtPrice * 1001601200560n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00020n) { + sqrtPrice = ((sqrtPrice * 1001601200560182043688009n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x40n) { - sqrtPrice = ((sqrtPrice * 1003204964963n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00040n) { + sqrtPrice = ((sqrtPrice * 1003204964963598014666528n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x80n) { - sqrtPrice = ((sqrtPrice * 1006420201726n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00080n) { + sqrtPrice = ((sqrtPrice * 1006420201727613920156533n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x100n) { - sqrtPrice = ((sqrtPrice * 1012881622442n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00100n) { + sqrtPrice = ((sqrtPrice * 1012881622445451097078095n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x200n) { - sqrtPrice = ((sqrtPrice * 1025929181080n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00200n) { + sqrtPrice = ((sqrtPrice * 1025929181087729343658708n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x400n) { - sqrtPrice = ((sqrtPrice * 1052530684591n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00400n) { + sqrtPrice = ((sqrtPrice * 1052530684607338948386589n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x800n) { - sqrtPrice = ((sqrtPrice * 1107820842005n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x00800n) { + sqrtPrice = ((sqrtPrice * 1107820842039993613899215n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x1000n) { - sqrtPrice = ((sqrtPrice * 1227267017980n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x01000n) { + sqrtPrice = ((sqrtPrice * 1227267018058200482050503n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x2000n) { - sqrtPrice = ((sqrtPrice * 1506184333421n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x02000n) { + sqrtPrice = ((sqrtPrice * 1506184333613467388107955n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x4000n) { - sqrtPrice = ((sqrtPrice * 2268591246242n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x04000n) { + sqrtPrice = ((sqrtPrice * 2268591246822644826925609n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x8000n) { - sqrtPrice = ((sqrtPrice * 5146506242525n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x08000n) { + sqrtPrice = ((sqrtPrice * 5146506245160322222537991n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x00010000n) { - sqrtPrice = ((sqrtPrice * 26486526504348n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x10000n) { + sqrtPrice = ((sqrtPrice * 26486526531474198664033811n) / FIXED_POINT_DENOMINATOR) as FixedPoint } - if (tickIndexAbs & 0x00020000n) { - sqrtPrice = ((sqrtPrice * 701536086265529n) / FIXED_POINT_DENOMINATOR) as FixedPoint + if (tickIndexAbs & 0x20000n) { + sqrtPrice = ((sqrtPrice * 701536087702486644953017488n) / FIXED_POINT_DENOMINATOR) as FixedPoint + } + if (tickIndexAbs & 0x40000n) { + sqrtPrice = ((sqrtPrice * 492152882348911033633683861778n) / + FIXED_POINT_DENOMINATOR) as FixedPoint + } + if (tickIndexAbs & 0x80000n) { + sqrtPrice = ((sqrtPrice * 242214459604341065650571799093539783n) / + FIXED_POINT_DENOMINATOR) as FixedPoint } if (tickIndex >= 0n) { @@ -427,8 +435,8 @@ export const getTickAtSqrtPrice = (sqrtPrice: bigint, tickSpacing: bigint): bigi throw new Error(String(LogError.SqrtPriceOutOfRange)) } - const sqrtPriceX32 = sqrtPriceToX32(sqrtPrice) - const [log2Sign, log2SqrtPrice] = log2IterativeApproximationX32(sqrtPriceX32) + const sqrtPriceX64 = sqrtPriceToX64(sqrtPrice) + const [log2Sign, log2SqrtPrice] = log2IterativeApproximationX64(sqrtPriceX64) let absFloorTick: bigint let nearerTick: bigint @@ -467,20 +475,20 @@ export const getTickAtSqrtPrice = (sqrtPrice: bigint, tickSpacing: bigint): bigi } } -const sqrtPriceToX32 = (val: bigint): bigint => { +const sqrtPriceToX64 = (val: bigint): bigint => { return (val * LOG2_ONE) / SQRT_PRICE_DENOMINATOR } -const log2IterativeApproximationX32 = (sqrtPriceX32: bigint): [boolean, bigint] => { +const log2IterativeApproximationX64 = (sqrtPriceX64: bigint): [boolean, bigint] => { let sign = true - if (sqrtPriceX32 < LOG2_ONE) { + if (sqrtPriceX64 < LOG2_ONE) { sign = false - sqrtPriceX32 = LOG2_DOUBLE_ONE / (sqrtPriceX32 + 1n) + sqrtPriceX64 = LOG2_DOUBLE_ONE / (sqrtPriceX64 + 1n) } - const log2Floor = log2FloorX32(sqrtPriceX32 >> LOG2_SCALE) + const log2Floor = log2FloorX64(sqrtPriceX64 >> LOG2_SCALE) let result = log2Floor << LOG2_SCALE - let y = sqrtPriceX32 >> log2Floor + let y = sqrtPriceX64 >> log2Floor if (y == LOG2_ONE) { return [sign, result] @@ -497,30 +505,34 @@ const log2IterativeApproximationX32 = (sqrtPriceX32: bigint): [boolean, bigint] return [sign, result] } -const log2FloorX32 = (sqrtPriceX32: bigint): bigint => { +const log2FloorX64 = (sqrtPriceX64: bigint): bigint => { let msb = 0n - if (sqrtPriceX32 >= 1n << 32n) { - sqrtPriceX32 >>= 32n + if (sqrtPriceX64 >= 1n << 64n) { + sqrtPriceX64 >>= 64n + msb |= 64n + } + if (sqrtPriceX64 >= 1n << 32n) { + sqrtPriceX64 >>= 32n msb |= 32n } - if (sqrtPriceX32 >= 1n << 16n) { - sqrtPriceX32 >>= 16n + if (sqrtPriceX64 >= 1n << 16n) { + sqrtPriceX64 >>= 16n msb |= 16n } - if (sqrtPriceX32 >= 1n << 8n) { - sqrtPriceX32 >>= 8n + if (sqrtPriceX64 >= 1n << 8n) { + sqrtPriceX64 >>= 8n msb |= 8n } - if (sqrtPriceX32 >= 1n << 4n) { - sqrtPriceX32 >>= 4n + if (sqrtPriceX64 >= 1n << 4n) { + sqrtPriceX64 >>= 4n msb |= 4n } - if (sqrtPriceX32 >= 1n << 2n) { - sqrtPriceX32 >>= 2n + if (sqrtPriceX64 >= 1n << 2n) { + sqrtPriceX64 >>= 2n msb |= 2n } - if (sqrtPriceX32 >= 1n << 1n) { + if (sqrtPriceX64 >= 1n << 1n) { msb |= 1n } diff --git a/test/contract/e2e/cross-both-side.test.ts b/test/contract/e2e/cross-both-side.test.ts index 417181d..e0cf164 100644 --- a/test/contract/e2e/cross-both-side.test.ts +++ b/test/contract/e2e/cross-both-side.test.ts @@ -185,7 +185,7 @@ describe('cross tests', () => { feeProtocolTokenX: 4n, feeProtocolTokenY: 2n, liquidity: expectedLiquidity, - sqrtPrice: 999500149964999999999999n + sqrtPrice: 999500149965006998740208n }) expect(await getTick(invariant, poolKey, -20n)).toMatchObject({ diff --git a/test/contract/e2e/cross.test.ts b/test/contract/e2e/cross.test.ts index 0e2e3b5..14b6e85 100644 --- a/test/contract/e2e/cross.test.ts +++ b/test/contract/e2e/cross.test.ts @@ -83,7 +83,7 @@ describe('cross tests', () => { expect(await getPool(invariant, poolKey)).toMatchObject({ liquidity: poolBefore.liquidity + liquidityDelta, currentTickIndex: -20n, - sqrtPrice: 999254456240199142700995n, + sqrtPrice: 999254456240206138000814n, feeGrowthGlobalX: 4n * 10n ** 22n, feeGrowthGlobalY: 0n, feeProtocolTokenX: 2n, diff --git a/test/contract/e2e/limits.test.ts b/test/contract/e2e/limits.test.ts index 3e183ab..7edcb49 100644 --- a/test/contract/e2e/limits.test.ts +++ b/test/contract/e2e/limits.test.ts @@ -51,9 +51,7 @@ describe('limits tests', () => { const user = await getSigner(ONE_ALPH * 1000n, 0) await withdrawTokens(user, [tokenX, withdrawAmount], [tokenY, withdrawAmount]) - // 2^176 - const limitAmount = 95780971304118053647396689196894323976171195136475136n as TokenAmount - // 0.6% fee + const limitAmount = (2n ** 176n) as TokenAmount const [fee, tickSpacing] = [toPercentage(6n, 3n), 1n] const feeTier = newFeeTier(fee, tickSpacing) const poolKey = newPoolKey(tokenX.contractId, tokenY.contractId, feeTier) @@ -74,7 +72,7 @@ describe('limits tests', () => { sqrtPrice, true ) - const y = await getDeltaY(calculateSqrtPrice(lowerTick), sqrtPrice, liquidityDelta, true) + const y = getDeltaY(calculateSqrtPrice(lowerTick), sqrtPrice, liquidityDelta, true) const slippageLimit = initSqrtPrice await initPosition( @@ -106,15 +104,13 @@ describe('limits tests', () => { y: y }) }) + test('deposit limits at upper limit', async () => { const [invariant, tokenX, tokenY] = await initDexAndTokens(admin, withdrawAmount) const user = await getSigner(ONE_ALPH * 1000n, 0) await withdrawTokens(user, [tokenX, withdrawAmount], [tokenY, withdrawAmount]) - // 2^236 - const limitAmount = 110427941548649020598956093796432407239217743554726184882600387580788736n - // 0.6% fee const [fee, tickSpacing] = [toPercentage(6n, 3n), 1n] const feeTier = newFeeTier(fee, tickSpacing) const poolKey = newPoolKey(tokenX.contractId, tokenY.contractId, feeTier) @@ -129,9 +125,8 @@ describe('limits tests', () => { expect(currentTickIndex).toBe(initTick) expect(sqrtPrice).toBe(initSqrtPrice) - const positionAmount = (limitAmount - 1n) as TokenAmount const { l: liquidityDelta } = getLiquidityByY( - positionAmount, + MAX_U256 as TokenAmount, 0n, GLOBAL_MAX_TICK, sqrtPrice, @@ -160,9 +155,7 @@ describe('limits tests', () => { const user = await getSigner(ONE_ALPH * 1000n, 0) await withdrawTokens(user, [tokenX, withdrawAmount], [tokenY, withdrawAmount]) - // 2^177 - const limitAmount = 191561942608236107294793378393788647952342390272950272n - // 0.6% fee + const limitAmount = 2n ** 177n const [fee, tickSpacing] = [toPercentage(6n, 3n), 1n] const feeTier = newFeeTier(fee, tickSpacing) const poolKey = newPoolKey(tokenX.contractId, tokenY.contractId, feeTier) @@ -233,10 +226,6 @@ describe('limits tests', () => { const user = await getSigner(ONE_ALPH * 1000n, 0) await withdrawTokens(user, [tokenX, withdrawAmount], [tokenY, withdrawAmount]) - // 2^237 - const liquidityLimitAmount = - 220855883097298041197912187592864814478435487109452369765200775161577472n as Liquidity - // 0.6% fee const [fee, tickSpacing] = [toPercentage(6n, 3n), 1n] const feeTier = newFeeTier(fee, tickSpacing) const poolKey = newPoolKey(tokenX.contractId, tokenY.contractId, feeTier) @@ -249,10 +238,16 @@ describe('limits tests', () => { const { currentTickIndex, sqrtPrice } = await getPool(invariant, poolKey) expect(currentTickIndex).toBe(initTick) expect(sqrtPrice).toBe(initSqrtPrice) - - const liquidityDelta = liquidityLimitAmount const slippageLimit = initSqrtPrice + const { l: liquidityDelta } = getLiquidityByY( + MAX_U256 as TokenAmount, + GLOBAL_MIN_TICK, + GLOBAL_MAX_TICK, + sqrtPrice, + false + ) + await initPosition( invariant, user, @@ -270,7 +265,7 @@ describe('limits tests', () => { expect(invariantBalance).toMatchObject({ x: 0n, - y: 144738750896072444118518848476700723725861030905971328860187553943253568n + y: 115792089237316195423570985008687907853269984665640564039457584007913125390908n }) }) }) @@ -281,10 +276,7 @@ const bigDepositOneAndSwapTheOther = async (xToY: boolean) => { const user = await getSigner(ONE_ALPH * 1000n, 0) await withdrawTokens(user, [tokenX, withdrawAmount], [tokenY, withdrawAmount]) - // 2^206 - const limitAmount = - 102844034832575377634685573909834406561420991602098741459288064n as TokenAmount - // 0.6% fee + const limitAmount = (2n ** 178n) as TokenAmount const [fee, tickSpacing] = [toPercentage(6n, 3n), 1n] const feeTier = newFeeTier(fee, tickSpacing) const poolKey = newPoolKey(tokenX.contractId, tokenY.contractId, feeTier) @@ -324,10 +316,10 @@ const bigDepositOneAndSwapTheOther = async (xToY: boolean) => { const expectedBalance = xToY ? { tokenX: 115792089237316195423570985008687907853269984665640564039457584007913129639935n, - tokenY: 115792089237316092579536152433310273167696074831234002618465981909171670351871n + tokenY: 115792089237316195423570601884802691381055395078883776462161679323132583739391n } : { - tokenX: 115792089237316092579536152433310273167696074831234002618465981909171670351871n, + tokenX: 115792089237316195423570601884802691381055395078883776462161679323132583739391n, tokenY: 115792089237316195423570985008687907853269984665640564039457584007913129639935n } @@ -350,7 +342,7 @@ const bigDepositOneAndSwapTheOther = async (xToY: boolean) => { tokenY: await balanceOf(tokenY.contractId, user.address) } const expectedAmount = - 115792089237316092579536152433310273167696074831234002618465981909171670351871n + 115792089237316195423570601884802691381055395078883776462161679323132583739391n if (xToY) { expect(userBalance.tokenX).toBe(expectedAmount) expect(userBalance.tokenY).not.toBe(0n) diff --git a/test/contract/e2e/max-tick-cross.test.ts b/test/contract/e2e/max-tick-cross.test.ts index 71f1a74..58eccb6 100644 --- a/test/contract/e2e/max-tick-cross.test.ts +++ b/test/contract/e2e/max-tick-cross.test.ts @@ -25,7 +25,7 @@ describe('max tick cross spec', () => { const searchLimit = SEARCH_RANGE * tickSpacing const txGasLimit = 5000000n const positionOwnerMint = (1n << 128n) as TokenAmount - const swapperMint = (1n << 30n) as TokenAmount + const swapperMint = (1n << 50n) as TokenAmount const supply = (positionOwnerMint + swapperMint) as TokenAmount const liquidityDelta = toLiquidity(10000000n) let admin: PrivateKeyWallet @@ -50,9 +50,9 @@ describe('max tick cross spec', () => { poolKey = newPoolKey(tokenX.contractId, tokenY.contractId, feeTier) }) - test('max tick cross swap xToY and ByAmountIn, no liquidity gap between positions', async () => { - const lastInitializedTick = -250n - const amount = 40282n as TokenAmount + test.only('max tick cross swap xToY and ByAmountIn, no liquidity gap between positions', async () => { + const lastInitializedTick = -750n + const amount = 301241n as TokenAmount const xToY = true const slippage = MIN_SQRT_PRICE const byAmountIn = true @@ -87,17 +87,17 @@ describe('max tick cross spec', () => { xToY, amount, byAmountIn, - targetSqrtPrice + slippage ) const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / -10n - expect(crosses).toBe(8n) + expect(crosses).toBe(59n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap yToX and ByAmountIn, no liquidity gap between positions', async () => { - const lastInitializedTick = 120n - const amount = 44998n as TokenAmount + const lastInitializedTick = 1120n + const amount = 337572n as TokenAmount const xToY = false const slippage = MAX_SQRT_PRICE const byAmountIn = true @@ -138,12 +138,12 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / 10n - expect(crosses).toBe(8n) + expect(crosses).toBe(66n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap xToY and ByAmountIn, liquidity gap between positions', async () => { - const lastInitializedTick = -250n - const amount = 35250n as TokenAmount + const lastInitializedTick = -1250n + const amount = 200032n as TokenAmount const xToY = true const slippage = MIN_SQRT_PRICE const byAmountIn = true @@ -182,12 +182,12 @@ describe('max tick cross spec', () => { ) const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / -10n - expect(crosses).toBe(13n) + expect(crosses).toBe(77n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap yToX and ByAmountIn, liquidity gap between positions', async () => { - const lastInitializedTick = 240n - const amount = 40000n as TokenAmount + const lastInitializedTick = 2400n + const amount = 215744n as TokenAmount const xToY = false const slippage = MAX_SQRT_PRICE const byAmountIn = true @@ -227,12 +227,12 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / 10n - expect(crosses).toBe(14n) + expect(crosses).toBe(83n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap xToY and ByAmountIn, positions between search limit range', async () => { - const lastInitializedTick = -35000n - const amount = 13569916n as TokenAmount + const lastInitializedTick = -150000n + const amount = 1395687588n as TokenAmount const xToY = true const slippage = MIN_SQRT_PRICE const byAmountIn = true @@ -270,12 +270,12 @@ describe('max tick cross spec', () => { ) const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / -searchLimit - expect(crosses).toBe(6n) + expect(crosses).toBe(38n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap yToX and ByAmountIn, positions between search limit range', async () => { - const lastInitializedTick = 25000n - const amount = 17947500n as TokenAmount + const lastInitializedTick = 150000n + const amount = 2460737677n as TokenAmount const xToY = false const slippage = MAX_SQRT_PRICE const byAmountIn = true @@ -313,13 +313,13 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / searchLimit - expect(crosses).toBe(7n) + expect(crosses).toBe(42n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap xToY and ByAmountOut, no liquidity gap between positions', async () => { - const lastInitializedTick = -250n - const mintAmount = 60000n as TokenAmount - const swapAmount = 44500n as TokenAmount + const lastInitializedTick = -750n + const mintAmount = 600000n as TokenAmount + const swapAmount = 339068n as TokenAmount const xToY = true const slippage = MIN_SQRT_PRICE const byAmountIn = false @@ -368,13 +368,14 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / -10n - expect(crosses).toBe(9n) + expect(crosses).toBe(69n) + console.log(gasAmount, txGasLimit) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap yToX and ByAmountOut, no liquidity gap between positions', async () => { - const lastInitializedTick = 120n - const mintAmount = 60000n as TokenAmount - const swapAmount = 39000n as TokenAmount + const lastInitializedTick = 900n + const mintAmount = 600000n as TokenAmount + const swapAmount = 314889n as TokenAmount const xToY = false const slippage = MAX_SQRT_PRICE @@ -423,13 +424,13 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / 10n - expect(crosses).toBe(7n) + expect(crosses).toBe(64n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap xToY and ByAmountOut, liquidity gap between positions', async () => { - const lastInitializedTick = -500n - const mintAmount = 60000n as TokenAmount - const swapAmount = 39500n as TokenAmount + const lastInitializedTick = -1000n + const mintAmount = 600000n as TokenAmount + const swapAmount = 210363n as TokenAmount const xToY = true const slippage = MIN_SQRT_PRICE const byAmountIn = false @@ -462,7 +463,6 @@ describe('max tick cross spec', () => { byAmountIn, slippage ) - const poolBefore = await getPool(invariant, poolKey) const { gasAmount } = await initSwap( @@ -478,13 +478,15 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / -10n - expect(crosses).toBe(16n) + expect(crosses).toBe(86n) + console.log(gasAmount, txGasLimit) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap yToX and ByAmountOut, liquidity gap between positions', async () => { - const lastInitializedTick = 360n - const mintAmount = 60000n as TokenAmount - const swapAmount = 39000n as TokenAmount + console.log(invariant.address, swapper.address) + const lastInitializedTick = 1360n + const mintAmount = 600000000n as TokenAmount + const swapAmount = 200872n as TokenAmount const xToY = false const slippage = MAX_SQRT_PRICE @@ -507,9 +509,9 @@ describe('max tick cross spec', () => { slippageLimit ) } + const poolBefore = await getPool(invariant, poolKey) await withdrawTokens(swapper, [tokenY, mintAmount]) - const { targetSqrtPrice } = await quote( invariant, poolKey, @@ -519,7 +521,6 @@ describe('max tick cross spec', () => { slippage ) - const poolBefore = await getPool(invariant, poolKey) const { gasAmount } = await initSwap( invariant, swapper, @@ -533,17 +534,17 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / 10n - expect(crosses).toBe(14n) + expect(crosses).toBe(80n) + console.log(gasAmount, txGasLimit) expect(gasAmount).toBeLessThan(txGasLimit) - }, 100000) + }, 1000000000) test('max tick cross swap xToY and ByAmountOut, positions between search limit range', async () => { - const lastInitializedTick = -25000n - const mintAmount = 20000000n as TokenAmount - const swapAmount = 6050000n as TokenAmount + const lastInitializedTick = -155040n + const mintAmount = 200000000000n as TokenAmount const xToY = true const slippage = MIN_SQRT_PRICE const byAmountIn = false - + const swapAmount = 9956848n as TokenAmount for (let i = lastInitializedTick; i < 0n; i += searchLimit) { const positionOwnerBalanceX = await balanceOf(tokenX.contractId, positionOwner.address) const positionOwnerBalanceY = await balanceOf(tokenY.contractId, positionOwner.address) @@ -587,13 +588,13 @@ describe('max tick cross spec', () => { ) const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / -searchLimit - expect(crosses).toBe(7n) + expect(crosses).toBe(42n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) test('max tick cross swap yToX and ByAmountOut, positions between search limit range', async () => { - const lastInitializedTick = 25000n - const mintAmount = 20000000n as TokenAmount - const swapAmount = 6408000n as TokenAmount + const lastInitializedTick = 155000n + const mintAmount = 20000000000n as TokenAmount + const swapAmount = 9959260n as TokenAmount const xToY = false const slippage = MAX_SQRT_PRICE const byAmountIn = false @@ -641,7 +642,8 @@ describe('max tick cross spec', () => { const poolAfter = await getPool(invariant, poolKey) const crosses = (poolAfter.currentTickIndex - poolBefore.currentTickIndex) / searchLimit - expect(crosses).toBe(7n) + console.log(gasAmount, txGasLimit) + expect(crosses).toBe(43n) expect(gasAmount).toBeLessThan(txGasLimit) }, 100000) }) diff --git a/test/contract/e2e/swap.test.ts b/test/contract/e2e/swap.test.ts index 86fc683..054dcf1 100644 --- a/test/contract/e2e/swap.test.ts +++ b/test/contract/e2e/swap.test.ts @@ -409,10 +409,9 @@ describe('swap tests', () => { const dexBalance = await getReserveBalances(invariant, poolKey) expect(dexBalance).toStrictEqual({ x: 500n, y: 2499n }) - await expectError( - InvariantError.TickLimitReached, + await expectVMError( + VMError.OutOfGas, initSwap(invariant, swapper, poolKey, false, swapAmount, true, MAX_SQRT_PRICE), - invariant ) } }) diff --git a/test/contract/unit/clamm.test.ts b/test/contract/unit/clamm.test.ts index 5ca2363..70254a2 100644 --- a/test/contract/unit/clamm.test.ts +++ b/test/contract/unit/clamm.test.ts @@ -79,20 +79,11 @@ describe('clamm tests', () => { // max FeeGrowth case inside of domain { - const maxTickSpacing = 100n - const tickSearchRange = 256n - const sqrtPriceUpper = 65535383934512647000000000000n - const sqrtPriceLowerIndex = 221818n - maxTickSpacing * tickSearchRange - const sqrtPriceLower = await calculateSqrtPrice(clamm, sqrtPriceLowerIndex) - - const maxDeltaSqrtPrice = sqrtPriceUpper - sqrtPriceLower - const maxLiquidity = ((1n << 256n) - 1n) as Liquidity - const maxToken = ((maxLiquidity * maxDeltaSqrtPrice) / - LIQUIDITY_DENOMINATOR / - SQRT_PRICE_DENOMINATOR) as TokenAmount + const maxLiquidity = MAX_U256 as Liquidity + const maxToken = MAX_U256 as TokenAmount const feeGrowth = await feeGrowthFromFee(clamm, maxLiquidity, maxToken) - expect(feeGrowth).toStrictEqual(473129365723326089999999999999999n) + expect(feeGrowth).toStrictEqual(1000000000000000000000000000000000n) } // min FeeGrowth case inside of domain { @@ -102,15 +93,11 @@ describe('clamm tests', () => { FEE_GROWTH_DENOMINATOR * LIQUIDITY_DENOMINATOR * basisPoint) as Liquidity - const feeGrowth = await feeGrowthFromFee( - clamm, - maxLiquidity, - (minToken + basisPoint) as TokenAmount - ) + await feeGrowthFromFee(clamm, maxLiquidity, (minToken + basisPoint) as TokenAmount) // outside of domain trigger overflow due to result not fit into FeeGrowth { const liquidity = 1n as Liquidity - const fee = ((1n << 256n) - 1n) as TokenAmount + const fee = MAX_U256 as TokenAmount await expectError( ArithmeticError.CastOverflow, @@ -185,7 +172,7 @@ describe('clamm tests', () => { } // max value inside domain { - const liquidity = ((1n << 256n) - 1n) as Liquidity + const liquidity = MAX_U256 as Liquidity const feeGrowth = (100000n * 10n ** 28n) as FeeGrowth const out = await toFee(clamm, liquidity, feeGrowth) expect(out).toStrictEqual( @@ -194,8 +181,8 @@ describe('clamm tests', () => { } // Overflow { - const liquidity = ((1n << 256n) - 1n) as Liquidity - const feeGrowth = ((1n << 256n) - 1n) as FeeGrowth + const liquidity = MAX_U256 as Liquidity + const feeGrowth = MAX_U256 as FeeGrowth await expectError(ArithmeticError.CastOverflow, toFee(clamm, liquidity, feeGrowth), clamm) } // FeeGrowth = 0 @@ -376,7 +363,7 @@ describe('clamm tests', () => { test('shouldnt overflow in intermediate operations', async () => { const sqrtPriceA = toSqrtPrice(1n) const sqrtPriceB = toSqrtPrice(5n, 1n) - const liquidity = ((1n << 256n) - 1n) as Liquidity + const liquidity = MAX_U256 as Liquidity await getDeltaX(clamm, sqrtPriceA, sqrtPriceB, liquidity, true) await getDeltaX(clamm, sqrtPriceA, sqrtPriceB, liquidity, false) }) @@ -390,39 +377,75 @@ describe('clamm tests', () => { }) describe('get delta x - domain', () => { let clamm: CLAMMInstance - const almostMinSqrtPrice = 15259695000000000000n as SqrtPrice - const maxLiquidity = ((1n << 256n) - 1n) as Liquidity + const almostMinSqrtPrice = (MIN_SQRT_PRICE + 1n) as SqrtPrice + const maxLiquidity = MAX_U256 as Liquidity const minLiquidity = 1n as Liquidity beforeAll(async () => { clamm = await deployCLAMM(sender) }) test('maximalize delta sqrt price and liquidity', async () => { - const params = { - sqrtPriceA: MAX_SQRT_PRICE, - sqrtPriceB: MIN_SQRT_PRICE, - liquidity: maxLiquidity + { + const maxLiquidity = + 14893892252372018684584396344694974244327977275368655982357119807809415n as Liquidity + const params = { + sqrtPriceA: MAX_SQRT_PRICE, + sqrtPriceB: MIN_SQRT_PRICE, + liquidity: maxLiquidity + } + const resultUp = await getDeltaX( + clamm, + params.sqrtPriceA, + params.sqrtPriceB, + params.liquidity, + true + ) + expect(resultUp).toEqual( + 115792089237316195423570985008687907853269984665640564039457584007913127186298n + ) + + await expectVMError( + VMError.VMExecutionError, + getDeltaX( + clamm, + params.sqrtPriceA, + params.sqrtPriceB, + (params.liquidity + 1n) as Liquidity, + true + ) + ) + } + + { + const maxLiquidity = + 14893892252372018684584411238587226621839738068399339794075395228890515n as Liquidity + const params = { + sqrtPriceA: MAX_SQRT_PRICE, + sqrtPriceB: MIN_SQRT_PRICE, + liquidity: maxLiquidity + } + const resultUp = await getDeltaX( + clamm, + params.sqrtPriceA, + params.sqrtPriceB, + params.liquidity, + false + ) + expect(resultUp).toEqual( + 115792089237316195423570985008687907853269984665640564039457584007913124933217n + ) + + await expectVMError( + VMError.VMExecutionError, + getDeltaX( + clamm, + params.sqrtPriceA, + params.sqrtPriceB, + (params.liquidity + 1n) as Liquidity, + false + ) + ) } - const resultUp = await getDeltaX( - clamm, - params.sqrtPriceA, - params.sqrtPriceB, - params.liquidity, - true - ) - const resultDown = await getDeltaX( - clamm, - params.sqrtPriceA, - params.sqrtPriceB, - params.liquidity, - false - ) - expect(resultUp).toEqual( - 75884792730156830614567103553061795263351065677581979504561495713443442818879n - ) - expect(resultDown).toEqual( - 75884792730156830614567103553061795263351065677581979504561495713443442818878n - ) }) test('maximalize delta sqrt price and minimalize liquidity', async () => { const params = { @@ -444,8 +467,8 @@ describe('clamm tests', () => { params.liquidity, false ) - expect(resultUp).toEqual(1n) - expect(resultDown).toEqual(0n) + expect(resultUp).toEqual(7774469n) + expect(resultDown).toEqual(7774468n) }) test('minimize denominator on maximize liquidity which fit into token amounts', async () => { const params = { @@ -468,16 +491,16 @@ describe('clamm tests', () => { false ) expect(resultUp).toEqual( - 3794315473971847510172532341754979462199874072217062973965311338137066234n + 1157920892373161954235709850086879078532699846656405640394575840079131296n ) expect(resultDown).toEqual( - 3794315473971847510172532341754979462199874072217062973965311338137066233n + 578960446186580977117854925043439539266349923328202820197287920039565648n ) }) test('minimize denominator on minimize liquidity which fit into token amounts', async () => { const params = { sqrtPriceA: MIN_SQRT_PRICE, - sqrtPriceB: almostMinSqrtPrice, + sqrtPriceB: (almostMinSqrtPrice + 99999n) as SqrtPrice, liquidity: minLiquidity } const resultUp = await getDeltaX( @@ -500,7 +523,7 @@ describe('clamm tests', () => { test('delta price limited by search range on max liquidity', async () => { const searchLimit = 256n const tickSpacing = 100n - const maxSearchLimit = 221818n - searchLimit * tickSpacing + const maxSearchLimit = GLOBAL_MAX_TICK - searchLimit * tickSpacing const minSearchSqrtPrice = await calculateSqrtPrice(clamm, maxSearchLimit) const params = { @@ -515,13 +538,13 @@ describe('clamm tests', () => { params.liquidity, true ) - expect(resultUp).toEqual( - 45875017378130362421757891862614875858481775310156442203847653871247n - ) + expect(resultUp).toEqual(3867064427937095529780795325095328040602638051663673509970074n) }) test('minimal price difference', async () => { - const almostMaxSqrtPrice = (MAX_SQRT_PRICE - toSqrtPrice(1n)) as SqrtPrice - const almostMinSqrtPrice = (MIN_SQRT_PRICE + toSqrtPrice(1n)) as SqrtPrice + const almostMaxSqrtPrice = (MAX_SQRT_PRICE - 1n) as SqrtPrice + const almostMinSqrtPrice = (MIN_SQRT_PRICE + 1n) as SqrtPrice + const maxLiquidity = + 115792089237316195423570985008687907853269984665640564039457584007913129639935n as Liquidity const paramsUpperBound = { sqrtPriceA: MAX_SQRT_PRICE, sqrtPriceB: almostMaxSqrtPrice, @@ -548,9 +571,9 @@ describe('clamm tests', () => { paramsBottomBound.liquidity, paramsBottomBound.roundingUp ) - expect(resultUp).toEqual(269608649375997235557394191156352599353486422139915865816324471n) + expect(resultUp).toEqual(1915744226453965600842067n) expect(resultDown).toEqual( - 75883634844601460750582416171430603974060896681619645705711819135499453546638n + 1157920892373161954235709850086879078532699846656405640394575840079131296n ) }) test('zero liquidity', async () => { @@ -629,8 +652,8 @@ describe('clamm tests', () => { test('overflow', async () => { const sqrtPriceA = toSqrtPrice(1n) - const sqrtPriceB = (2n ** 256n - 1n) as SqrtPrice - const liquidity = (2n ** 256n - 1n) as Liquidity + const sqrtPriceB = MAX_U256 as SqrtPrice + const liquidity = MAX_U256 as Liquidity await expectError( ArithmeticError.CastOverflow, @@ -647,7 +670,7 @@ describe('clamm tests', () => { test('huge liquidity', async () => { const sqrtPriceA = 1_000000000000000000000000n as SqrtPrice const sqrtPriceB = 1_000000000000000001000000n as SqrtPrice - const liquidity = (2n ** 256n - 1n) as Liquidity + const liquidity = MAX_U256 as Liquidity const resultUp = await getDeltaY(clamm, sqrtPriceA, sqrtPriceB, liquidity, true) const resultDown = await getDeltaY(clamm, sqrtPriceA, sqrtPriceB, liquidity, false) @@ -660,21 +683,23 @@ describe('clamm tests', () => { describe('get delta y - domain', () => { let clamm: CLAMMInstance const minLiquidity = 1n as Liquidity - const maxLiquidity = (2n ** 256n - 1n) as Liquidity + const maxLiquidity = MAX_U256 as Liquidity beforeEach(async () => { clamm = await deployCLAMM(sender) }) it('maximize delta sqrt price and liquidity', async () => { + const maxLiquidity = + 14893892252377511760793030683811718275421081100289805046680361113347505n as Liquidity const resultUp = await getDeltaY(clamm, MAX_SQRT_PRICE, MIN_SQRT_PRICE, maxLiquidity, true) const resultDown = await getDeltaY(clamm, MAX_SQRT_PRICE, MIN_SQRT_PRICE, maxLiquidity, false) expect(resultUp).toStrictEqual( - 75884790229800029582010010030152469040784228171629896065450012281800526658806n + 115792089237316195423570985008687907853269984665640564039457584007913125390908n ) expect(resultDown).toStrictEqual( - 75884790229800029582010010030152469040784228171629896065450012281800526658805n + 115792089237316195423570985008687907853269984665640564039457584007913125390907n ) }) @@ -808,12 +833,12 @@ describe('clamm tests', () => { const clamm = await deployCLAMM(sender) const minY = 1n as TokenAmount - const maxY = ((1n << 256n) - 1n) as TokenAmount + const maxY = MAX_U256 as TokenAmount const almostMinSqrtPrice = (MIN_SQRT_PRICE + 1n) as SqrtPrice const almostMaxSqrtPrice = (MAX_SQRT_PRICE - 1n) as SqrtPrice const minSqrtPriceOutsideDomain = 1n as SqrtPrice const minLiquidity = 1n as Liquidity - const maxLiquidity = ((1n << 256n) - 1n) as Liquidity + const maxLiquidity = MAX_U256 as Liquidity const minOverflowTokenY = 115792089237316195423570985008687907853269984665575031n const oneLiquidity = toLiquidity(1n) @@ -834,7 +859,7 @@ describe('clamm tests', () => { params.y, true ) - expect(nextSqrtPrice).toEqual(15258932000000000001n) + expect(nextSqrtPrice).toEqual(MIN_SQRT_PRICE + 1n) } // decreases almostMinSqrtPrice { @@ -851,7 +876,7 @@ describe('clamm tests', () => { params.y, false ) - expect(nextSqrtPrice).toEqual(15258932000000000000n) + expect(nextSqrtPrice).toEqual(MIN_SQRT_PRICE) } } // Max value inside domain @@ -871,7 +896,7 @@ describe('clamm tests', () => { params.y, false ) - expect(nextSqrtPrice).toEqual(65535383934512646999999999998n) + expect(nextSqrtPrice).toEqual(MAX_SQRT_PRICE - 2n) } // increases almostMaxSqrtPrice { @@ -888,7 +913,7 @@ describe('clamm tests', () => { params.y, true ) - expect(nextSqrtPrice).toEqual(65535383934512646999999999999n) + expect(nextSqrtPrice).toEqual(MAX_SQRT_PRICE - 1n) } } // Extension TokenAmount to SqrtPrice decimal overflow @@ -995,7 +1020,7 @@ describe('clamm tests', () => { params.y, true ) - expect(nextSqrtPrice).toEqual(100000000015258932000000000000n) + expect(nextSqrtPrice).toEqual(100000000000000001286261639329n) } // L = 0 { @@ -1030,35 +1055,35 @@ describe('clamm tests', () => { } }) - test('calculate max liquidity per tick - tick spacing 1, max liquidity / 443637', async () => { + test('calculate max liquidity per tick - tick spacing 1, max liquidity / 1095227', async () => { const clamm = await deployCLAMM(sender) const maxLiquidity = await calculateMaxLiquidityPerTick(clamm, 1n) expect(maxLiquidity).toEqual( - 261006384132333857238172165551313140818439365214444611336425014162283870n + 105724282945285493713696781588372006765054171113057442922296093876349952n ) }) - test('calculate max liquidity per tick - tick spacing 2, max liquidity / 221819', async () => { + test('calculate max liquidity per tick - tick spacing 2, max liquidity / 547613', async () => { const clamm = await deployCLAMM(sender) const maxLiquidity = await calculateMaxLiquidityPerTick(clamm, 2n) expect(maxLiquidity).toEqual( - 522013944933757384087725004321957225532959384115087883036803072825077900n + 211448758954437158036005326770343121608270776379743658458542043391798824n ) }) - test('calculate max liquidity per tick - tick spacing 5, max liquidity / 88727', async () => { + test('calculate max liquidity per tick - tick spacing 5, max liquidity / 219045', async () => { const clamm = await deployCLAMM(sender) const maxLiquidity = await calculateMaxLiquidityPerTick(clamm, 5n) expect(maxLiquidity).toEqual( - 1305037804020379314341417888677492847197245310510223089245185614389229091n + 528622380046639710669364673965111770883927890002696085459415115651638383n ) }) - test('calculate max liquidity per tick - tick spacing 100, max liquidity / 4436', async () => { + test('calculate max liquidity per tick - tick spacing 100, max liquidity / 10952', async () => { const clamm = await deployCLAMM(sender) const maxLiquidity = await calculateMaxLiquidityPerTick(clamm, 100n) expect(maxLiquidity).toEqual( - 26102815427708790672581376241814226296949951457538449963809193870133708214n + 10572688936935372116834458090639874712679874421625325423617383492322236088n ) }) @@ -1066,7 +1091,7 @@ describe('clamm tests', () => { const clamm = await deployCLAMM(sender) const zeroLiquidity = 0n as Liquidity const maxFee = (10n ** 12n) as Percentage - const maxAmount = ((1n << 256n) - 1n) as TokenAmount + const maxAmount = MAX_U256 as TokenAmount const minAmount = 1n as TokenAmount const minLiquidity = 1n as Liquidity const minFee = 0n as Percentage @@ -1396,15 +1421,15 @@ describe('clamm tests', () => { const clamm = await deployCLAMM(sender) { const sqrtPrice = await calculateSqrtPrice(clamm, 30n) - expect(sqrtPrice).toEqual(1001501050455000000000000n) + expect(sqrtPrice).toEqual(1001501050455136530035005n) } { const sqrtPrice = await calculateSqrtPrice(clamm, 20n) - expect(sqrtPrice).toEqual(1001000450120000000000000n) + expect(sqrtPrice).toEqual(1001000450120021002520210n) } { const sqrtPrice = await calculateSqrtPrice(clamm, 10n) - expect(sqrtPrice).toEqual(1000500100010000000000000n) + expect(sqrtPrice).toEqual(1000500100010000500010000n) } { const sqrtPrice = await calculateSqrtPrice(clamm, 0n) @@ -1412,42 +1437,50 @@ describe('clamm tests', () => { } { const sqrtPrice = await calculateSqrtPrice(clamm, -10n) - expect(sqrtPrice).toEqual(999500149965000000000000n) + expect(sqrtPrice).toEqual(999500149965006998740209n) } { const params = { args: { tickIndex: -20n } } const sqrtPrice = await calculateSqrtPrice(clamm, -20n) - expect(sqrtPrice).toEqual(999000549780000000000000n) + expect(sqrtPrice).toEqual(999000549780071479985003n) } { const params = { args: { tickIndex: -30n } } const sqrtPrice = await calculateSqrtPrice(clamm, -30n) - expect(sqrtPrice).toEqual(998501199320000000000000n) + expect(sqrtPrice).toEqual(998501199320305883758749n) } { const result = await calculateSqrtPrice(clamm, 20_000n) - expect(result).toBe(2_718145925979000000000000n) + expect(result).toBe(2_718145926825224864037656n) } { const result = await calculateSqrtPrice(clamm, 200_000n) - expect(result).toBe(22015_455979766288000000000000n) + expect(result).toBe(22015_456048552198645701365772n) } { const result = await calculateSqrtPrice(clamm, -20_000n) - expect(result).toBe(367897834491000000000000n) + expect(result).toBe(367897834377123709894002n) } { const result = await calculateSqrtPrice(clamm, -200_000n) - expect(result).toBe(45422634000000000000n) + expect(result).toBe(45422633889328990341n) } { const result = await calculateSqrtPrice(clamm, 221_818n) - expect(result).toBe(65535_383934512647000000000000n) + expect(result).toBe(65535_384161610681941078870693n) } { const result = await calculateSqrtPrice(clamm, -221_818n) - expect(result).toBe(15258932000000000000n) + expect(result).toBe(15258932449895975601n) + } + { + const result = await calculateSqrtPrice(clamm, GLOBAL_MAX_TICK) + expect(result).toBe(MAX_SQRT_PRICE) + } + { + const result = await calculateSqrtPrice(clamm, GLOBAL_MIN_TICK) + expect(result).toBe(MIN_SQRT_PRICE) } }) @@ -1541,7 +1574,6 @@ describe('clamm tests', () => { describe('calculate amount delta - domain', () => { let clamm: CLAMMInstance - let maxLiquidity = MAX_U256 as Liquidity beforeEach(async () => { clamm = await deployCLAMM(sender) @@ -1550,7 +1582,8 @@ describe('clamm tests', () => { test('max x', async () => { const currentTickIndex = GLOBAL_MIN_TICK const currentSqrtPrice = toSqrtPrice(1n) - const liquidityDelta = maxLiquidity + const liquidityDelta = + 14894636928365657818617562894966478347089917844485661564914997061885569n as Liquidity const liquiditySign = true const upperTick = GLOBAL_MAX_TICK const lowerTick = GLOBAL_MIN_TICK + 1n @@ -1564,8 +1597,9 @@ describe('clamm tests', () => { upperTick, lowerTick ) + expect(result).toEqual([ - 75880998414682858767056931020720040283888865803509762441587530402105305752645n, + 115792089237316195423570985008687907853269984665640564039457584007913126723661n, 0n, false ]) @@ -1574,7 +1608,8 @@ describe('clamm tests', () => { test('max y', async () => { const currentTickIndex = GLOBAL_MAX_TICK const currentSqrtPrice = toSqrtPrice(1n) - const liquidityDelta = maxLiquidity + const liquidityDelta = + 14894636928373696130999721733782910261271218958219522272590008580045463n as Liquidity const liquiditySign = true const upperTick = GLOBAL_MAX_TICK - 1n const lowerTick = GLOBAL_MIN_TICK @@ -1590,7 +1625,7 @@ describe('clamm tests', () => { ) expect(result).toEqual([ 0n, - 75880996274614937472454279923345931777432945506580976077368827511053494714377n, + 115792089237316195423570985008687907853269984665640564039457584007913122202687n, false ]) }) @@ -1738,8 +1773,8 @@ describe('clamm tests', () => { const minLiquidity = 1n as Liquidity const maxX = MAX_U256 as TokenAmount const minX = 1n as TokenAmount - const almostMinSqrtPrice = 15258932000000000001n as SqrtPrice - const almostMaxSqrtPrice = 65535383934512646999999999999n as SqrtPrice + const almostMinSqrtPrice = (MIN_SQRT_PRICE + 1n) as SqrtPrice + const almostMaxSqrtPrice = (MAX_SQRT_PRICE - 1n) as SqrtPrice beforeEach(async () => { clamm = await deployCLAMM(sender) @@ -1760,14 +1795,14 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(15258932000000000001n) + expect(result).toEqual(MIN_SQRT_PRICE + 1n) }) test('min value inside domain / decreases almost min sqrt price', async () => { const params = { startingSqrtPrice: almostMinSqrtPrice, liquidity: maxLiquidity, - x: ((2n ** 128n - 1n) * 2n ** 64n) as TokenAmount, + x: ((2n ** 128n - 1n) * 2n ** 111n) as TokenAmount, addX: true } const result = await getNextSqrtPriceXUp( @@ -1777,14 +1812,14 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(15258932000000000000n) + expect(result).toEqual(MIN_SQRT_PRICE) }) test('max value inside domain / decreases max sqrt price', async () => { const params = { startingSqrtPrice: MAX_SQRT_PRICE, liquidity: maxLiquidity, - x: (2n ** 128n - 1n) as TokenAmount, + x: (2n ** 81n) as TokenAmount, addX: true } const result = await getNextSqrtPriceXUp( @@ -1794,14 +1829,14 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(65535383934512646999999999999n) + expect(result).toEqual(almostMaxSqrtPrice) }) test('max value inside domain / increases almost max sqrt price', async () => { const params = { startingSqrtPrice: almostMaxSqrtPrice, liquidity: maxLiquidity, - x: (2n ** 128n - 1n) as TokenAmount, + x: (2n ** 64n - 1n) as TokenAmount, addX: false } const result = await getNextSqrtPriceXUp( @@ -1811,7 +1846,7 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(65535383934512647000000000001n) + expect(result).toEqual(MAX_SQRT_PRICE) }) test('all max', async () => { @@ -1828,7 +1863,7 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(9999999998474106750n) + expect(result).toEqual(9999999999999999872n) }) test('subtraction underflow', async () => { @@ -1864,7 +1899,7 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(65535383934512647000000000000n) + expect(result).toEqual(MAX_SQRT_PRICE) }) test('liquidity is zero', async () => { @@ -1898,7 +1933,7 @@ describe('clamm tests', () => { params.x, params.addX ) - expect(result).toEqual(65535383934512647000000000000n) + expect(result).toEqual(MAX_SQRT_PRICE) }) }) @@ -1928,14 +1963,14 @@ describe('clamm tests', () => { params.amount, params.xToY ) - expect(result).toEqual(65535383934512647000000000001n) + expect(result).toEqual(MAX_SQRT_PRICE + 1n) }) test('min result, decrease sqrt_price case', async () => { const params = { startingSqrtPrice: almostMinSqrtPrice, liquidity: maxLiquidity, - amount: ((2n ** 128n - 1n) * 10n ** 20n) as TokenAmount, + amount: ((2n ** 128n - 1n) * 2n ** 111n) as TokenAmount, xToY: true } const result = await getNextSqrtPriceFromInput( @@ -1945,7 +1980,7 @@ describe('clamm tests', () => { params.amount, params.xToY ) - expect(result).toEqual(15258931999999999995n) + expect(result).toEqual(MIN_SQRT_PRICE) }) test('amount = 0', async () => { @@ -2030,7 +2065,7 @@ describe('clamm tests', () => { params.amount, params.xToY ) - expect(result).toEqual(65535383934512647000000000000n) + expect(result).toEqual(MAX_SQRT_PRICE) }) test('min result, decrease sqrt_price case', async () => { @@ -2047,7 +2082,7 @@ describe('clamm tests', () => { params.amount, params.xToY ) - expect(result).toEqual(15258932000000000000n) + expect(result).toEqual(MIN_SQRT_PRICE) }) test('amount = 0', async () => { @@ -2570,7 +2605,8 @@ describe('clamm tests', () => { const params = { currentSqrtPrice: MAX_SQRT_PRICE, targetSqrtPrice: MIN_SQRT_PRICE, - liquidity: maxLiquidity, + liquidity: + 14893892252372018684584396344694974244327977275368655982357119807809415n as Liquidity, amount: maxAmountNotReachedTargetSqrtPrice, byAmountIn: true, fee: minFee @@ -2585,9 +2621,9 @@ describe('clamm tests', () => { params.fee ) expect(result).toEqual({ - nextSqrtPrice: 15258932000000000000n, - amountIn: 75884792730156830614567103553061795263351065677581979504561495713443442818879n, - amountOut: 75884790229800029582010010030152469040784228171629896065450012281800526658805n, + nextSqrtPrice: MIN_SQRT_PRICE, + amountIn: 115792089237316195423570985008687907853269984665640564039457584007913127186298n, + amountOut: 115792089237273489678171488614551827950927273765573549347385441617238758671171n, feeAmount: 0n }) }) @@ -2596,7 +2632,8 @@ describe('clamm tests', () => { const params = { currentSqrtPrice: MIN_SQRT_PRICE, targetSqrtPrice: MAX_SQRT_PRICE, - liquidity: maxLiquidity, + liquidity: + 14893892252372018684584411238587226621839738068399339794075395228890515n as Liquidity, amount: maxAmountNotReachedTargetSqrtPrice, byAmountIn: true, fee: minFee @@ -2610,10 +2647,11 @@ describe('clamm tests', () => { params.byAmountIn, params.fee ) + expect(result).toEqual({ - nextSqrtPrice: 65535_383934512647000000000000n, - amountIn: 75884790229800029582010010030152469040784228171629896065450012281800526658806n, - amountOut: 75884792730156830614567103553061795263351065677581979504561495713443442818878n, + nextSqrtPrice: MAX_SQRT_PRICE, + amountIn: 115792089237273489678171604406641065267122697336558558035293294887223422058656n, + amountOut: 115792089237316195423570985008687907853269984665640564039457584007913124933217n, feeAmount: 0n }) }) @@ -2628,6 +2666,7 @@ describe('clamm tests', () => { byAmountIn: true, fee: minFee } + const result = await computeSwapStep( clamm, params.currentSqrtPrice, @@ -2639,8 +2678,8 @@ describe('clamm tests', () => { ) expect(result).toEqual({ nextSqrtPrice: MAX_SQRT_PRICE, - amountIn: 65535n, - amountOut: 65534n, + amountIn: 777439029062n, + amountOut: 777439029062n, feeAmount: 0n }) }) @@ -2665,9 +2704,9 @@ describe('clamm tests', () => { params.fee ) expect(result).toEqual({ - nextSqrtPrice: 65535383934512647000000000000n, + nextSqrtPrice: MAX_SQRT_PRICE, amountIn: 269594397044712364927302271135767871256767389391069984018896158734608n, - amountOut: 62771017353866807635074993554120737773068233085134433767742n, + amountOut: 446035573781064836058621344013922633754231023n, feeAmount: 0n }) }) @@ -2691,16 +2730,16 @@ describe('clamm tests', () => { params.fee ) expect(result).toEqual({ - nextSqrtPrice: 65535383934512647000000000000n, - amountIn: 18446743465900796471n, - amountOut: 18446744073709559494n, + nextSqrtPrice: MAX_SQRT_PRICE, + amountIn: 218833870886803958855620056n, + amountOut: 218833870886884667854278009n, feeAmount: 0n }) }) test('get next sqrt price from output -> get next sqrt price x up / min token change', async () => { const params = { - currentSqrtPrice: (MAX_SQRT_PRICE - 1_000000000000000000000000n) as SqrtPrice, + currentSqrtPrice: 9873007294522358128427212253744918n as SqrtPrice, targetSqrtPrice: MAX_SQRT_PRICE, liquidity: toLiquidity(10000000000n), amount: 1n as TokenAmount, @@ -2717,8 +2756,8 @@ describe('clamm tests', () => { params.fee ) expect(result).toEqual({ - nextSqrtPrice: 65534813412874974599766965330n, - amountIn: 4294783624n, + nextSqrtPrice: MAX_SQRT_PRICE, + amountIn: 7675737962355106071345n, amountOut: 1n, feeAmount: 0n }) @@ -2728,11 +2767,13 @@ describe('clamm tests', () => { const params = { currentSqrtPrice: MAX_SQRT_PRICE, targetSqrtPrice: MIN_SQRT_PRICE, - liquidity: maxLiquidity, + liquidity: + 14893892252372018684584396344694974244327977275368655982357119807809415n as Liquidity, amount: maxAmount, byAmountIn: false, fee: minFee } + const result = await computeSwapStep( clamm, params.currentSqrtPrice, @@ -2743,9 +2784,9 @@ describe('clamm tests', () => { params.fee ) expect(result).toEqual({ - nextSqrtPrice: 15258932000000000000n, - amountIn: 75884792730156830614567103553061795263351065677581979504561495713443442818879n, - amountOut: 75884790229800029582010010030152469040784228171629896065450012281800526658805n, + nextSqrtPrice: MIN_SQRT_PRICE, + amountIn: 115792089237316195423570985008687907853269984665640564039457584007913127186298n, + amountOut: 115792089237273489678171488614551827950927273765573549347385441617238758671171n, feeAmount: 0n }) }) diff --git a/test/contract/unit/log.test.ts b/test/contract/unit/log.test.ts index 54f43da..ff83f98 100644 --- a/test/contract/unit/log.test.ts +++ b/test/contract/unit/log.test.ts @@ -14,9 +14,9 @@ import { import { SqrtPrice } from '../../../src/types' import { toSqrtPrice } from '../../../src/math' -const sqrtPriceToX32 = async (clamm: CLAMMInstance, val: bigint): Promise => { +const sqrtPriceToX64 = async (clamm: CLAMMInstance, val: bigint): Promise => { return ( - await clamm.view.sqrtPriceToX32({ + await clamm.view.sqrtPriceToX64({ args: { val: { v: val } } @@ -24,14 +24,14 @@ const sqrtPriceToX32 = async (clamm: CLAMMInstance, val: bigint): Promise => { return ( - await clamm.view.log2IterativeApproximationX32({ + await clamm.view.log2IterativeApproximationX64({ args: { - sqrtPriceX32 + sqrtPriceX64 } }) ).returns @@ -46,68 +46,68 @@ describe('log tests', () => { clamm = await deployCLAMM(sender) }) - describe('sqrt price to x32', () => { + describe('sqrt price to x64', () => { test('min sqrt price -> sqrt(1.0001) ^ MIN_TICK', async () => { - const minSqrtPriceDecimal = await calculateSqrtPrice(clamm, -221818n) - const result = await sqrtPriceToX32(clamm, minSqrtPriceDecimal) - expect(result).toBe(65536n) + const minSqrtPriceDecimal = await calculateSqrtPrice(clamm, GLOBAL_MIN_TICK) + const result = await sqrtPriceToX64(clamm, minSqrtPriceDecimal) + expect(result).toBe(23727339n) }) test('max sqrt price -> sqrt(1.0001) ^ MAX_TICK', async () => { - const maxSqrtPriceDecimal = await calculateSqrtPrice(clamm, 221818n) - const result = await sqrtPriceToX32(clamm, maxSqrtPriceDecimal) - expect(result).toBe(281472330729535n) + const maxSqrtPriceDecimal = await calculateSqrtPrice(clamm, GLOBAL_MAX_TICK) + const result = await sqrtPriceToX64(clamm, maxSqrtPriceDecimal) + expect(result).toBe(14341362215642069715256648712895n) }) }) - describe('log2 iterative approximation x32', () => { + describe('log2 iterative approximation x64', () => { test('log2 of 1', async () => { const sqrtPriceDecimal = 1_000000000000000000000000n - const sqrtPriceX32 = await sqrtPriceToX32(clamm, sqrtPriceDecimal) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, sqrtPriceDecimal) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) expect(result).toStrictEqual([true, 0n]) }) test('log2 > 0 when x > 1', async () => { const sqrtPriceDecimal = 879_000000000000000000000000n - const sqrtPriceX32 = await sqrtPriceToX32(clamm, sqrtPriceDecimal) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) - expect(result).toStrictEqual([true, 42003464192n]) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, sqrtPriceDecimal) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) + expect(result).toStrictEqual([true, 180403980057034096640n]) }) test('log2 < 0 when x < 1', async () => { const sqrtPriceDecimal = 5900000000000000000000n - const sqrtPriceX32 = await sqrtPriceToX32(clamm, sqrtPriceDecimal) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) - expect(result).toStrictEqual([false, 31804489728n]) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, sqrtPriceDecimal) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) + expect(result).toStrictEqual([false, 136599418782046486528n]) }) test('log2 of max sqrt price', async () => { - const maxSqrtPrice = await calculateSqrtPrice(clamm, 221818n) - const sqrtPriceX32 = await sqrtPriceToX32(clamm, maxSqrtPrice) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) - expect(result).toStrictEqual([true, 68719345664n]) + const maxSqrtPrice = await calculateSqrtPrice(clamm, GLOBAL_MAX_TICK) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, maxSqrtPrice) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) + expect(result).toStrictEqual([true, 728645524035954540544n]) }) test('log2 of min sqrt price', async () => { - const maxSqrtPrice = await calculateSqrtPrice(clamm, -221818n) - const sqrtPriceX32 = await sqrtPriceToX32(clamm, maxSqrtPrice) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) - expect(result).toStrictEqual([false, 68719345664n]) + const maxSqrtPrice = await calculateSqrtPrice(clamm, GLOBAL_MIN_TICK) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, maxSqrtPrice) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) + expect(result).toStrictEqual([false, 728645523220022951936n]) }) test('log2 of sqrt(1.0001 ^ (-19_999)) - 1', async () => { let sqrtPriceDecimal = ((await calculateSqrtPrice(clamm, -19999n)) - 1n) as SqrtPrice - const sqrtPriceX32 = await sqrtPriceToX32(clamm, sqrtPriceDecimal) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) - expect(result).toStrictEqual([false, 6195642368n]) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, sqrtPriceDecimal) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) + expect(result).toStrictEqual([false, 26610365048300503040n]) }) test('log2 of sqrt(1.0001 ^ (-19_999)) + 1', async () => { let sqrtPriceDecimal = ((await calculateSqrtPrice(clamm, 19999n)) - 1n) as SqrtPrice - const sqrtPriceX32 = await sqrtPriceToX32(clamm, sqrtPriceDecimal) - const result = await log2IterativeApproximationX32(clamm, sqrtPriceX32) - expect(result).toStrictEqual([true, 6195642368n]) + const sqrtPriceX64 = await sqrtPriceToX64(clamm, sqrtPriceDecimal) + const result = await log2IterativeApproximationX64(clamm, sqrtPriceX64) + expect(result).toStrictEqual([true, 26610365048300503040n]) }) }) @@ -169,47 +169,47 @@ describe('log tests', () => { test('around max - 1 tick / get tick at sqrt(1.0001 ^ (MAX_TICK - 1))', async () => { const sqrtPriceDecimal = await calculateSqrtPrice(clamm, GLOBAL_MAX_TICK - 1n) const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(221818n - 1n) + expect(result).toBe(GLOBAL_MAX_TICK - 1n) }) test('around max - 1 tick / get tick slightly below sqrt(1.0001 ^ (MAX_TICK - 1))', async () => { let sqrtPriceDecimal = ((await calculateSqrtPrice(clamm, GLOBAL_MAX_TICK - 1n)) - 1n) as SqrtPrice const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(221818n - 2n) + expect(result).toBe(GLOBAL_MAX_TICK - 2n) }) test('around max - 1 tick / get tick slightly above sqrt(1.0001 ^ (MAX_TICK - 1))', async () => { let sqrtPriceDecimal = ((await calculateSqrtPrice(clamm, GLOBAL_MAX_TICK - 1n)) + 1n) as SqrtPrice const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(221818n - 1n) + expect(result).toBe(GLOBAL_MAX_TICK - 1n) }) test('around min + 1 tick / get tick at sqrt(1.0001 ^ (MAX_TICK - 1))', async () => { const sqrtPriceDecimal = await calculateSqrtPrice(clamm, GLOBAL_MIN_TICK + 1n) const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(-(221818n - 1n)) + expect(result).toBe(GLOBAL_MIN_TICK + 1n) }) test('around min + 1 tick / get tick slightly below sqrt(1.0001 ^ (MAX_TICK - 1))', async () => { let sqrtPriceDecimal = ((await calculateSqrtPrice(clamm, GLOBAL_MIN_TICK + 1n)) - 1n) as SqrtPrice const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(-221818n) + expect(result).toBe(GLOBAL_MIN_TICK) }) test('around min + 1 tick / get tick slightly above sqrt(1.0001 ^ (MAX_TICK - 1))', async () => { let sqrtPriceDecimal = ((await calculateSqrtPrice(clamm, GLOBAL_MIN_TICK + 1n)) + 1n) as SqrtPrice const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(-(221818n - 1n)) + expect(result).toBe(GLOBAL_MIN_TICK + 1n) }) test('get tick slightly below at max tick', async () => { const sqrtPriceDecimal = (MAX_SQRT_PRICE - 1n) as SqrtPrice const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(221818n - 1n) + expect(result).toBe(GLOBAL_MAX_TICK - 1n) }) test('around 19999 tick / get tick at sqrt(1.0001 ^ 19999)', async () => { @@ -268,7 +268,7 @@ describe('log tests', () => { test('get tick slightly above at min tick', async () => { const sqrtPriceDecimal = (MIN_SQRT_PRICE + 1n) as SqrtPrice const result = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) - expect(result).toBe(-221818n) + expect(result).toBe(GLOBAL_MIN_TICK) }) }) @@ -366,7 +366,15 @@ describe('log tests', () => { describe('all ticks', () => { test.skip('all positive ticks', async () => { + const oneProgressPercent = GLOBAL_MAX_TICK / 100n + let lastPercent = 0n + for (let i = 0n; i < GLOBAL_MAX_TICK; i++) { + if (lastPercent < i / oneProgressPercent) { + lastPercent = i / oneProgressPercent + console.log(`[all positive ticks] \n${lastPercent}% completed`) + } + const sqrtPriceDecimal = await calculateSqrtPrice(clamm, i) { const tick = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) @@ -381,10 +389,18 @@ describe('log tests', () => { expect(tick).toBe(i) } } - }, 3600000) + }, 36000000) test.skip('all negative ticks', async () => { + const oneProgressPercent = GLOBAL_MAX_TICK / 100n + let lastPercent = 0n + for (let i = 0n; i < GLOBAL_MAX_TICK; i++) { + if (lastPercent < i / oneProgressPercent) { + lastPercent = i / oneProgressPercent + console.log(`[all negative ticks] \n${lastPercent}% completed`) + } + const sqrtPriceDecimal = await calculateSqrtPrice(clamm, -i) { const tick = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, 1n) @@ -399,11 +415,21 @@ describe('log tests', () => { expect(tick).toBe(-i) } } - }, 3600000) + }, 36000000) test.skip('all positive ticks, tick spacing greater than 1', async () => { + const oneProgressPercent = GLOBAL_MAX_TICK / 100n + let lastPercent = 0n + const tickSpacing = 3n for (let i = 0n; i < GLOBAL_MAX_TICK; i++) { + if (lastPercent < i / oneProgressPercent) { + lastPercent = i / oneProgressPercent + console.log( + `[all positive ticks, tick spacing greater than 1] \n${lastPercent}% completed` + ) + } + const sqrtPriceDecimal = await calculateSqrtPrice(clamm, i) { const tick = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, tickSpacing) @@ -435,11 +461,21 @@ describe('log tests', () => { expect(tick).toBe(expectedTick) } } - }, 3600000) + }, 36000000) test.skip('all negative ticks, tick spacing greater than 1', async () => { + const oneProgressPercent = GLOBAL_MAX_TICK / 100n + let lastPercent = 0n + const tickSpacing = 4n for (let i = 0n; i < GLOBAL_MAX_TICK; i++) { + if (lastPercent < i / oneProgressPercent) { + lastPercent = i / oneProgressPercent + console.log( + `[all negative ticks, tick spacing greater than 1] \n${lastPercent}% completed` + ) + } + const sqrtPriceDecimal = await calculateSqrtPrice(clamm, -i) { const tick = await getTickAtSqrtPrice(clamm, sqrtPriceDecimal, tickSpacing) @@ -471,6 +507,6 @@ describe('log tests', () => { expect(tick).toBe(expectedTick) } } - }, 3600000) + }, 36000000) }) }) diff --git a/test/contract/unit/tickmap.test.ts b/test/contract/unit/tickmap.test.ts index 84e3061..1ae0a55 100644 --- a/test/contract/unit/tickmap.test.ts +++ b/test/contract/unit/tickmap.test.ts @@ -3,7 +3,7 @@ import { getSigner } from '@alephium/web3-test' import { PrivateKeyWallet } from '@alephium/web3-wallet' import { InvariantInstance } from '../../../artifacts/ts' import { deployTokenFaucet, newFeeTier, newPoolKey } from '../../../src/utils' -import { GLOBAL_MIN_TICK, GLOBAL_MAX_TICK } from '../../../src/consts' +import { GLOBAL_MIN_TICK, GLOBAL_MAX_TICK, SEARCH_RANGE } from '../../../src/consts' import { Percentage, PoolKey, TokenAmount, wrapPoolKey } from '../../../src/types' import { deployInvariant } from '../../../src/testUtils' @@ -88,7 +88,6 @@ const nextInitialized = async ( ).returns } -const TICK_SEARCH_RANGE = 256n const protocolFee = 100n as Percentage describe('tickmap tests', () => { beforeAll(async () => { @@ -207,12 +206,7 @@ describe('tickmap tests', () => { await flip(invariant, true, tick, poolKey) - const [isSome, index] = await nextInitialized( - invariant, - -TICK_SEARCH_RANGE, - tickSpacing, - poolKey - ) + const [isSome, index] = await nextInitialized(invariant, -SEARCH_RANGE, tickSpacing, poolKey) expect(isSome).toBeTruthy() expect(index).toBe(tick) }) @@ -229,7 +223,7 @@ describe('tickmap tests', () => { await flip(invariant, true, tick, poolKey) - const [isSome] = await nextInitialized(invariant, -TICK_SEARCH_RANGE - 1n, tickSpacing, poolKey) + const [isSome] = await nextInitialized(invariant, -SEARCH_RANGE - 1n, tickSpacing, poolKey) expect(isSome).toBeFalsy() }) test('next initialized chunk - farther than limit', async () => { @@ -250,7 +244,7 @@ describe('tickmap tests', () => { }) test('next initialized chunk - hitting the limit limit', async () => { const invariant = await deployInvariant(sender, protocolFee) - const tick = GLOBAL_MAX_TICK - 22n + const tick = GLOBAL_MAX_TICK - 25n const tickSpacing = 4n const feeTier = newFeeTier(0n as Percentage, tickSpacing) const poolKey = newPoolKey(token0Id, token1Id, feeTier) @@ -385,12 +379,7 @@ describe('tickmap tests', () => { await flip(invariant, true, tick, poolKey) - const [isSome, index] = await prevInitialized( - invariant, - TICK_SEARCH_RANGE, - tickSpacing, - poolKey - ) + const [isSome, index] = await prevInitialized(invariant, SEARCH_RANGE, tickSpacing, poolKey) expect(isSome).toBeTruthy() expect(index).toBe(tick) }) @@ -407,7 +396,7 @@ describe('tickmap tests', () => { await flip(invariant, true, tick, poolKey) - const [isSome] = await prevInitialized(invariant, TICK_SEARCH_RANGE + 1n, tickSpacing, poolKey) + const [isSome] = await prevInitialized(invariant, SEARCH_RANGE + 1n, tickSpacing, poolKey) expect(isSome).toBeFalsy() }) test('prev initialized chunk - further than limit', async () => { @@ -479,7 +468,7 @@ describe('tickmap tests', () => { const up = true const result = (await invariant.view.getSearchLimit({ args: { tick, tickSpacing, up } })) .returns - expect(result).toBe(TICK_SEARCH_RANGE) + expect(result).toBe(SEARCH_RANGE) } { const tick = 0n @@ -487,7 +476,7 @@ describe('tickmap tests', () => { const up = false const result = (await invariant.view.getSearchLimit({ args: { tick, tickSpacing, up } })) .returns - expect(result).toBe(-TICK_SEARCH_RANGE) + expect(result).toBe(-SEARCH_RANGE) } { const tick = 60n @@ -495,7 +484,7 @@ describe('tickmap tests', () => { const up = true const result = (await invariant.view.getSearchLimit({ args: { tick, tickSpacing, up } })) .returns - const expected = tick + TICK_SEARCH_RANGE * tickSpacing + const expected = tick + SEARCH_RANGE * tickSpacing expect(result).toBe(expected) } { @@ -504,7 +493,7 @@ describe('tickmap tests', () => { const up = false const result = (await invariant.view.getSearchLimit({ args: { tick, tickSpacing, up } })) .returns - const expected = tick - TICK_SEARCH_RANGE * tickSpacing + const expected = tick - SEARCH_RANGE * tickSpacing expect(result).toBe(expected) } { @@ -522,7 +511,7 @@ describe('tickmap tests', () => { const up = true const result = (await invariant.view.getSearchLimit({ args: { tick, tickSpacing, up } })) .returns - const expected = tick + const expected = GLOBAL_MAX_TICK - 3n expect(result).toBe(expected) } }) @@ -550,7 +539,7 @@ describe('tickmap tests', () => { await flip(invariant, true, minIndex, poolKey) } - const tickEdgeDiff = (TICK_SEARCH_RANGE / tickSpacing) * tickSpacing + const tickEdgeDiff = (SEARCH_RANGE / tickSpacing) * tickSpacing { const [isSome] = await nextInitialized( invariant, @@ -578,7 +567,7 @@ describe('tickmap tests', () => { const maxIndex = GLOBAL_MAX_TICK - (GLOBAL_MAX_TICK % tickSpacing) const minIndex = -maxIndex - const tickEdgeDiff = (TICK_SEARCH_RANGE / tickSpacing) * tickSpacing + const tickEdgeDiff = (SEARCH_RANGE / tickSpacing) * tickSpacing { const [isSome] = await nextInitialized( invariant, diff --git a/test/sdk/e2e/get-tickmap.test.ts b/test/sdk/e2e/get-tickmap.test.ts index 6011e4b..4c03695 100644 --- a/test/sdk/e2e/get-tickmap.test.ts +++ b/test/sdk/e2e/get-tickmap.test.ts @@ -22,19 +22,26 @@ let feeTier: FeeTier let poolKey: PoolKey describe('query tickmap tests', () => { - const initialFee = 0n as Percentage + const protocolFee = 0n as Percentage const [fee] = getBasicFeeTickSpacing() const tickSpacing = 1n const initSqrtPrice = toSqrtPrice(1n) const supply = (10n ** 10n) as TokenAmount const lowerTickIndex = GLOBAL_MIN_TICK const upperTickIndex = GLOBAL_MAX_TICK - const ticks = [-221818n, -221817n, -58n, 5n, 221817n, 221818n] + const ticks = [ + GLOBAL_MIN_TICK, + GLOBAL_MIN_TICK + 1n, + 35n, + 98n, + GLOBAL_MAX_TICK - 1n, + GLOBAL_MAX_TICK + ] beforeEach(async () => { deployer = await getSigner(ONE_ALPH * 1000n, 0) positionOwner = await getSigner(ONE_ALPH * 1000n, 0) - invariant = await Invariant.deploy(deployer, initialFee) + invariant = await Invariant.deploy(deployer, protocolFee) ;[tokenX, tokenY] = await initTokensXY(deployer, supply) feeTier = newFeeTier(fee, tickSpacing) @@ -119,7 +126,7 @@ describe('query tickmap tests', () => { const tickmap = await invariant.getFullTickmap(poolKey) for (const [chunkIndex, value] of tickmap.entries()) { - if (chunkIndex === 866n) { + if (chunkIndex === 2139n) { expect(value).toBe(0x80000000000000010000000000000000n) } else { expect(value).toBe(0n) @@ -162,7 +169,7 @@ describe('query tickmap tests', () => { const maxChunk = getMaxChunk(tickSpacing) expect(tickmap.get(0n)).toBe(0b11n) expect(tickmap.get(maxChunk)).toBe( - 0x18000000000000000000000000000000000000000000000000000000000000n + 0x600000000000000n ) }) test('get tickmap edge tick initialized on tick spacing equal 100', async () => { @@ -207,6 +214,7 @@ describe('query tickmap tests', () => { const maxChunk = getMaxChunk(tickSpacing) expect(tickmap.get(0n)).toBe(0b11n) - expect(tickmap.get(maxChunk)).toBe(0x1800000000000000000000n) + + expect(tickmap.get(maxChunk)).toBe(0x180000000000000000000000000000000000000000000000000n) }) }) diff --git a/test/sdk/e2e/simulate-invariant-swap.test.ts b/test/sdk/e2e/simulate-invariant-swap.test.ts index 4d866ac..0ef2503 100644 --- a/test/sdk/e2e/simulate-invariant-swap.test.ts +++ b/test/sdk/e2e/simulate-invariant-swap.test.ts @@ -659,7 +659,7 @@ describe('simulateInvariantSwap tests', () => { }) it('max ticks crossed', async function () { const sqrtPriceLimit = getMinSqrtPrice(feeTier.tickSpacing) - const amountIn = 1000000n as TokenAmount + const amountIn = 3000000n as TokenAmount const byAmountIn = true const xToY = true @@ -672,7 +672,7 @@ describe('simulateInvariantSwap tests', () => { const indexes: bigint[] = [] - for (let i = -12n; i < 5; i += 1n) { + for (let i = -40n; i < 5; i += 1n) { indexes.push(i + 1n) await invariant.createPosition( deployer, diff --git a/test/sdk/unit/math-port.test.ts b/test/sdk/unit/math-port.test.ts index c390b6f..8a59946 100644 --- a/test/sdk/unit/math-port.test.ts +++ b/test/sdk/unit/math-port.test.ts @@ -105,7 +105,8 @@ describe('math spec - port', () => { test('max x', async () => { const currentTickIndex = GLOBAL_MIN_TICK const currentSqrtPrice = toSqrtPrice(1n) - const liquidityDelta = maxLiquidity + const liquidityDelta = + 14894636928365657818617562894966478347089917844485661564914997061885569n as Liquidity const liquiditySign = true const upperTick = GLOBAL_MAX_TICK const lowerTick = GLOBAL_MIN_TICK + 1n @@ -119,7 +120,7 @@ describe('math spec - port', () => { lowerTick ) expect(result).toEqual([ - 75880998414682858767056931020720040283888865803509762441587530402105305752645n, + 115792089237316195423570985008687907853269984665640564039457584007913126723661n, 0n, false ]) @@ -128,7 +129,8 @@ describe('math spec - port', () => { test('max y', async () => { const currentTickIndex = GLOBAL_MAX_TICK const currentSqrtPrice = toSqrtPrice(1n) - const liquidityDelta = maxLiquidity + const liquidityDelta = + 14894636928373696130999721733782910261271218958219522272590008580045463n as Liquidity const liquiditySign = true const upperTick = GLOBAL_MAX_TICK - 1n const lowerTick = GLOBAL_MIN_TICK @@ -143,7 +145,7 @@ describe('math spec - port', () => { ) expect(result).toEqual([ 0n, - 75880996274614937472454279923345931777432945506580976077368827511053494714377n, + 115792089237316195423570985008687907853269984665640564039457584007913122202687n, false ]) }) @@ -248,7 +250,7 @@ describe('math spec - port', () => { test('shouldnt overflow in intermediate operations', async () => { const sqrtPriceA = toSqrtPrice(1n) const sqrtPriceB = toSqrtPrice(5n, 1n) - const liquidity = ((1n << 256n) - 1n) as Liquidity + const liquidity = MAX_U256 as Liquidity getDeltaX(sqrtPriceA, sqrtPriceB, liquidity, true) getDeltaX(sqrtPriceA, sqrtPriceB, liquidity, false) }) @@ -261,11 +263,14 @@ describe('math spec - port', () => { }) }) describe('get delta x - domain', () => { - const almostMinSqrtPrice = 15259695000000000000n as SqrtPrice - const maxLiquidity = ((1n << 256n) - 1n) as Liquidity + const almostMinSqrtPrice = (MIN_SQRT_PRICE + 1n) as SqrtPrice + const maxLiquidity = MAX_U256 as Liquidity const minLiquidity = 1n as Liquidity test('maximalize delta sqrt price and liquidity', async () => { + const maxLiquidity = + 14893892252372018684584396344694974244327977275368655982357119807809415n as Liquidity + const params = { sqrtPriceA: MAX_SQRT_PRICE, sqrtPriceB: MIN_SQRT_PRICE, @@ -274,10 +279,10 @@ describe('math spec - port', () => { const resultUp = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, true) const resultDown = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, false) expect(resultUp).toEqual( - 75884792730156830614567103553061795263351065677581979504561495713443442818879n + 115792089237316195423570985008687907853269984665640564039457584007913127186298n ) expect(resultDown).toEqual( - 75884792730156830614567103553061795263351065677581979504561495713443442818878n + 115792089237316195423570869216598670494368815695259202827259764340774619665833n ) }) test('maximalize delta sqrt price and minimalize liquidity', async () => { @@ -288,8 +293,8 @@ describe('math spec - port', () => { } const resultUp = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, true) const resultDown = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, false) - expect(resultUp).toEqual(1n) - expect(resultDown).toEqual(0n) + expect(resultUp).toEqual(7774469n) + expect(resultDown).toEqual(7774468n) }) test('minimize denominator on maximize liquidity which fit into token amounts', async () => { const params = { @@ -300,16 +305,16 @@ describe('math spec - port', () => { const resultUp = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, true) const resultDown = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, false) expect(resultUp).toEqual( - 3794315473971847510172532341754979462199874072217062973965311338137066234n + 1157920892373161954235709850086879078532699846656405640394575840079131296n ) expect(resultDown).toEqual( - 3794315473971847510172532341754979462199874072217062973965311338137066233n + 578960446186580977117854925043439539266349923328202820197287920039565648n ) }) test('minimize denominator on minimize liquidity which fit into token amounts', async () => { const params = { sqrtPriceA: MIN_SQRT_PRICE, - sqrtPriceB: almostMinSqrtPrice, + sqrtPriceB: (almostMinSqrtPrice + 99999n) as SqrtPrice, liquidity: minLiquidity } const resultUp = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, true) @@ -320,7 +325,7 @@ describe('math spec - port', () => { test('delta price limited by search range on max liquidity', async () => { const searchLimit = 256n const tickSpacing = 100n - const maxSearchLimit = 221818n - searchLimit * tickSpacing + const maxSearchLimit = GLOBAL_MAX_TICK - searchLimit * tickSpacing const minSearchSqrtPrice = calculateSqrtPrice(maxSearchLimit) const params = { @@ -329,13 +334,11 @@ describe('math spec - port', () => { liquidity: maxLiquidity } const resultUp = getDeltaX(params.sqrtPriceA, params.sqrtPriceB, params.liquidity, true) - expect(resultUp).toEqual( - 45875017378130362421757891862614875858481775310156442203847653871247n - ) + expect(resultUp).toEqual(3867064427937095529780795325095328040602638051663673509970074n) }) test('minimal price difference', async () => { - const almostMaxSqrtPrice = (MAX_SQRT_PRICE - toSqrtPrice(1n)) as SqrtPrice - const almostMinSqrtPrice = (MIN_SQRT_PRICE + toSqrtPrice(1n)) as SqrtPrice + const almostMaxSqrtPrice = (MAX_SQRT_PRICE - 1n) as SqrtPrice + const almostMinSqrtPrice = (MIN_SQRT_PRICE + 1n) as SqrtPrice const paramsUpperBound = { sqrtPriceA: MAX_SQRT_PRICE, sqrtPriceB: almostMaxSqrtPrice, @@ -360,9 +363,9 @@ describe('math spec - port', () => { paramsBottomBound.liquidity, paramsBottomBound.roundingUp ) - expect(resultUp).toEqual(269608649375997235557394191156352599353486422139915865816324471n) + expect(resultUp).toEqual(1915744226453965600842067n) expect(resultDown).toEqual( - 75883634844601460750582416171430603974060896681619645705711819135499453546638n + 1157920892373161954235709850086879078532699846656405640394575840079131296n ) }) test('zero liquidity', async () => { @@ -463,14 +466,16 @@ describe('math spec - port', () => { const maxLiquidity = (2n ** 256n - 1n) as Liquidity it('maximize delta sqrt price and liquidity', async () => { + const maxLiquidity = + 14893892252377511760793030683811718275421081100289805046680361113347505n as Liquidity const resultUp = getDeltaY(MAX_SQRT_PRICE, MIN_SQRT_PRICE, maxLiquidity, true) const resultDown = getDeltaY(MAX_SQRT_PRICE, MIN_SQRT_PRICE, maxLiquidity, false) expect(resultUp).toStrictEqual( - 75884790229800029582010010030152469040784228171629896065450012281800526658806n + 115792089237316195423570985008687907853269984665640564039457584007913125390908n ) expect(resultDown).toStrictEqual( - 75884790229800029582010010030152469040784228171629896065450012281800526658805n + 115792089237316195423570985008687907853269984665640564039457584007913125390907n ) }) diff --git a/test/sdk/unit/math.test.ts b/test/sdk/unit/math.test.ts index f7bb5f8..75d163b 100644 --- a/test/sdk/unit/math.test.ts +++ b/test/sdk/unit/math.test.ts @@ -50,7 +50,7 @@ describe('math spec', () => { } // In current tick { - const expectedL = 43239299731929n + const expectedL = 43239299699070n const expectedYUp = 434322n const expectedYDown = 434321n const lowerTick = 80n @@ -64,7 +64,7 @@ describe('math spec', () => { { const lowerTick = 150n const upperTick = 800n - const expectedResult = { l: 1354882631162n, amount: 0n } + const expectedResult = { l: 1354882630774n, amount: 0n } const resultUp = getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) const resultDown = getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) @@ -77,7 +77,7 @@ describe('math spec', () => { const currentSqrtPrice = calculateSqrtPrice(-20000n) // Below current tick { - const expectedL = 278905227910392327n + const expectedL = 278905227913027805n const expectedX = 0n const lowerTick = -22000n const upperTick = -21000n @@ -91,9 +91,9 @@ describe('math spec', () => { } // In current tick { - const expectedL = 58494529055434693n - const expectedXUp = 77539808126n - const expectedXDown = 77539808125n + const expectedL = 58494529057380141n + const expectedXUp = 77539808174n + const expectedXDown = 77539808173n const lowerTick = -25000n const upperTick = -19000n @@ -121,7 +121,7 @@ describe('math spec', () => { const currentSqrtPrice = calculateSqrtPrice(-20000n) // Below current tick { - const expectedL = 278905227910392327n + const expectedL = 278905227913027805n const expectedX = 0n as TokenAmount const lowerTick = -22000n const upperTick = -21000n @@ -135,10 +135,10 @@ describe('math spec', () => { } // In current tick { - const expectedXUp = 77539808126n as TokenAmount - const expectedXDown = 77539808125n as TokenAmount - const expectedLUp = 58494529055434693n - const expectedLDown = 58494529055291192n + const expectedXUp = 77539808174n as TokenAmount + const expectedXDown = 77539808173n as TokenAmount + const expectedLUp = 58494529057380141n + const expectedLDown = 58494529057221346n const lowerTick = -25000n const upperTick = -19000n const expectedResultUp = { l: expectedLUp, x: expectedXUp } @@ -164,7 +164,7 @@ describe('math spec', () => { const x = 430000000n as TokenAmount const expectedY = 0n as TokenAmount - const expectedResult = { l: 1354882631162385n, y: expectedY } + const expectedResult = { l: 1354882630774114n, y: expectedY } const resultUp = getLiquidity(x, expectedY, lowerTick, upperTick, currentSqrtPrice, true) @@ -377,7 +377,7 @@ describe('math spec', () => { const maxConcentration = 10 const expectedResult = 11 - const result = getConcentrationArray(tickSpacing, maxConcentration, 221752) + const result = getConcentrationArray(tickSpacing, maxConcentration, 547548) expect(result.length).toBe(expectedResult) }) @@ -386,7 +386,7 @@ describe('math spec', () => { const maxConcentration = 10 const expectedResult = 124 - const result = getConcentrationArray(tickSpacing, maxConcentration, 221300) + const result = getConcentrationArray(tickSpacing, maxConcentration, 547094) expect(result.length).toBe(expectedResult) }) it('low current tick ', async () => {