Skip to content

Commit

Permalink
add LiquidityPoolCalculator and testcase
Browse files Browse the repository at this point in the history
  • Loading branch information
fatsheep1919 committed Jul 19, 2023
1 parent e0418db commit 0ddaf73
Show file tree
Hide file tree
Showing 13 changed files with 960 additions and 64 deletions.
575 changes: 575 additions & 0 deletions packages/math/__tests__/__snapshots__/pool-calculator.test.ts.snap

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/math/__tests__/apr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import superfluid from "../../../__fixtures__/rpc/osmosis/superfluid/v1beta1/all
import summary from "../../../__fixtures__/validator/pairs/v1/summary/data.json";
import cases from "jest-in-case";
import Long from "long";
import { omit } from "./pools.test";
import { omit } from "./pool-utils.test";
import { calcPoolAprs } from "../src/apr";
import { convertGeckoPricesToDenomPriceHash } from "../src/utils";

Expand Down Expand Up @@ -87,11 +87,11 @@ describe("Test APR calculations", () => {
)!.volume_7d;

const aprs = calcPoolAprs(
osmosisAssets,
{
activeGauges,
lockupDurations,
pool,
assets: osmosisAssets,
prices,
superfluidPools,
swapFee: pool.poolParams!.swapFee,
Expand Down
243 changes: 243 additions & 0 deletions packages/math/__tests__/pool-calculator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
import { assets } from 'chain-registry';
import { asset_lists } from '@chain-registry/assets';
import priceResponse from "../../../__fixtures__/coingecko/api/v3/simple/price/data.json";
import poolResponse from "../../../__fixtures__/rpc/osmosis/gamm/v1beta1/pools/data.json";
import { LiquidityPoolCalculator } from '../src/pool-calculator';
import {
noDecimals,
getOsmoAssetByDenom,
convertGeckoPricesToDenomPriceHash
} from "../src/utils";
import cases from "jest-in-case";
import { omit } from "./pool-utils.test";

const fakeBalances = [
{
denom: "gamm/pool/1",
amount: "3971711067183317356",
},
{
denom: "gamm/pool/497",
amount: "349025380200104928",
},
{
denom: "gamm/pool/604",
amount: "35696235433901",
},
{
denom: "gamm/pool/795",
amount: "6240168637927540325",
},
{
denom:
"ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2",
amount: "838542",
},
{
denom:
"ibc/2DA9C149E9AD2BD27FEFA635458FB37093C256C1A940392634A16BEA45262604",
amount: "2887086",
},
{
denom:
"ibc/46B44899322F3CD854D2D46DEEF881958467CDD4B3B10086DA49296BBED94BED",
amount: "35409600",
},
{
denom:
"ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4",
amount: "232663227",
},
{
denom: "uosmo",
amount: "5283728",
},
];

describe("Test pool calculations of LiquidityPoolCalculator", () => {
let osmosisAssets, pools, prices;
let calculator: LiquidityPoolCalculator;
beforeAll(() => {
osmosisAssets = assets.find(({ chain_name }) => chain_name === 'osmosis');
const osmosisAssetList = asset_lists.find(({ chain_name }) => chain_name === 'osmosis');
osmosisAssets = [...(osmosisAssets?.assets || []), ...(osmosisAssetList?.assets || [])];
pools = poolResponse.pools.map((p) => omit(p, "@type"));
prices = convertGeckoPricesToDenomPriceHash(osmosisAssets, priceResponse);
calculator = new LiquidityPoolCalculator({ assets: osmosisAssets });
});

cases(
"calcPoolLiquidity",
(opts) => {
const pool = pools.find((pool) => pool.id === opts.poolId);
const liquidity = calculator.calcPoolLiquidity(pool, prices);
expect(noDecimals(liquidity)).toEqual(opts.liquidity);
},
[
{
name: "pool#1",
poolId: "1",
liquidity: "446862602",
},
{
name: "pool#497",
poolId: "497",
liquidity: "65709813",
},
{
name: "pool#604",
poolId: "604",
liquidity: "24905046",
},
]
);

cases(
"convertGammTokenToDollarValue",
(opts) => {
const pool = pools.find((pool) => pool.id === opts.poolId);
const value = calculator.convertGammTokenToDollarValue(opts.coin, pool, prices);
expect(noDecimals(value)).toEqual(opts.value);
},
[
{ poolId: "1", coin: fakeBalances[0], value: "5" },
{ poolId: "497", coin: fakeBalances[1], value: "14" },
{ poolId: "604", coin: fakeBalances[2], value: "6" },
]
);

cases(
"convertDollarValueToCoins",
(opts) => {
const pool = pools.find(
(pool) => pool.poolAssets.length === opts.poolLength
);
const coins = calculator.convertDollarValueToCoins(opts.value, pool, prices);
expect(coins).toMatchSnapshot();
},
[
{
name: "2 token pool",
value: 10,
poolLength: 2,
},
{
name: "3 token pool",
value: 10,
poolLength: 3,
},
{
name: "4 token pool",
value: 10,
poolLength: 4,
},
{
name: "0 dollar",
value: 0,
poolLength: 2,
},
]
);

cases(
"convertDollarValueToShares",
(opts) => {
const pool = pools.find((pool) => pool.id === opts.poolId);
const shares = calculator.convertDollarValueToShares(opts.value, pool, prices);
expect(noDecimals(shares)).toEqual(opts.shares);
},
[
{ name: "10 usd for pool#1", value: 10, poolId: "1", shares: "7" },
{ name: "100 usd for pool#497", value: 100, poolId: "497", shares: "2" },
{ name: "0 usd for pool#1", value: 0, poolId: "1", shares: "0" },
]
);

cases(
"calcCoinsNeededForValue",
(opts) => {
const pool = pools.find((pool) => pool.id === opts.poolId);
const prettiedPool = calculator.prettyPool(pool);
const coinsNeeded = calculator.calcCoinsNeededForValue(
prices,
prettiedPool,
opts.value
);
expect(coinsNeeded).toMatchSnapshot();
},
[
{ name: "10 for pool#1", poolId: "1", value: 10 },
{ name: "10 for pool#497", poolId: "497", value: 10 },
{ name: "10 for pool#604", poolId: "604", value: 10 },
{ name: "0 for pool#1", poolId: "1", value: 0 },
]
);

cases(
"calcMaxCoinsForPool",
(opts) => {
const pool = pools.find((pool) => pool.id === opts.poolId);
const prettiedPool = calculator.prettyPool(pool);
const coinsNeeded = calculator.calcMaxCoinsForPool(
prices,
prettiedPool,
fakeBalances
);
expect(coinsNeeded).toMatchSnapshot();
},
[
{ name: "pool#1", poolId: "1" },
{ name: "pool#604", poolId: "604" },
{ name: "pool#25", poolId: "25" },
]
);

cases(
"calcShareOutAmount",
(opts) => {
const pool = pools.find((pool) => pool.id === opts.poolId);
const prettiedPool = calculator.prettyPool(pool);
const coinsNeeded = opts.useMaxCoins
? calculator.calcMaxCoinsForPool(prices, prettiedPool, fakeBalances)
: calculator.calcCoinsNeededForValue(prices, prettiedPool, opts.value as number);
const shareOutAmount = calculator.calcShareOutAmount(pool, coinsNeeded);
expect(shareOutAmount).toEqual(opts.amount);
},
[
{
name: "pool#1",
poolId: "1",
useMaxCoins: true,
amount: "44690927353631068872",
},
{
name: "pool#604",
poolId: "604",
useMaxCoins: false,
value: 10,
amount: "51864273176244",
},
{
name: "pool#497",
poolId: "497",
useMaxCoins: true,
amount: "2222110943246410615",
},
]
);

test("makePoolPairs", () => {
const poolsFiltered = pools.filter((pool) =>
pool.poolAssets.every(({ token }) => {
try {
return !!getOsmoAssetByDenom(osmosisAssets, token.denom);
} catch (error) {
return false;
}
})
);
const LIQUIDITY_LIMIT = 50000000;
const poolPairs = calculator.makePoolPairs(poolsFiltered, prices, LIQUIDITY_LIMIT);
expect(poolPairs).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
calcShareOutAmount,
prettyPool,
makePoolPairs,
} from "../src/pool";
} from "../src/pool-utils";
import cases from "jest-in-case";
import { noDecimals, convertGeckoPricesToDenomPriceHash } from "../src/utils";

Expand Down
4 changes: 2 additions & 2 deletions packages/math/__tests__/swap.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import cases from "jest-in-case";
import { assets } from 'chain-registry';
import { asset_lists } from '@chain-registry/assets';
import { makePoolPairs } from "../src/pool";
import { makePoolPairs } from "../src/pool-utils";
import {
convertGeckoPricesToDenomPriceHash,
getOsmoAssetByDenom,
Expand All @@ -16,7 +16,7 @@ import {
} from "./../src/swap";
import priceResponse from "../../../__fixtures__/coingecko/api/v3/simple/price/data.json";
import poolResponse from "../../../__fixtures__/rpc/osmosis/gamm/v1beta1/pools/data.json";
import { omit } from "./pools.test";
import { omit } from "./pool-utils.test";
import BigNumber from "bignumber.js";

const osmosisAssets = [
Expand Down
13 changes: 6 additions & 7 deletions packages/math/src/apr.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Asset as OsmosisAsset } from "@chain-registry/types";
import { CalcPoolAprsParams } from "./types";
import { Duration } from "osmojs/dist/codegen/google/protobuf/duration";
import { calcPoolLiquidity } from "./pool";
import { calcPoolLiquidity } from "./pool-utils";
import BigNumber from "bignumber.js";
import {
dollarValueToDenomUnits,
Expand All @@ -26,10 +25,10 @@ const convertLockup = (lockup: string, durations: Duration[]) => {
};

export const calcPoolAprs = (
osmosisAssets: OsmosisAsset[],
{
activeGauges,
pool,
assets,
prices,
superfluidPools,
aprSuperfluid,
Expand Down Expand Up @@ -59,7 +58,7 @@ export const calcPoolAprs = (
const superfluidApr =
isSuperfluidPool && lockup === "14" ? aprSuperfluid : null;

const liquidity = calcPoolLiquidity(osmosisAssets, pool, prices);
const liquidity = calcPoolLiquidity(assets, pool, prices);

// gauge aprs
const lockupDuration = convertLockup(lockup, lockupDurations);
Expand All @@ -79,21 +78,21 @@ export const calcPoolAprs = (
const tokensRemaining = new BigNumber(gauge.coins[0].amount).minus(
gauge.distributedCoins[0].amount
);
const symbol = osmoDenomToSymbol(osmosisAssets, gauge.coins[0].denom);
const symbol = osmoDenomToSymbol(assets, gauge.coins[0].denom);
const daysRemaining = gauge.isPerpetual
? null
: gauge.numEpochsPaidOver.low - gauge.filledEpochs.low;

const totalValue = tokensRemaining
.shiftedBy(-getExponentByDenom(osmosisAssets, gauge.coins[0].denom))
.shiftedBy(-getExponentByDenom(assets, gauge.coins[0].denom))
.multipliedBy(prices[gauge.coins[0].denom]);

const distributedValuePerDay = totalValue
.dividedBy(gauge.isPerpetual ? 1 : daysRemaining)
.toString();

const distributedCoinPerDay = {
amount: dollarValueToDenomUnits(osmosisAssets, prices, symbol, distributedValuePerDay),
amount: dollarValueToDenomUnits(assets, prices, symbol, distributedValuePerDay),
denom: gauge.coins[0].denom,
};

Expand Down
3 changes: 2 additions & 1 deletion packages/math/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./apr";
export * from "./pool";
export * from "./pool-utils";
export * from "./pool-calculator";
export * from "./swap";
export * from "./utils";
Loading

0 comments on commit 0ddaf73

Please sign in to comment.