Skip to content

Commit

Permalink
Osmosis: Removed GAAM from poolPositions, fixed interactions with amm…
Browse files Browse the repository at this point in the history
….lp strat
  • Loading branch information
chasevoorhees committed Mar 12, 2024
1 parent aa7998e commit 3db1553
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 64 deletions.
4 changes: 2 additions & 2 deletions src/chains/cosmos/cosmos-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,12 @@ export class CosmosBase {
public getAllowedSlippage(allowedSlippageStr?: string): number {
if (allowedSlippageStr != null && isFractionString(allowedSlippageStr)) {
const fractionSplit = allowedSlippageStr.split('/');
return Number(fractionSplit[0]) / Number(fractionSplit[1]);
return 100 * (Number(fractionSplit[0]) / Number(fractionSplit[1]));
}

const allowedSlippage = RefConfig.config.allowedSlippage;
const nd = allowedSlippage.match(percentRegexp);
if (nd) return Number(nd[1]) / Number(nd[2]);
if (nd) return 100 * (Number(nd[1]) / Number(nd[2]));
throw new Error(
'Encountered a malformed percent string in the config for ALLOWED_SLIPPAGE.'
);
Expand Down
9 changes: 6 additions & 3 deletions src/chains/osmosis/osmosis.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ export class OsmosisController {
latency: latency(startTimestamp, Date.now()),
token0: req.token0,
token1: req.token1,
prices: [priceAndPools.price],
prices: priceAndPools.prices,
pools: priceAndPools.pools, //CosmosExtendedPool[];
};
}
Expand Down Expand Up @@ -697,7 +697,10 @@ export class OsmosisController {
}
})
}
var tokenId = position_id ? position_id!=undefined : pool_id;
var tokenId = position_id;
if (position_id == undefined){
tokenId = pool_id;
}

var txStatus = unconfirmedTransaction;
//@ts-ignore cosmojs models again
Expand All @@ -712,7 +715,7 @@ export class OsmosisController {
return {
txStatus: txStatus,
txReceipt: null,
tokenId: Number(tokenId ? tokenId != undefined : -1),
tokenId: Number(tokenId),
txHash: req.txHash,
currentBlock,
//@ts-ignore cosmojs models again
Expand Down
84 changes: 55 additions & 29 deletions src/chains/osmosis/osmosis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } from './osmosis.utils';
import { fetchFees, findTickForPrice, tickToPrice } from './osmosis.utils';
import { getImperatorPriceHash } from './osmosis.prices';
import { GasPrice, calculateFee, setupIbcExtension, SigningStargateClient, AminoTypes } from '@cosmjs/stargate';
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";
Expand Down Expand Up @@ -1148,12 +1148,13 @@ export class Osmosis extends CosmosBase implements Cosmosish{
var amount0 = req.amount0;
var amount1 = req.amount1;

var slippage = 0;
if (req.allowedSlippage){
slippage = this.getAllowedSlippage(req.allowedSlippage)
}else{
slippage = this.getAllowedSlippage(this.allowedSlippage)
}
// set slippage for this to 100 because the pools are too unbalanced
var slippage = 100;
// if (req.allowedSlippage){
// slippage = this.getAllowedSlippage(req.allowedSlippage)
// }else{
// slippage = this.getAllowedSlippage(this.allowedSlippage)
// }
var feeTier = this.feeTier;
if (feeTier_input){
feeTier = feeTier_input;
Expand Down Expand Up @@ -1347,19 +1348,20 @@ export class Osmosis extends CosmosBase implements Cosmosish{
.shiftedBy(this.getExponentByBase(token1.base))
.toString()});

// var token0_bignumber = new BigNumber(amount0)
// var token1_bignumber = new BigNumber(amount1)
var token0_bignumber = new BigNumber(amount0)
var token1_bignumber = new BigNumber(amount1)

var tokenMinAmount0;
var tokenMinAmount1;
// if (slippage == 100){
tokenMinAmount0 = '0';
tokenMinAmount1 = '0';
// }else{
// tokenMinAmount0 = token0_bignumber.shiftedBy(this.getExponentByBase(token0.base)).multipliedBy(100-slippage).dividedBy(100).integerValue(BigNumber.ROUND_CEIL)
// tokenMinAmount1 = token1_bignumber.shiftedBy(this.getExponentByBase(token1.base)).multipliedBy(100-slippage).dividedBy(100).integerValue(BigNumber.ROUND_CEIL)
// }
const lowerTick = findTickForPrice(req.lowerPrice!, pool.exponentAtPriceOne, pool.tickSpacing, true)
if (slippage == 100){
tokenMinAmount0 = '0';
tokenMinAmount1 = '0';
}else{
tokenMinAmount0 = token0_bignumber.shiftedBy(this.getExponentByBase(token0.base)).multipliedBy(100-slippage).dividedBy(100).integerValue(BigNumber.ROUND_CEIL)
tokenMinAmount1 = token1_bignumber.shiftedBy(this.getExponentByBase(token1.base)).multipliedBy(100-slippage).dividedBy(100).integerValue(BigNumber.ROUND_CEIL)
}

const lowerTick = findTickForPrice(req.lowerPrice!, pool.exponentAtPriceOne, pool.tickSpacing, true) // pool.currentTick,
const upperTick = findTickForPrice(req.upperPrice!, pool.exponentAtPriceOne, pool.tickSpacing, false)

var tokenMinAmount0_final = tokenMinAmount0.toString()
Expand Down Expand Up @@ -1528,7 +1530,7 @@ export class Osmosis extends CosmosBase implements Cosmosish{
TRADE_FAILED_ERROR_MESSAGE,
TRADE_FAILED_ERROR_CODE
);
}
}

/**
* exchange pool liquidity shares for amounts of tokens from a pool
Expand Down Expand Up @@ -1996,7 +1998,7 @@ export class Osmosis extends CosmosBase implements Cosmosish{
this.signingClient.disconnect();

var finalBalancesReceived: CoinAndSymbol[] = [];
var collect_strings: string[] = ['180000uosmo,293400000000000000ibc/0CD3A0285E1341859B5E86B6AB7682F023D03E97607CCC1DC95706411D866DF7'];
var collect_strings: string[] = [];
//@ts-ignore
res.events.filter((evt)=>evt.type='total_collect_spread_rewards').forEach((evt)=>{evt.attributes.forEach((atr)=>{
if (atr.key=='tokens_out'){
Expand Down Expand Up @@ -2163,12 +2165,15 @@ export class Osmosis extends CosmosBase implements Cosmosish{
const prices = await getImperatorPriceHash(callImperatorWithTokens);

// filter for CL
const filteredPools = filterPoolsSwapAndLP(this.tokenList, pools, prices); // removes stableswap, !token.denom.startsWith('gamm/pool'), has price, has osmosisAsset

const filteredPools = filterPoolsLP(this.tokenList, pools, prices);
const extendedPools = filteredPools.map((pool) =>
extendPool(this.tokenList, { pool, fees, balances, lockedCoins, prices:prices })
);
const exponentToken0 = this.getExponentByBase(token0.base)
const exponentToken1 = this.getExponentByBase(token1.base)

var pricesOut: string[] = [];
var returnPools: SerializableExtendedPool[] = [];
extendedPools.forEach(function (cPool) {
var foundToken0 = false;
Expand Down Expand Up @@ -2197,11 +2202,12 @@ export class Osmosis extends CosmosBase implements Cosmosish{

if (foundToken0 && foundToken1){
returnPools.push(new SerializableExtendedPool(cPool));
// @ts-ignore
pricesOut.push(tickToPrice(exponentToken0, exponentToken1, cPool.currentTick.toString(), cPool.exponentAtPriceOne.toString()))
}
});

var price_out = new BigNumber(prices[token0.base]).dividedBy(new BigNumber(prices[token1.base])).toString()
var returnPriceAndPools = {'pools':returnPools, 'price':price_out}
var returnPriceAndPools = {'pools':returnPools, 'prices':pricesOut}

return returnPriceAndPools;

Expand Down Expand Up @@ -2232,7 +2238,7 @@ export class Osmosis extends CosmosBase implements Cosmosish{
): Promise<PositionInfo> {

// find out if this is CL or GAMM (positionId or poolId)
var final_poolId = undefined
var final_poolId = tokenId
if (tokenId){
try{
const allCLPositionsContainer = await this._provider.osmosis.concentratedliquidity.v1beta1.positionById({
Expand Down Expand Up @@ -2312,8 +2318,8 @@ export class Osmosis extends CosmosBase implements Cosmosish{
{
returnPools.push(new SerializableExtendedPool(cPool));
}
else if (tokenId){
if ((cPool.id && cPool.id.toString() == tokenId.toString()) || (cPool.poolId && cPool.poolId.toString() == tokenId.toString())){
else if (final_poolId){
if ((cPool.id && cPool.id.toString() == final_poolId.toString()) || (cPool.poolId && cPool.poolId.toString() == final_poolId.toString())){
returnPools.push(new SerializableExtendedPool(cPool));
}
}
Expand All @@ -2325,6 +2331,26 @@ export class Osmosis extends CosmosBase implements Cosmosish{
// so (if we can) let's pretend we match the existing model and just return the first position for that poolId
if (clPositions && clPositions.length > 0){
const clPosition = clPositions[0];
var unclaimedToken0 = new BigNumber(0)
var unclaimedToken1 = new BigNumber(0)
clPosition.claimableIncentives.forEach((element: { amount: number; denom: string;}) => {
if (new BigNumber(element.amount).isGreaterThan(0)){
if (element.denom == clPosition.asset0.denom){
unclaimedToken0 = unclaimedToken0.plus(new BigNumber(element.amount))
}else{
unclaimedToken1 = unclaimedToken1.plus(new BigNumber(element.amount))
}
}
});
clPosition.claimableSpreadRewards.forEach((element: { amount: number; denom: string;}) => {
if (new BigNumber(element.amount).isGreaterThan(0)){
if (element.denom == clPosition.asset0.denom){
unclaimedToken0 = unclaimedToken0.plus(new BigNumber(element.amount))
}else{
unclaimedToken1 = unclaimedToken1.plus(new BigNumber(element.amount))
}
}
});

returnObj.token0 = clPosition.asset0.denom;
returnObj.token1 = clPosition.asset1.denom;
Expand All @@ -2333,12 +2359,12 @@ export class Osmosis extends CosmosBase implements Cosmosish{
returnObj.lowerPrice = clPosition.position.lowerTick.toString();
returnObj.upperPrice = clPosition.position.upperTick.toString();
returnObj.poolShares = clPosition.position.liquidity
returnObj.unclaimedToken0 = '0'
returnObj.unclaimedToken1 = '0'
returnObj.unclaimedToken0 = unclaimedToken0.toString()
returnObj.unclaimedToken1 = unclaimedToken1.toString()
const clPositionPool = extendedPools.find((pl) => pl.id.toString() === clPosition.position.poolId.toString());
returnObj.fee = clPositionPool?.fees7D.toString()
}
// not returning GAMM positons here; problematic for strat
// not returning GAMM positons here; problematic for strat and apparently this is amm-liquidity route only
// else if (tokenId && returnPools.length > 0){ // we got a poolId but it was for a GAMM pool - so yes poolShares
// var firstPool: SerializableExtendedPool = returnPools[0]!;
// returnObj.token0 = firstPool.poolAssets![0].token.denom;
Expand Down
2 changes: 1 addition & 1 deletion src/chains/osmosis/osmosis.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ export interface TransactionEventAttribute {

export interface PriceAndSerializableExtendedPools{
pools: SerializableExtendedPool[];
price: string;
prices: string[];
}

export class SerializableExtendedPool {
Expand Down
23 changes: 21 additions & 2 deletions src/chains/osmosis/osmosis.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ export const fetchRewards = async (address: string): Promise<Rewards> => {
.then((res) => res.json());
};

export function tickToPrice(exponentToken0: number, exponentToken1: number, currentTickIn: string, exponentAtPriceOne: string): string {
const currentTick = new BigNumber(currentTickIn)
var exponent = new BigNumber(exponentAtPriceOne); // -6

var geoExponentIncrementTicks = new BigNumber(9).multipliedBy(new BigNumber(10).exponentiatedBy(exponent.multipliedBy(-1))) // 9e6
var geoExponentDelta;
geoExponentDelta = currentTick.dividedBy(geoExponentIncrementTicks).integerValue(BigNumber.ROUND_FLOOR)

var exponentAtCurrentTick = new BigNumber(exponentAtPriceOne).plus(geoExponentDelta)
var currentAddIncrementTicks = new BigNumber(10).exponentiatedBy(exponentAtCurrentTick) // 10e-6

var numAdditiveTicks = currentTick.minus((geoExponentDelta.multipliedBy(geoExponentIncrementTicks)))

var price = new BigNumber(10).exponentiatedBy(geoExponentDelta).plus((numAdditiveTicks.multipliedBy(currentAddIncrementTicks)))

price = price.dividedBy((new BigNumber(10).exponentiatedBy(exponentToken1)).dividedBy((new BigNumber(10).exponentiatedBy(exponentToken0))))

return price.toString()
}

export function findTickForPrice(desiredPriceString: string, exponentAtPriceOne: number, tickSpacing: number, is_lowerBound: boolean): string{
var desiredPrice = new BigNumber(desiredPriceString)
var exponent = new BigNumber(exponentAtPriceOne); // -6
Expand All @@ -62,15 +82,14 @@ export function findTickForPrice(desiredPriceString: string, exponentAtPriceOne:

var ticksToBeFulfilledByExponentAtCurrentTick = (desiredPrice.minus(totalPrice)).dividedBy(currentAddIncrementTicks)
var tickIndex = ticksPassed.plus(ticksToBeFulfilledByExponentAtCurrentTick)

var returnTick
if (is_lowerBound){
returnTick = tickIndex.dividedBy(tickSpacing).integerValue(BigNumber.ROUND_DOWN).multipliedBy(tickSpacing)
}
else{
returnTick = tickIndex.dividedBy(tickSpacing).integerValue(BigNumber.ROUND_CEIL).multipliedBy(tickSpacing)
}

return returnTick.toString()
}

33 changes: 6 additions & 27 deletions test-bronze/chains/osmosis/osmosis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,19 +152,19 @@ describe('controllers - price + trade', () => {

it('price', async () => {
// slippage must be high on testnet due to price mismatch with pool ratios
const priceRequest1 = {'quote':'ION', 'base':'OSMO', 'amount':'1', 'side':'BUY' as Side, 'allowedSlippage':'100%', 'chain':'osmosis', 'network':network};
const priceRequest1 = {'quote':'ION', 'base':'OSMO', 'amount':'1', 'side':'BUY' as Side, 'allowedSlippage':'100/100', 'chain':'osmosis', 'network':network};
const priceResponse1 = await osmosis.controller.price(osmosis, priceRequest1)
expect(priceResponse1.base).toEqual('OSMO')
});

it('trade', async () => {
const tradeRequest = {'quote':'ION', 'base':'OSMO', 'amount':'0.01', 'side':'BUY' as Side, 'allowedSlippage':'100%', 'chain':'osmosis', 'network':network, 'address':osmosisAddress, };
const tradeRequest = {'quote':'ION', 'base':'OSMO', 'amount':'0.01', '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')
});

it('trade back', async () => {
const tradeRequest = {'quote':'OSMO', 'base':'ION', 'amount':'0.00001', 'side':'BUY' as Side, 'allowedSlippage':'100%', 'chain':'osmosis', 'network':network, 'address':osmosisAddress, };
const tradeRequest = {'quote':'OSMO', 'base':'ION', 'amount':'0.00001', '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('uion')
});
Expand All @@ -188,33 +188,12 @@ describe('controllers - CL Pools + Liquidity', () => {

var poolIdCL: number;
it('addLiquidity CL', async () => {
const addLiquidityRequestFunction = {'allowedSlippage':'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.1', 'chain':'osmosis', 'network':network, 'address':osmosisAddress};
var addLiquidityResponse = await osmosis.controller.addLiquidity(osmosis, addLiquidityRequestFunction)
poolIdCL = addLiquidityResponse.tokenId;
expect(addLiquidityResponse.tokenId).toBeDefined();
});

it('positionsRequest ALL in Cosmos pool format', async () => {
const positionsRequest1 = {
chain:'osmosis',
network:network,
address: osmosisAddress,
}
var positionsResponse1 = await osmosis.controller.poolPositions(osmosis, positionsRequest1)
expect(positionsResponse1.pools!.length).toBeGreaterThan(0)
});

it('positionsRequest GAMM', async () => {
const positionsRequest1 = {
chain:'osmosis',
network:network,
address: osmosisAddress,
tokenId: poolIdGAMM // GAMM
}
var positionsResponse1 = await osmosis.controller.poolPositions(osmosis, positionsRequest1)
expect(positionsResponse1.pools!.length).toBeGreaterThan(0)
});

it('positionsRequest CL', async () => {
const positionsRequest1 = {
chain:'osmosis',
Expand All @@ -227,13 +206,13 @@ describe('controllers - CL Pools + Liquidity', () => {
});

it('removeLiquidity GAMM', async () => {
const removeLiquidityRequest = {'decreasePercent':100, 'tokenId':poolIdGAMM, 'chain':'osmosis', 'network':network, 'address':osmosisAddress, 'allowedSlippage':'100%'};
const removeLiquidityRequest = {'decreasePercent':100, 'tokenId':poolIdGAMM, 'chain':'osmosis', 'network':network, 'address':osmosisAddress, 'allowedSlippage':'100/100'};
var removeLiquidityResponse = await osmosis.controller.removeLiquidity(osmosis, removeLiquidityRequest)
expect(removeLiquidityResponse.txHash).toBeDefined();
});

it('removeLiquidity CL', async () => {
const removeLiquidityRequest = {'decreasePercent':100, 'tokenId':poolIdCL, 'chain':'osmosis', 'network':network, 'address':osmosisAddress, 'allowedSlippage':'100%'};
const removeLiquidityRequest = {'decreasePercent':100, 'tokenId':poolIdCL, 'chain':'osmosis', 'network':network, 'address':osmosisAddress, 'allowedSlippage':'100/100'};
var removeLiquidityResponse = await osmosis.controller.removeLiquidity(osmosis, removeLiquidityRequest)
expect(removeLiquidityResponse.txHash).toBeDefined();
});
Expand Down

0 comments on commit 3db1553

Please sign in to comment.