Skip to content

Commit

Permalink
Merge pull request #961 from Levana-Protocol/master
Browse files Browse the repository at this point in the history
fix levana volumes
  • Loading branch information
dtmkeng authored Nov 7, 2023
2 parents a011fc1 + e9be03d commit d498f09
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 74 deletions.
42 changes: 10 additions & 32 deletions dexs/levana/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
import BigNumber from "bignumber.js";
import fetchURL from "../../utils/fetchURL";
import { ChainId, DateString, MarketAddr, TradeVolumeResp } from "./types";
const INDEXER_URL = 'https://indexer.levana.finance';

export async function fetchVolume(marketAddrs: MarketAddr[], kind: "daily" | "cumulative", startDate: DateString, endDate: DateString) {
const api = kind === "daily" ? "trade-volume" : "cumulative-trade-volume";

const url = `${INDEXER_URL}/${api}?scope=daily&start_date=${startDate}&end_date=${endDate}`;
const resp: TradeVolumeResp = (await fetchURL(url)).data;

if (!resp || !resp[startDate]) {
return 0;
}
import { MarketInfo} from "./types";

const totalVolume = Object.entries(resp[startDate]).reduce((totalVolume, [marketAddr, volumePerMarket]) => {
return (marketAddrs.includes(marketAddr))
? totalVolume.plus(BigNumber(volumePerMarket))
: totalVolume;

}, BigNumber(0))

return totalVolume.toString();
}
const INDEXER_URL = 'https://indexer.levana.finance';

export async function fetchMarketAddrs(chainId: string) {
interface Market {
chain: string;
contract: string;
}
export async function fetchVolume(kind: "daily" | "total", marketInfos: MarketInfo[], timestampSeconds: number) {
const marketsStr = marketInfos.map(({addr}) => `market=${addr}`).join("&");
const timestamp = new Date(timestampSeconds * 1000).toISOString();
// it's either 1 day back or "all the days" back
const intervalDays = kind === "daily" ? 1 : Math.floor(timestampSeconds / (24 * 60 * 60));

const url = `${INDEXER_URL}/markets`;
const markets: [Market] = (await fetchURL(url))?.data;
const url = `${INDEXER_URL}/rolling_trade_volume?${marketsStr}&timestamp=${timestamp}&interval_days=${intervalDays}`

return markets
.filter(market => chainId === market.chain)
.map(market => market.contract);
}
return new BigNumber((await fetchURL(url)).data);
}
55 changes: 22 additions & 33 deletions dexs/levana/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import {Adapter, BaseAdapter, FetchResultVolume, SimpleAdapter} from "../../adapters/types";
import {getTimestampAtStartOfDayUTC, getTimestampAtStartOfPreviousDayUTC} from "../../utils/date";
import { fetchMarketAddrs, fetchVolume } from "./fetch";
import { ChainId } from "./types";
import { dateStr } from "./utils";
import {FetchResultVolume, SimpleAdapter} from "../../adapters/types";
import { fetchVolume } from "./fetch";
import { queryMarketInfos } from "./query";

const adapter: SimpleAdapter = {
// each of these is the time of factory instantiation
// start times are factory instantiation
adapter: {
osmosis: {
fetch: async (timestamp: number): Promise<FetchResultVolume> => {
const marketAddrs = await fetchMarketAddrs("osmosis-1");
const [totalVolume, dailyVolume] = await Promise.all([
getTotalVolume(marketAddrs, timestamp),
getDailyVolume(marketAddrs, timestamp)
const marketInfos = await queryMarketInfos({chain: "osmosis"});

const [dailyVolume, totalVolume] = await Promise.all([
fetchVolume("daily", marketInfos, timestamp),
fetchVolume("total", marketInfos, timestamp)
]);

return {
timestamp,
dailyVolume: dailyVolume.toString(),
Expand All @@ -24,11 +24,13 @@ const adapter: SimpleAdapter = {
},
sei: {
fetch: async (timestamp: number): Promise<FetchResultVolume> => {
const marketAddrs = await fetchMarketAddrs("pacific-1");
const [totalVolume, dailyVolume] = await Promise.all([
getTotalVolume(marketAddrs, timestamp),
getDailyVolume(marketAddrs, timestamp)
const marketInfos = await queryMarketInfos({chain: "sei"});

const [dailyVolume, totalVolume] = await Promise.all([
fetchVolume("daily", marketInfos, timestamp),
fetchVolume("total", marketInfos, timestamp)
]);

return {
timestamp,
dailyVolume: dailyVolume.toString(),
Expand All @@ -39,11 +41,13 @@ const adapter: SimpleAdapter = {
},
injective: {
fetch: async (timestamp: number): Promise<FetchResultVolume> => {
const marketAddrs = await fetchMarketAddrs("injective-1");
const [totalVolume, dailyVolume] = await Promise.all([
getTotalVolume(marketAddrs, timestamp),
getDailyVolume(marketAddrs, timestamp)
const marketInfos = await queryMarketInfos({chain: "injective"});

const [dailyVolume, totalVolume] = await Promise.all([
fetchVolume("daily", marketInfos, timestamp),
fetchVolume("total", marketInfos, timestamp)
]);

return {
timestamp,
dailyVolume: dailyVolume.toString(),
Expand All @@ -55,19 +59,4 @@ const adapter: SimpleAdapter = {
}
}


async function getTotalVolume(marketAddrs: string[], timestamp: number) {
const startDate = dateStr(getTimestampAtStartOfPreviousDayUTC(timestamp))
const endDate = dateStr(getTimestampAtStartOfDayUTC(timestamp));

return fetchVolume(marketAddrs, "cumulative", startDate, endDate);
}

async function getDailyVolume(marketAddrs: string[], timestamp: number) {
const startDate = dateStr(getTimestampAtStartOfPreviousDayUTC(timestamp))
const endDate = dateStr(getTimestampAtStartOfDayUTC(timestamp));
return fetchVolume(marketAddrs, "daily", startDate, endDate);
}


export default adapter;
64 changes: 64 additions & 0 deletions dexs/levana/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { MarketInfo} from "./types";
import fetchURL from "../../utils/fetchURL";
import { Chain, queryContract } from "./utils";

const factories:Record<Chain, string> = {
osmosis: "osmo1ssw6x553kzqher0earlkwlxasfm2stnl3ms3ma2zz4tnajxyyaaqlucd45",
sei: "sei18rdj3asllguwr6lnyu2sw8p8nut0shuj3sme27ndvvw4gakjnjqqper95h",
injective: "inj1vdu3s39dl8t5l88tyqwuhzklsx9587adv8cnn9"
}

export async function queryMarketInfos({chain}:{chain: Chain}):Promise<MarketInfo[]> {
interface MarketsResp {
markets: string[]
}
interface MarketInfoResp {
market_addr: string,
position_token: string,
liquidity_token_lp: string,
liquidity_token_xlp: string,
}
const factoryAddr = factories[chain]

const marketIds = []
while(true) {
const resp:MarketsResp = await queryContract({
chain,
contract: factoryAddr,
msg: {
markets: {
start_after: marketIds.length ? marketIds[marketIds.length-1] : undefined
}
}
})

if(!resp || !resp.markets) {
throw new Error(`failed to get market addresses on chain ${chain}`);
}

if(!resp.markets.length) {
break;
}

marketIds.push(...resp.markets);
}

const queryMarketInfo = (marketId:string) => queryContract({
chain,
contract: factoryAddr,
msg: {
market_info: {
market_id: marketId
}
}
}).then((resp:MarketInfoResp) => ({
id: marketId,
addr: resp.market_addr,
positionTokenAddr: resp.position_token,
liquidityTokenLpAddr: resp.liquidity_token_lp,
liquidityTokenXlpAddr: resp.liquidity_token_xlp,
}))

return await Promise.all(marketIds.map(queryMarketInfo))

}
13 changes: 7 additions & 6 deletions dexs/levana/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type TradeVolumeResp = Record<DateString, Record<MarketAddr, VolumeString>>;

export type ChainId = string;
export type MarketAddr = string;
export type VolumeString = string;
export type DateString = string;
export interface MarketInfo {
id: string,
addr: string,
positionTokenAddr: string,
liquidityTokenLpAddr: string,
liquidityTokenXlpAddr: string,
}
23 changes: 20 additions & 3 deletions dexs/levana/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
export function dateStr(timestamp: number): string {
const date = new Date(timestamp * 1000)
return `${date.getUTCFullYear()}-${date.getUTCMonth() + 1}-${date.getUTCDate()}`
import fetchURL from "../../utils/fetchURL";

// These utils were adapted from the DefiLlama-Adapters repo
export type Chain = "osmosis" | "injective" | "sei"

const endpoints:Record<Chain,string> = {
osmosis: "https://osmosis-api.polkachu.com",
injective: "https://lcd-injective.whispernode.com:443",
sei: "https://sei-api.polkachu.com",
};

export async function queryContract<T>({contract, chain, msg}:{contract: string, chain: Chain, msg: T}) {
const data = Buffer.from(JSON.stringify(msg)).toString("base64");

const endpoint = endpoints[chain]
return (
await fetchURL(
`${endpoint}/cosmwasm/wasm/v1/contract/${contract}/smart/${data}`
)
).data.data;
}

0 comments on commit d498f09

Please sign in to comment.