From ff198e6c2c9ba71f28ef98e4d30b98f5e2988628 Mon Sep 17 00:00:00 2001 From: chasevoorhees Date: Sat, 13 Jul 2024 16:24:50 -0700 Subject: [PATCH] Fix/Osmosis - fix broken tests again, update tick calc to @mlguys --- src/chains/osmosis/osmosis.ts | 6 +-- src/chains/osmosis/osmosis.utils.ts | 55 ++++++++++++++++++++++ test-bronze/chains/osmosis/osmosis.test.ts | 4 +- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/chains/osmosis/osmosis.ts b/src/chains/osmosis/osmosis.ts index 116bbde4f9..8cf624d67a 100755 --- a/src/chains/osmosis/osmosis.ts +++ b/src/chains/osmosis/osmosis.ts @@ -51,7 +51,7 @@ import { Pool as CLPool } from 'osmo-query/dist/codegen/osmosis/concentrated-liq import { TradeInfo } from './osmosis.controllers'; import { HttpException, TRADE_FAILED_ERROR_CODE, TRADE_FAILED_ERROR_MESSAGE, GAS_LIMIT_EXCEEDED_ERROR_MESSAGE, GAS_LIMIT_EXCEEDED_ERROR_CODE, AMOUNT_LESS_THAN_MIN_AMOUNT_ERROR_MESSAGE, AMOUNT_LESS_THAN_MIN_AMOUNT_ERROR_CODE } from '../../services/error-handler'; import { extendPool, filterPoolsSwap, filterPoolsLP, filterPoolsSwapAndLP } from './osmosis.lp.utils'; -import { fetchFees, findTickForPrice, tickToPrice } from './osmosis.utils'; +import { fetchFees, findTickForPrice, tickToPrice, calculatePriceToTick } from './osmosis.utils'; import { getImperatorPriceHash } from './osmosis.prices'; import { GasPrice, calculateFee, setupIbcExtension, SigningStargateClient, AminoTypes } from '@cosmjs/stargate'; import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate"; @@ -1282,8 +1282,8 @@ export class Osmosis extends CosmosBase implements Cosmosish{ singleTokenMinAmount = singleToken_amount.shiftedBy(this.getExponentByBase(singleToken.base)).multipliedBy(100-slippage).dividedBy(100).integerValue(BigNumber.ROUND_CEIL) } - const lowerTick = findTickForPrice(req.lowerPrice!, pool.exponentAtPriceOne, pool.tickSpacing, true) - const upperTick = findTickForPrice(req.upperPrice!, pool.exponentAtPriceOne, pool.tickSpacing, false) + const lowerTick = calculatePriceToTick(req.lowerPrice!, pool.exponentAtPriceOne, pool.tickSpacing, true) // pool.currentTick, + const upperTick = calculatePriceToTick(req.upperPrice!, pool.exponentAtPriceOne, pool.tickSpacing, false) var MsgCreatePosition; if (singleToken.base == pool.token0){ diff --git a/src/chains/osmosis/osmosis.utils.ts b/src/chains/osmosis/osmosis.utils.ts index b54d387d0a..23c1f19790 100755 --- a/src/chains/osmosis/osmosis.utils.ts +++ b/src/chains/osmosis/osmosis.utils.ts @@ -39,6 +39,61 @@ export const fetchRewards = async (address: string): Promise => { .then((res) => res.json()); }; +export function calculatePriceToTick(desiredPriceString: string, exponentAtPriceOne: number, tickSpacing: number, is_lowerBound: boolean): string { + console.log(`Inputs: desiredPriceString=${desiredPriceString}, exponentAtPriceOne=${exponentAtPriceOne}, tickSpacing=${tickSpacing}, is_lowerBound=${is_lowerBound}`); + + const desiredPrice = new BigNumber(desiredPriceString) + const exponent = new BigNumber(exponentAtPriceOne); + const geometricExponentIncrementDistanceInTicks = new BigNumber(9).multipliedBy(new BigNumber(10).exponentiatedBy(exponent.multipliedBy(-1))) + + console.log(`Initial calculations: desiredPrice=${desiredPrice}, exponent=${exponent}, geometricExponentIncrementDistanceInTicks=${geometricExponentIncrementDistanceInTicks}`); + + let currentPrice = new BigNumber(1); + let ticksPassed = new BigNumber(0); + let exponentAtCurrentTick = exponent; + let currentAdditiveIncrementInTicks = new BigNumber(10).exponentiatedBy(exponent) + + if (desiredPrice.gt(new BigNumber(1))) { + while (currentPrice.lt(desiredPrice)) { + currentAdditiveIncrementInTicks = new BigNumber(10).exponentiatedBy(exponentAtCurrentTick); + const maxPriceForCurrentAdditiveIncrementInTicks = geometricExponentIncrementDistanceInTicks.multipliedBy(currentAdditiveIncrementInTicks); + currentPrice = currentPrice.plus(maxPriceForCurrentAdditiveIncrementInTicks); + exponentAtCurrentTick = exponentAtCurrentTick.plus(1); + ticksPassed = ticksPassed.plus(geometricExponentIncrementDistanceInTicks); + + console.log(`Loop (desiredPrice > 1): currentPrice=${currentPrice}, exponentAtCurrentTick=${exponentAtCurrentTick}, ticksPassed=${ticksPassed}`); + } + } else { + exponentAtCurrentTick = exponent.minus(1); + while (currentPrice.gt(desiredPrice)) { + currentAdditiveIncrementInTicks = new BigNumber(10).exponentiatedBy(exponentAtCurrentTick); + const maxPriceForCurrentAdditiveIncrementInTicks = geometricExponentIncrementDistanceInTicks.multipliedBy(currentAdditiveIncrementInTicks); + currentPrice = currentPrice.minus(maxPriceForCurrentAdditiveIncrementInTicks); + exponentAtCurrentTick = exponentAtCurrentTick.minus(1); + ticksPassed = ticksPassed.minus(geometricExponentIncrementDistanceInTicks); + + console.log(`Loop (desiredPrice <= 1): currentPrice=${currentPrice}, exponentAtCurrentTick=${exponentAtCurrentTick}, ticksPassed=${ticksPassed}`); + } + } + + const ticksToBeFulfilledByExponentAtCurrentTick = desiredPrice.minus(currentPrice).dividedBy(currentAdditiveIncrementInTicks); + console.log(`Ticks to be fulfilled by current exponent: ${ticksToBeFulfilledByExponentAtCurrentTick}`); + + const tickIndex = ticksPassed.plus(ticksToBeFulfilledByExponentAtCurrentTick); + console.log(`Tick index: ${tickIndex}`); + + let returnTick = new BigNumber(0); + if (is_lowerBound){ + returnTick = tickIndex.dividedBy(tickSpacing).integerValue(BigNumber.ROUND_DOWN).multipliedBy(tickSpacing) + } + else{ + returnTick = tickIndex.dividedBy(tickSpacing).integerValue(BigNumber.ROUND_CEIL).multipliedBy(tickSpacing) + } + + console.log(`Final calculations: tickIndex=${tickIndex}, returnTick=${BigInt(returnTick.toNumber()).toString()}`); + return BigInt(returnTick.toNumber()).toString(); +} + export function tickToPrice(exponentToken0: number, exponentToken1: number, currentTickIn: string, exponentAtPriceOne: string): string { const currentTick = new BigNumber(currentTickIn) var exponent = new BigNumber(exponentAtPriceOne); // -6 diff --git a/test-bronze/chains/osmosis/osmosis.test.ts b/test-bronze/chains/osmosis/osmosis.test.ts index d9d5f1d0f0..2795c72782 100755 --- a/test-bronze/chains/osmosis/osmosis.test.ts +++ b/test-bronze/chains/osmosis/osmosis.test.ts @@ -158,7 +158,7 @@ describe('controllers - price + trade', () => { }); it('trade', async () => { - const tradeRequest = {'quote':'ION', 'base':'OSMO', 'amount':'0.01', 'side':'BUY' as Side, 'allowedSlippage':'100/100', 'chain':'osmosis', 'network':network, 'address':osmosisAddress, }; + const tradeRequest = {'quote':'ION', 'base':'OSMO', 'amount':'0.04', 'side':'BUY' as Side, 'allowedSlippage':'100/100', 'chain':'osmosis', 'network':network, 'address':osmosisAddress, }; const tradeResponse = await osmosis.controller.trade(osmosis, tradeRequest) expect(tradeResponse.base).toEqual('uosmo') }); @@ -188,7 +188,7 @@ describe('controllers - CL Pools + Liquidity', () => { var poolIdCL: number; it('addLiquidity CL', async () => { - const addLiquidityRequestFunction = {'allowedSlippage':'100/100', 'lowerPrice':'100', 'upperPrice':'500', 'fee': 'high', 'token0':'ION', 'token1':'OSMO', 'amount0':'0.000401', 'amount1':'0.1', 'chain':'osmosis', 'network':network, 'address':osmosisAddress}; + const addLiquidityRequestFunction = {'allowedSlippage':'100/100', 'lowerPrice':'100', 'upperPrice':'500', 'fee': 'high', 'token0':'ION', 'token1':'OSMO', 'amount0':'0.000401', 'amount1':'0.01', 'chain':'osmosis', 'network':network, 'address':osmosisAddress}; var addLiquidityResponse = await osmosis.controller.addLiquidity(osmosis, addLiquidityRequestFunction) poolIdCL = addLiquidityResponse.tokenId; expect(addLiquidityResponse.tokenId).toBeDefined();