diff --git a/contracts/collections/tickmap.ral b/contracts/collections/tickmap.ral index 75f75cd..e924a00 100644 --- a/contracts/collections/tickmap.ral +++ b/contracts/collections/tickmap.ral @@ -267,4 +267,12 @@ Abstract Contract Tickmap() extends Decimal(), BatchHelper() { let (upperChunk, _) = tickToPosition(upperTick, tickSpacing) return lowerChunk, upperChunk } + + @using(checkExternalCaller = false) + pub fn getMaxChunk(tickSpacing: U256) -> (U256) { + let maxTick = getMaxTick(tickSpacing) + let maxBitmapIndex = maxTick + GlobalMaxTick / toI256!(tickSpacing) + let maxChunkIndex = toU256!(maxBitmapIndex) / ChunkSize + return maxChunkIndex + } } \ No newline at end of file diff --git a/contracts/math/decimal.ral b/contracts/math/decimal.ral index 41d327e..8d55c2e 100644 --- a/contracts/math/decimal.ral +++ b/contracts/math/decimal.ral @@ -48,12 +48,14 @@ Abstract Contract Decimal() { return GlobalMinTick } - pub fn getMaxSqrtPrice() -> U256 { - return MaxSqrtPrice + pub fn getMaxSqrtPrice(tickSpacing: U256) -> U256 { + let maxTick = getMaxTick(tickSpacing) + return calculateSqrtPrice(maxTick) } - pub fn getMinSqrtPrice() -> U256 { - return MinSqrtPrice + pub fn getMinSqrtPrice(tickSpacing: U256) -> U256 { + let minTick = getMinTick(tickSpacing) + return calculateSqrtPrice(minTick) } pub fn getMaxTick(tickSpacing: U256) -> I256 { @@ -208,7 +210,7 @@ Abstract Contract Decimal() { } else { return a - b } - } + } pub fn calculateFeeGrowthInside( tickLowerIndex: I256, diff --git a/contracts/math/utils.ral b/contracts/math/utils.ral index 985bf69..d0c6e48 100644 --- a/contracts/math/utils.ral +++ b/contracts/math/utils.ral @@ -9,7 +9,11 @@ struct LiquidityResult { l: U256 } -Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelper() { +Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelper(), Tickmap() { + // Placeholder to allow exporting tickmap methods + // Key: poolKey ++ subcontract index + mapping[ByteVec, TickmapBatch] bitmap + enum UtilsError { InvalidTickIndex = 900 UpperLTCurrentSqrtPrice = 901 @@ -17,9 +21,35 @@ Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelp } enum InvariantError { + // NotAdmin = 0 + // InsufficientLiquidity = 1 InvalidTickSpacing = 2 InvalidFee = 3 + // FeeTierNotFound = 4 TokensAreSame = 5 + // PoolKeyAlreadyExist = 6 + // TickAndSqrtPriceMismatch = 7 + // NotFeeReceiver = 8 + // InvalidTickLiquidity = 9 + // ZeroLiquidity = 10 + // PriceLimitReached = 11 + // InvalidProtocolFee = 12 + // NotOwner = 13 + // ZeroAmount = 14 + // WrongPriceLimit = 15 + // NoGainSwap = 16 + // PositionDoesNotExist = 17 + // FeeTierAlreadyExist = 18 + // PoolDoesNotExist = 19 + // PoolAlreadyExist = 20 + // TickAlreadyExist = 21 + InvalidTickIndex = 22 + TickAndTickSpacingMismatch = 23 + TickLimitReached = 24 + ChunkNotFound = 25 + TickInitialized = 26 + // PositionNotFound = 27 + // EmptyPositionPokes = 28 } pub fn getLiquidityByX(x: U256, lowerTick: I256, upperTick: I256, currentSqrtPrice: U256, roundingUp: Bool) -> SingleTokenLiquidity { @@ -124,4 +154,57 @@ Contract Utils() extends Uints(), Decimal(), Log(), PoolKeyHelper(), FeeTierHelp return LiquidityResult { x: resultByY.amount, y: resultByX.amount, l: resultByX.l } } } + + pub fn isTokenX(candidate: Address, compareTo: Address) -> Bool { + let candidateBytes = toByteVec!(candidate) + let compareToBytes = toByteVec!(compareTo) + + assert!(candidateBytes != compareToBytes, InvariantError.TokensAreSame) + + for (let mut i = 0; i <= size!(candidateBytes); i = i + 1) { + if (u256From1Byte!(byteVecSlice!(candidateBytes, i, i + 1)) < u256From1Byte!(byteVecSlice!(compareToBytes, i, i + 1))) { + return true + } else { + return false + } + } + + return true + } + + pub fn calculateFee( + tickLowerIndex: I256, + tickLowerFeeGrowthOutsideX: U256, + tickLowerFeeGrowthOutsideY: U256, + tickUpperIndex: I256, + tickUpperFeeGrowthOutsideX: U256, + tickUpperFeeGrowthOutsideY: U256, + tickCurrent: I256, + globalFeeGrowthX: U256, + globalFeeGrowthY: U256, + positionFeeGrowthInsideX: U256, + positionFeeGrowthInsideY: U256, + positionLiquidity: U256 + ) -> (U256, U256) { + let (feeGrowthInsideX, feeGrowthInsideY) = calculateFeeGrowthInside( + tickLowerIndex, + tickLowerFeeGrowthOutsideX, + tickLowerFeeGrowthOutsideY, + tickUpperIndex, + tickUpperFeeGrowthOutsideX, + tickUpperFeeGrowthOutsideY, + tickCurrent, + globalFeeGrowthX, + globalFeeGrowthY + ) + + let tokensOwedX = toFee(wrappingSub(feeGrowthInsideX, positionFeeGrowthInsideX), positionLiquidity) + let tokensOwedY = toFee(wrappingSub(feeGrowthInsideY, positionFeeGrowthInsideY), positionLiquidity) + + return tokensOwedX, tokensOwedY + } + + pub fn toFee(feeGrowth: U256, liquidity: U256) -> U256 { + return toU256(bigMulDiv256(feeGrowth, liquidity, one(FeeGrowthScale + LiquidityScale))) + } } \ No newline at end of file diff --git a/src/math.ts b/src/math.ts index 6bc476f..7b7e45f 100644 --- a/src/math.ts +++ b/src/math.ts @@ -1,6 +1,7 @@ import { CLAMM, Utils } from '../artifacts/ts' +import { LiquidityResult, Pool, Position, SingleTokenLiquidity, Tick } from '../artifacts/ts/types' -export const calculateSqrtPrice = async (tickIndex: bigint) => { +export const calculateSqrtPrice = async (tickIndex: bigint): Promise => { return ( await Utils.tests.calculateSqrtPrice({ testArgs: { tickIndex } @@ -14,7 +15,7 @@ export const getLiquidityByX = async ( upperTick: bigint, currentSqrtPrice: bigint, roundingUp: boolean -) => { +): Promise => { return ( await Utils.tests.getLiquidityByX({ testArgs: { @@ -34,7 +35,7 @@ export const getLiquidityByY = async ( upperTick: bigint, currentSqrtPrice: bigint, roundingUp: boolean -) => { +): Promise => { return ( await Utils.tests.getLiquidityByY({ testArgs: { @@ -55,7 +56,7 @@ export const getLiquidity = async ( upperTick: bigint, currentSqrtPrice: bigint, roundingUp: boolean -) => { +): Promise => { return ( await Utils.tests.getLiquidity({ testArgs: { @@ -75,7 +76,7 @@ export const getDeltaY = async ( sqrtPriceB: bigint, liquidity: bigint, roundingUp: boolean -) => { +): Promise => { return ( await CLAMM.tests.getDeltaY({ testArgs: { @@ -88,7 +89,7 @@ export const getDeltaY = async ( ).returns } -export const getMaxTick = async (tickSpacing: bigint) => { +export const getMaxTick = async (tickSpacing: bigint): Promise => { return ( await Utils.tests.getMaxTick({ testArgs: { @@ -97,3 +98,109 @@ export const getMaxTick = async (tickSpacing: bigint) => { }) ).returns } + +export const getMinTick = async (tickSpacing: bigint): Promise => { + return ( + await Utils.tests.getMinTick({ + testArgs: { + tickSpacing + } + }) + ).returns +} + +export const getMaxChunk = async (tickSpacing: bigint): Promise => { + return ( + await Utils.tests.getMaxChunk({ + testArgs: { + tickSpacing + } + }) + ).returns +} + +export const calculateTick = async (sqrtPrice: bigint, tickSpacing: bigint): Promise => { + return ( + await Utils.tests.getTickAtSqrtPrice({ + testArgs: { + sqrtPrice, + tickSpacing + } + }) + ).returns +} + +export const getMaxSqrtPrice = async (tickSpacing: bigint): Promise => { + return ( + await Utils.tests.getMaxSqrtPrice({ + testArgs: { + tickSpacing + } + }) + ).returns +} + +export const getMinSqrtPrice = async (tickSpacing: bigint): Promise => { + return ( + await Utils.tests.getMinSqrtPrice({ + testArgs: { + tickSpacing + } + }) + ).returns +} + +export const isTokenX = async (candidate: string, compareTo: string): Promise => { + return ( + await Utils.tests.isTokenX({ + testArgs: { + candidate, + compareTo + } + }) + ).returns +} + +export const calculateFee = async ( + pool: Pool, + position: Position, + lowerTick: Tick, + upperTick: Tick +): Promise<[bigint, bigint]> => { + return ( + await Utils.tests.calculateFee({ + testArgs: { + tickLowerIndex: lowerTick.index, + tickLowerFeeGrowthOutsideX: lowerTick.feeGrowthOutsideX, + tickLowerFeeGrowthOutsideY: lowerTick.feeGrowthOutsideY, + tickUpperIndex: upperTick.index, + tickUpperFeeGrowthOutsideX: upperTick.feeGrowthOutsideX, + tickUpperFeeGrowthOutsideY: upperTick.feeGrowthOutsideY, + tickCurrent: pool.currentTickIndex, + globalFeeGrowthX: pool.feeGrowthGlobalX, + globalFeeGrowthY: pool.feeGrowthGlobalY, + positionFeeGrowthInsideX: position.feeGrowthInsideX, + positionFeeGrowthInsideY: position.feeGrowthInsideY, + positionLiquidity: position.liquidity + } + }) + ).returns +} + +export const calculateTokenAmounts = async ( + pool: Pool, + position: Position +): Promise<[bigint, bigint, boolean]> => { + return ( + await CLAMM.tests.calculateAmountDelta({ + testArgs: { + currentTickIndex: pool.currentTickIndex, + currentSqrtPrice: pool.sqrtPrice, + liquidityDelta: position.liquidity, + liquiditySign: false, + upperTick: position.upperTickIndex, + lowerTick: position.lowerTickIndex + } + }) + ).returns +} diff --git a/test/clamm.test.ts b/test/clamm.test.ts index 400ae6b..5fbe5af 100644 --- a/test/clamm.test.ts +++ b/test/clamm.test.ts @@ -127,6 +127,7 @@ describe('math tests', () => { }) test('fee growth to fee', async () => { const clamm = await deployCLAMM(sender) + // Equal { const amount = 100n diff --git a/test/math.test.ts b/test/math.test.ts index b198d04..3f8a338 100644 --- a/test/math.test.ts +++ b/test/math.test.ts @@ -1,193 +1,261 @@ import { web3 } from '@alephium/web3' -import { calculateSqrtPrice, getLiquidity, getLiquidityByX, getLiquidityByY } from '../src/math' +import { + calculateFee, + calculateSqrtPrice, + getLiquidity, + getLiquidityByX, + getLiquidityByY +} from '../src/math' import { expectError } from '../src/testUtils' import { UtilsError } from '../src/consts' +import { Pool, Position, Tick } from '../artifacts/ts/types' +import { newFeeTier, newPoolKey } from '../src/utils' +import { getBasicFeeTickSpacing } from '../src/snippets' web3.setCurrentNodeProvider('http://127.0.0.1:22973') describe('math spec', () => { - test('Calculating off-chain works', async () => { - const sqrtPrice = await calculateSqrtPrice(0n) - expect(sqrtPrice).toBe(10n ** 24n) - }) - test('get liquidity by x', async () => { - const x = 430000n - const currentSqrtPrice = await calculateSqrtPrice(100n) - - // Bellow current tick - { - const lowerTick = -50n - const upperTick = 10n - await expectError( - UtilsError.UpperLTCurrentSqrtPrice, - getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) - ) - await expectError( - UtilsError.UpperLTCurrentSqrtPrice, - getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) - ) - } - // In current tick - { - const expectedL = 43239299731929n - const expectedYUp = 434322n - const expectedYDown = 434321n - const lowerTick = 80n - const upperTick = 120n - const resultUp = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) - const resultDown = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) - expect(resultUp).toMatchObject({ l: expectedL, amount: expectedYUp }) - expect(resultDown).toMatchObject({ l: expectedL, amount: expectedYDown }) - } - // Above current tick - { - const lowerTick = 150n - const upperTick = 800n - const expectedResult = { l: 1354882631162n, amount: 0n } - - const resultUp = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) - const resultDown = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) - expect(resultUp).toMatchObject(expectedResult) - expect(resultDown).toMatchObject(expectedResult) - } - }) - test('get liquidity by y', async () => { - const y = 47600000000n - const currentSqrtPrice = await calculateSqrtPrice(-20000n) - // Below current tick - { - const expectedL = 278905227910392327n - const expectedX = 0n - const lowerTick = -22000n - const upperTick = -21000n - const expectedResult = { l: expectedL, amount: expectedX } - - const resultUp = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, true) - const resultDown = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, false) - - expect(resultUp).toMatchObject(expectedResult) - expect(resultDown).toMatchObject(expectedResult) - } - // In current tick - { - const expectedL = 58494529055434693n - const expectedXUp = 77539808126n - const expectedXDown = 77539808125n - const lowerTick = -25000n - const upperTick = -19000n - - const resultUp = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, true) - const resultDown = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, false) - - expect(resultUp).toMatchObject({ l: expectedL, amount: expectedXUp }) - expect(resultDown).toMatchObject({ l: expectedL, amount: expectedXDown }) - } - // Above current Tick - { - const lowerTick = -10000n - const upperTick = 0n - - await expectError( - UtilsError.CurrentLTLowerSqrtPrice, - getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, true) - ) - await expectError( - UtilsError.CurrentLTLowerSqrtPrice, - getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, false) - ) - } - }) - test('get liquidity', async () => { - const y = 47600000000n - const currentSqrtPrice = await calculateSqrtPrice(-20000n) - // Below current tick - { - const expectedL = 278905227910392327n - const expectedX = 0n - const lowerTick = -22000n - const upperTick = -21000n - const expectedResult = { l: expectedL, x: expectedX, y } - - const resultUp = await getLiquidity( - expectedX, - y, - lowerTick, - upperTick, - currentSqrtPrice, - true - ) - const resultDown = await getLiquidity( - expectedX, - y, - lowerTick, - upperTick, - currentSqrtPrice, - false - ) + describe('get liquidity by tests', () => { + test('get liquidity by x', async () => { + const x = 430000n + const currentSqrtPrice = await calculateSqrtPrice(100n) - expect(resultUp).toMatchObject(expectedResult) - expect(resultDown).toMatchObject(expectedResult) - } - // In current tick - { - const expectedXUp = 77539808126n - const expectedXDown = 77539808125n - const expectedLUp = 58494529055434693n - const expectedLDown = 58494529055291192n - const lowerTick = -25000n - const upperTick = -19000n - const expectedResultUp = { l: expectedLUp, x: expectedXUp } - const expectedResultDown = { l: expectedLDown, x: expectedXDown } - - const resultUp = await getLiquidity( - expectedXUp, - y, - lowerTick, - upperTick, - currentSqrtPrice, - true - ) - const resultDown = await getLiquidity( - expectedXDown, - y, - lowerTick, - upperTick, - currentSqrtPrice, - false - ) + // Bellow current tick + { + const lowerTick = -50n + const upperTick = 10n + await expectError( + UtilsError.UpperLTCurrentSqrtPrice, + getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) + ) + await expectError( + UtilsError.UpperLTCurrentSqrtPrice, + getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) + ) + } + // In current tick + { + const expectedL = 43239299731929n + const expectedYUp = 434322n + const expectedYDown = 434321n + const lowerTick = 80n + const upperTick = 120n + const resultUp = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) + const resultDown = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) + expect(resultUp).toMatchObject({ l: expectedL, amount: expectedYUp }) + expect(resultDown).toMatchObject({ l: expectedL, amount: expectedYDown }) + } + // Above current tick + { + const lowerTick = 150n + const upperTick = 800n + const expectedResult = { l: 1354882631162n, amount: 0n } - expect(resultUp).toMatchObject(expectedResultUp) - expect(resultDown).toMatchObject(expectedResultDown) - } - // Above current Tick - { - const lowerTick = 150n - const upperTick = 800n - - const x = 430000000n - const expectedY = 0n - const expectedResult = { l: 1354882631162385n, y: expectedY } - - const resultUp = await getLiquidity( - x, - expectedY, - lowerTick, - upperTick, - currentSqrtPrice, - true - ) + const resultUp = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, true) + const resultDown = await getLiquidityByX(x, lowerTick, upperTick, currentSqrtPrice, false) + expect(resultUp).toMatchObject(expectedResult) + expect(resultDown).toMatchObject(expectedResult) + } + }) + test('get liquidity by y', async () => { + const y = 47600000000n + const currentSqrtPrice = await calculateSqrtPrice(-20000n) + // Below current tick + { + const expectedL = 278905227910392327n + const expectedX = 0n + const lowerTick = -22000n + const upperTick = -21000n + const expectedResult = { l: expectedL, amount: expectedX } - const resultDown = await getLiquidity( - x, - expectedY, - lowerTick, - upperTick, - currentSqrtPrice, - false - ) + const resultUp = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, true) + const resultDown = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, false) - expect(resultUp).toMatchObject(expectedResult) - expect(resultDown).toMatchObject(expectedResult) - } + expect(resultUp).toMatchObject(expectedResult) + expect(resultDown).toMatchObject(expectedResult) + } + // In current tick + { + const expectedL = 58494529055434693n + const expectedXUp = 77539808126n + const expectedXDown = 77539808125n + const lowerTick = -25000n + const upperTick = -19000n + + const resultUp = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, true) + const resultDown = await getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, false) + + expect(resultUp).toMatchObject({ l: expectedL, amount: expectedXUp }) + expect(resultDown).toMatchObject({ l: expectedL, amount: expectedXDown }) + } + // Above current Tick + { + const lowerTick = -10000n + const upperTick = 0n + + await expectError( + UtilsError.CurrentLTLowerSqrtPrice, + getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, true) + ) + await expectError( + UtilsError.CurrentLTLowerSqrtPrice, + getLiquidityByY(y, lowerTick, upperTick, currentSqrtPrice, false) + ) + } + }) + test('get liquidity', async () => { + const y = 47600000000n + const currentSqrtPrice = await calculateSqrtPrice(-20000n) + // Below current tick + { + const expectedL = 278905227910392327n + const expectedX = 0n + const lowerTick = -22000n + const upperTick = -21000n + const expectedResult = { l: expectedL, x: expectedX, y } + + const resultUp = await getLiquidity( + expectedX, + y, + lowerTick, + upperTick, + currentSqrtPrice, + true + ) + const resultDown = await getLiquidity( + expectedX, + y, + lowerTick, + upperTick, + currentSqrtPrice, + false + ) + + expect(resultUp).toMatchObject(expectedResult) + expect(resultDown).toMatchObject(expectedResult) + } + // In current tick + { + const expectedXUp = 77539808126n + const expectedXDown = 77539808125n + const expectedLUp = 58494529055434693n + const expectedLDown = 58494529055291192n + const lowerTick = -25000n + const upperTick = -19000n + const expectedResultUp = { l: expectedLUp, x: expectedXUp } + const expectedResultDown = { l: expectedLDown, x: expectedXDown } + + const resultUp = await getLiquidity( + expectedXUp, + y, + lowerTick, + upperTick, + currentSqrtPrice, + true + ) + const resultDown = await getLiquidity( + expectedXDown, + y, + lowerTick, + upperTick, + currentSqrtPrice, + false + ) + + expect(resultUp).toMatchObject(expectedResultUp) + expect(resultDown).toMatchObject(expectedResultDown) + } + // Above current Tick + { + const lowerTick = 150n + const upperTick = 800n + + const x = 430000000n + const expectedY = 0n + const expectedResult = { l: 1354882631162385n, y: expectedY } + + const resultUp = await getLiquidity( + x, + expectedY, + lowerTick, + upperTick, + currentSqrtPrice, + true + ) + + const resultDown = await getLiquidity( + x, + expectedY, + lowerTick, + upperTick, + currentSqrtPrice, + false + ) + + expect(resultUp).toMatchObject(expectedResult) + expect(resultDown).toMatchObject(expectedResult) + } + }) + }) + describe('test calculateFee', () => { + test('Should return correct amounts', async () => { + const [fee, tickSpacing] = await getBasicFeeTickSpacing() + const feeTier = await newFeeTier(fee, tickSpacing) + const poolKey = await newPoolKey( + '55cd8e663fecd454071a2bf9937bf306a58e344694a16009b5d87421b06f7000', + '55cd8e663fecd454071a2bf9937bf306a58e344694a16009b5d87421b06e7000', + feeTier + ) + const pool: Pool = { + poolKey, + liquidity: 10000000000000n, + sqrtPrice: 999505344804856076727628n, + currentTickIndex: -10n, + feeGrowthGlobalX: 49000000000000000000000n, + feeGrowthGlobalY: 0n, + feeProtocolTokenX: 1n, + feeProtocolTokenY: 0n, + startTimestamp: 1720687408546n, + lastTimestamp: 1720687408644n, + feeReceiver: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY', + reserveX: '55cd8e663fecd454071a2bf9937bf306a58e344694a16009b5d87421b06f7000', + reserveY: '55cd8e663fecd454071a2bf9937bf306a58e344694a16009b5d87421b06f7000' + } + const position: Position = { + poolKey, + liquidity: 10000000000000n, + lowerTickIndex: -10n, + upperTickIndex: 10n, + feeGrowthInsideX: 0n, + feeGrowthInsideY: 0n, + lastBlockNumber: 51n, + tokensOwedX: 0n, + tokensOwedY: 0n, + owner: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY' + } + const lowerTick: Tick = { + index: -10n, + sign: true, + liquidityChange: 10000000000000n, + liquidityGross: 10000000000000n, + sqrtPrice: 999500149965000000000000n, + feeGrowthOutsideX: 0n, + feeGrowthOutsideY: 0n, + secondsOutside: 98n + } + const upperTick: Tick = { + index: 10n, + sign: false, + liquidityChange: 10000000000000n, + liquidityGross: 10000000000000n, + sqrtPrice: 1000500100010000000000000n, + feeGrowthOutsideX: 0n, + feeGrowthOutsideY: 0n, + secondsOutside: 0n + } + const [x, y] = await calculateFee(pool, position, lowerTick, upperTick) + expect(x).toBe(490n) + expect(y).toBe(0n) + }) }) })